The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/swtch.s

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1990 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * William Jolitz.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  * $FreeBSD: releng/5.0/sys/i386/i386/swtch.s 100432 2002-07-21 05:22:16Z peter $
   37  */
   38 
   39 #include "opt_npx.h"
   40 
   41 #include <machine/asmacros.h>
   42 
   43 #ifdef SMP
   44 #include <machine/apic.h>
   45 #include <machine/smptests.h>                   /* CHEAP_TPR, GRAB_LOPRIO */
   46 #endif
   47 
   48 #include "assym.s"
   49 
   50 /*****************************************************************************/
   51 /* Scheduling                                                                */
   52 /*****************************************************************************/
   53 
   54         .data
   55 
   56         .globl  panic
   57 
   58 #ifdef SWTCH_OPTIM_STATS
   59         .globl  swtch_optim_stats, tlb_flush_count
   60 swtch_optim_stats:      .long   0               /* number of _swtch_optims */
   61 tlb_flush_count:        .long   0
   62 #endif
   63 
   64         .text
   65 
   66 /*
   67  * cpu_throw()
   68  *
   69  * This is the second half of cpu_swtch(). It is used when the current
   70  * thread is either a dummy or slated to die, and we no longer care
   71  * about its state.
   72  */
   73 ENTRY(cpu_throw)
   74         jmp     sw1
   75 
   76 /*
   77  * cpu_switch()
   78  *
   79  * Save the current thread state, then select the next thread to run
   80  * and load its state.
   81  */
   82 ENTRY(cpu_switch)
   83 
   84         /* Switch to new thread.  First, save context as needed. */
   85         movl    PCPU(CURTHREAD),%ecx
   86 
   87         /* If no thread to save, don't save it (XXX shouldn't happen). */
   88         testl   %ecx,%ecx
   89         jz      sw1
   90 
   91         movl    TD_PROC(%ecx), %eax
   92         movl    P_VMSPACE(%eax), %edx
   93         movl    PCPU(CPUID), %eax
   94         btrl    %eax, VM_PMAP+PM_ACTIVE(%edx)
   95 
   96         movl    TD_PCB(%ecx),%edx
   97 
   98         movl    (%esp),%eax                     /* Hardware registers */
   99         movl    %eax,PCB_EIP(%edx)
  100         movl    %ebx,PCB_EBX(%edx)
  101         movl    %esp,PCB_ESP(%edx)
  102         movl    %ebp,PCB_EBP(%edx)
  103         movl    %esi,PCB_ESI(%edx)
  104         movl    %edi,PCB_EDI(%edx)
  105         movl    %gs,PCB_GS(%edx)
  106         pushfl                                  /* PSL */
  107         popl    PCB_PSL(%edx)
  108 
  109         /* Test if debug registers should be saved. */
  110         testl   $PCB_DBREGS,PCB_FLAGS(%edx)
  111         jz      1f                              /* no, skip over */
  112         movl    %dr7,%eax                       /* yes, do the save */
  113         movl    %eax,PCB_DR7(%edx)
  114         andl    $0x0000fc00, %eax               /* disable all watchpoints */
  115         movl    %eax,%dr7
  116         movl    %dr6,%eax
  117         movl    %eax,PCB_DR6(%edx)
  118         movl    %dr3,%eax
  119         movl    %eax,PCB_DR3(%edx)
  120         movl    %dr2,%eax
  121         movl    %eax,PCB_DR2(%edx)
  122         movl    %dr1,%eax
  123         movl    %eax,PCB_DR1(%edx)
  124         movl    %dr0,%eax
  125         movl    %eax,PCB_DR0(%edx)
  126 1:
  127 
  128 #ifdef SMP
  129         /* XXX FIXME: we should be saving the local APIC TPR */
  130 #endif
  131 
  132 #ifdef DEV_NPX
  133         /* have we used fp, and need a save? */
  134         cmpl    %ecx,PCPU(FPCURTHREAD)
  135         jne     1f
  136         addl    $PCB_SAVEFPU,%edx               /* h/w bugs make saving complicated */
  137         pushl   %edx
  138         call    npxsave                         /* do it in a big C function */
  139         popl    %eax
  140 1:
  141 #endif
  142 
  143         /* Save is done.  Now choose a new thread. */
  144         /* XXX still trashing space above the old "Top Of Stack". */
  145 sw1:
  146 
  147 #ifdef SMP
  148         /*
  149          * Stop scheduling if smp_active has become zero (for rebooting) and
  150          * we are not the BSP.
  151          */
  152         cmpl    $0,smp_active
  153         jne     1f
  154         cmpl    $0,PCPU(CPUID)
  155         je      1f
  156         movl    PCPU(IDLETHREAD), %eax
  157         jmp     sw1b
  158 1:
  159 #endif
  160 
  161         /*
  162          * Choose a new thread to schedule.  choosethread() returns idlethread
  163          * if it cannot find another thread to run.
  164          */
  165         call    choosethread                    /* Trash ecx, edx; ret eax. */
  166 
  167 #ifdef INVARIANTS
  168         testl   %eax,%eax                       /* no thread? */
  169         jz      badsw3                          /* no, panic */
  170 #endif
  171 
  172 sw1b:
  173         movl    %eax,%ecx
  174         movl    TD_PCB(%ecx),%edx
  175 
  176 #ifdef SWTCH_OPTIM_STATS
  177         incl    swtch_optim_stats
  178 #endif
  179 
  180         /* switch address space */
  181         movl    %cr3,%ebx                       /* The same address space? */
  182         cmpl    PCB_CR3(%edx),%ebx
  183         je      4f                              /* Yes, skip all that cruft */
  184 #ifdef SWTCH_OPTIM_STATS
  185         decl    swtch_optim_stats
  186         incl    tlb_flush_count
  187 #endif
  188         movl    PCB_CR3(%edx),%ebx              /* Tell the CPU about the */
  189         movl    %ebx,%cr3                       /* new address space */
  190 4:
  191 
  192         movl    PCPU(CPUID), %esi
  193         cmpl    $0, PCB_EXT(%edx)               /* has pcb extension? */
  194         je      1f                              /* If not, use the default */
  195         btsl    %esi, private_tss               /* mark use of private tss */
  196         movl    PCB_EXT(%edx), %edi             /* new tss descriptor */
  197         jmp     2f                              /* Load it up */
  198 
  199 1:      /*
  200          * Use the common default TSS instead of our own.
  201          * Set our stack pointer into the TSS, it's set to just
  202          * below the PCB.  In C, common_tss.tss_esp0 = &pcb - 16;
  203          */
  204         leal    -16(%edx), %ebx                 /* leave space for vm86 */
  205         movl    %ebx, PCPU(COMMON_TSS) + TSS_ESP0
  206 
  207         /*
  208          * Test this CPU's  bit in the bitmap to see if this
  209          * CPU was using a private TSS.
  210          */
  211         btrl    %esi, private_tss               /* Already using the common? */
  212         jae     3f                              /* if so, skip reloading */
  213         PCPU_ADDR(COMMON_TSSD, %edi)
  214 2:
  215         /* Move correct tss descriptor into GDT slot, then reload tr. */
  216         movl    PCPU(TSS_GDT), %ebx             /* entry in GDT */
  217         movl    0(%edi), %eax
  218         movl    %eax, 0(%ebx)
  219         movl    4(%edi), %eax
  220         movl    %eax, 4(%ebx)
  221         movl    $GPROC0_SEL*8, %esi             /* GSEL(entry, SEL_KPL) */
  222         ltr     %si
  223 3:
  224         /* Note in vmspace that this cpu is using it. */
  225         movl    TD_PROC(%ecx),%eax
  226         movl    P_VMSPACE(%eax), %ebx
  227         movl    PCPU(CPUID), %eax
  228         btsl    %eax, VM_PMAP+PM_ACTIVE(%ebx)
  229 
  230         /* Restore context. */
  231         movl    PCB_EBX(%edx),%ebx
  232         movl    PCB_ESP(%edx),%esp
  233         movl    PCB_EBP(%edx),%ebp
  234         movl    PCB_ESI(%edx),%esi
  235         movl    PCB_EDI(%edx),%edi
  236         movl    PCB_EIP(%edx),%eax
  237         movl    %eax,(%esp)
  238         pushl   PCB_PSL(%edx)
  239         popfl
  240 
  241 #if defined(SMP) && defined(GRAB_LOPRIO)
  242         /* Hold LOPRIO for interrupts. */
  243 #ifdef CHEAP_TPR
  244         movl    $0, lapic+LA_TPR
  245 #else
  246         andl    $~APIC_TPR_PRIO, lapic+LA_TPR
  247 #endif
  248 #endif
  249         movl    %edx, PCPU(CURPCB)
  250         movl    %ecx, PCPU(CURTHREAD)           /* into next thread */
  251 
  252 #ifdef SMP
  253         /* XXX FIXME: we should be restoring the local APIC TPR */
  254 #endif
  255 
  256         /*
  257          * Determine the LDT to use and load it if is the default one and
  258          * that is not the current one.
  259          */
  260         movl    TD_PROC(%ecx),%eax
  261         cmpl    $0,P_MD+MD_LDT(%eax)
  262         jnz     1f
  263         movl    _default_ldt,%eax
  264         cmpl    PCPU(CURRENTLDT),%eax
  265         je      2f
  266         lldt    _default_ldt
  267         movl    %eax,PCPU(CURRENTLDT)
  268         jmp     2f
  269 1:
  270         /* Load the LDT when it is not the default one. */
  271         pushl   %edx                            /* Preserve pointer to pcb. */
  272         addl    $P_MD,%eax                      /* Pointer to mdproc is arg. */
  273         pushl   %eax
  274         call    set_user_ldt
  275         addl    $4,%esp
  276         popl    %edx
  277 2:
  278 
  279         /* This must be done after loading the user LDT. */
  280         .globl  cpu_switch_load_gs
  281 cpu_switch_load_gs:
  282         movl    PCB_GS(%edx),%gs
  283 
  284         /* Test if debug registers should be restored. */
  285         testl   $PCB_DBREGS,PCB_FLAGS(%edx)
  286         jz      1f
  287 
  288         /*
  289          * Restore debug registers.  The special code for dr7 is to
  290          * preserve the current values of its reserved bits.
  291          */
  292         movl    PCB_DR6(%edx),%eax
  293         movl    %eax,%dr6
  294         movl    PCB_DR3(%edx),%eax
  295         movl    %eax,%dr3
  296         movl    PCB_DR2(%edx),%eax
  297         movl    %eax,%dr2
  298         movl    PCB_DR1(%edx),%eax
  299         movl    %eax,%dr1
  300         movl    PCB_DR0(%edx),%eax
  301         movl    %eax,%dr0
  302         movl    %dr7,%eax
  303         andl    $0x0000fc00,%eax
  304         movl    PCB_DR7(%edx),%ecx
  305         andl    $~0x0000fc00,%ecx
  306         orl     %ecx,%eax
  307         movl    %eax,%dr7
  308 1:
  309         ret
  310 
  311 #ifdef INVARIANTS
  312 badsw3:
  313         pushal
  314         pushl   $sw0_3
  315         call    panic
  316 
  317 sw0_3:  .asciz  "cpu_switch: choosethread returned NULL"
  318 #endif
  319 
  320 /*
  321  * savectx(pcb)
  322  * Update pcb, saving current processor state.
  323  */
  324 ENTRY(savectx)
  325         /* Fetch PCB. */
  326         movl    4(%esp),%ecx
  327 
  328         /* Save caller's return address.  Child won't execute this routine. */
  329         movl    (%esp),%eax
  330         movl    %eax,PCB_EIP(%ecx)
  331 
  332         movl    %cr3,%eax
  333         movl    %eax,PCB_CR3(%ecx)
  334 
  335         movl    %ebx,PCB_EBX(%ecx)
  336         movl    %esp,PCB_ESP(%ecx)
  337         movl    %ebp,PCB_EBP(%ecx)
  338         movl    %esi,PCB_ESI(%ecx)
  339         movl    %edi,PCB_EDI(%ecx)
  340         movl    %gs,PCB_GS(%ecx)
  341         pushfl
  342         popl    PCB_PSL(%ecx)
  343 
  344 #ifdef DEV_NPX
  345         /*
  346          * If fpcurthread == NULL, then the npx h/w state is irrelevant and the
  347          * state had better already be in the pcb.  This is true for forks
  348          * but not for dumps (the old book-keeping with FP flags in the pcb
  349          * always lost for dumps because the dump pcb has 0 flags).
  350          *
  351          * If fpcurthread != NULL, then we have to save the npx h/w state to
  352          * fpcurthread's pcb and copy it to the requested pcb, or save to the
  353          * requested pcb and reload.  Copying is easier because we would
  354          * have to handle h/w bugs for reloading.  We used to lose the
  355          * parent's npx state for forks by forgetting to reload.
  356          */
  357         pushfl
  358         cli
  359         movl    PCPU(FPCURTHREAD),%eax
  360         testl   %eax,%eax
  361         je      1f
  362 
  363         pushl   %ecx
  364         movl    TD_PCB(%eax),%eax
  365         leal    PCB_SAVEFPU(%eax),%eax
  366         pushl   %eax
  367         pushl   %eax
  368         call    npxsave
  369         addl    $4,%esp
  370         popl    %eax
  371         popl    %ecx
  372 
  373         pushl   $PCB_SAVEFPU_SIZE
  374         leal    PCB_SAVEFPU(%ecx),%ecx
  375         pushl   %ecx
  376         pushl   %eax
  377         call    bcopy
  378         addl    $12,%esp
  379 1:
  380         popfl
  381 #endif  /* DEV_NPX */
  382 
  383         ret

Cache object: fb27d8abde2da162b6fe8fea64ca5f71


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.