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.1/sys/i386/i386/swtch.s 113148 2003-04-05 22:18:14Z peter $
   37  */
   38 
   39 #include "opt_npx.h"
   40 #include "opt_swtch.h"
   41 
   42 #include <machine/asmacros.h>
   43 
   44 #include "assym.s"
   45 
   46 /*****************************************************************************/
   47 /* Scheduling                                                                */
   48 /*****************************************************************************/
   49 
   50         .text
   51 
   52 /*
   53  * cpu_throw()
   54  *
   55  * This is the second half of cpu_swtch(). It is used when the current
   56  * thread is either a dummy or slated to die, and we no longer care
   57  * about its state.  This is only a slight optimization and is probably
   58  * not worth it anymore.  Note that we need to clear the pm_active bits so
   59  * we do need the old proc if it still exists.
   60  * 0(%esp) = ret
   61  * 4(%esp) = oldtd
   62  * 8(%esp) = newtd
   63  */
   64 ENTRY(cpu_throw)
   65         movl    PCPU(CPUID), %esi
   66         movl    4(%esp),%ecx                    /* Old thread */
   67         testl   %ecx,%ecx                       /* no thread? */
   68         jz      1f
   69         /* release bit from old pm_active */
   70         movl    TD_PROC(%ecx), %eax             /* thread->td_proc */
   71         movl    P_VMSPACE(%eax), %ebx           /* proc->p_vmspace */
   72 #ifdef SMP
   73         lock
   74 #endif
   75         btrl    %esi, VM_PMAP+PM_ACTIVE(%ebx)   /* clear old */
   76 1:
   77         movl    8(%esp),%ecx                    /* New thread */
   78         movl    TD_PCB(%ecx),%edx
   79 #ifdef SWTCH_OPTIM_STATS
   80         incl    tlb_flush_count
   81 #endif
   82         movl    PCB_CR3(%edx),%eax
   83         movl    %eax,%cr3                       /* new address space */
   84         /* set bit in new pm_active */
   85         movl    TD_PROC(%ecx),%eax
   86         movl    P_VMSPACE(%eax), %ebx
   87 #ifdef SMP
   88         lock
   89 #endif
   90         btsl    %esi, VM_PMAP+PM_ACTIVE(%ebx)   /* set new */
   91         jmp     sw1
   92 
   93 /*
   94  * cpu_switch(old, new)
   95  *
   96  * Save the current thread state, then select the next thread to run
   97  * and load its state.
   98  * 0(%esp) = ret
   99  * 4(%esp) = oldtd
  100  * 8(%esp) = newtd
  101  */
  102 ENTRY(cpu_switch)
  103 
  104         /* Switch to new thread.  First, save context. */
  105         movl    4(%esp),%ecx
  106 
  107 #ifdef INVARIANTS
  108         testl   %ecx,%ecx                       /* no thread? */
  109         jz      badsw2                          /* no, panic */
  110 #endif
  111 
  112         movl    TD_PCB(%ecx),%edx
  113 
  114         movl    (%esp),%eax                     /* Hardware registers */
  115         movl    %eax,PCB_EIP(%edx)
  116         movl    %ebx,PCB_EBX(%edx)
  117         movl    %esp,PCB_ESP(%edx)
  118         movl    %ebp,PCB_EBP(%edx)
  119         movl    %esi,PCB_ESI(%edx)
  120         movl    %edi,PCB_EDI(%edx)
  121         movl    %gs,PCB_GS(%edx)
  122         pushfl                                  /* PSL */
  123         popl    PCB_PSL(%edx)
  124 
  125         /* Test if debug registers should be saved. */
  126         testl   $PCB_DBREGS,PCB_FLAGS(%edx)
  127         jz      1f                              /* no, skip over */
  128         movl    %dr7,%eax                       /* yes, do the save */
  129         movl    %eax,PCB_DR7(%edx)
  130         andl    $0x0000fc00, %eax               /* disable all watchpoints */
  131         movl    %eax,%dr7
  132         movl    %dr6,%eax
  133         movl    %eax,PCB_DR6(%edx)
  134         movl    %dr3,%eax
  135         movl    %eax,PCB_DR3(%edx)
  136         movl    %dr2,%eax
  137         movl    %eax,PCB_DR2(%edx)
  138         movl    %dr1,%eax
  139         movl    %eax,PCB_DR1(%edx)
  140         movl    %dr0,%eax
  141         movl    %eax,PCB_DR0(%edx)
  142 1:
  143 
  144 #ifdef DEV_NPX
  145         /* have we used fp, and need a save? */
  146         cmpl    %ecx,PCPU(FPCURTHREAD)
  147         jne     1f
  148         addl    $PCB_SAVEFPU,%edx               /* h/w bugs make saving complicated */
  149         pushl   %edx
  150         call    npxsave                         /* do it in a big C function */
  151         popl    %eax
  152 1:
  153 #endif
  154 
  155         /* Save is done.  Now fire up new thread. Leave old vmspace. */
  156         movl    %ecx,%edi
  157         movl    8(%esp),%ecx                    /* New thread */
  158 #ifdef INVARIANTS
  159         testl   %ecx,%ecx                       /* no thread? */
  160         jz      badsw3                          /* no, panic */
  161 #endif
  162         movl    TD_PCB(%ecx),%edx
  163         movl    PCPU(CPUID), %esi
  164 
  165         /* switch address space */
  166         movl    PCB_CR3(%edx),%eax
  167 #ifdef LAZY_SWITCH
  168         cmpl    $0,lazy_flush_enable
  169         je      1f
  170         cmpl    %eax,IdlePTD                    /* Kernel address space? */
  171 #ifdef SWTCH_OPTIM_STATS
  172         je      3f
  173 #else
  174         je      sw1
  175 #endif
  176 1:
  177 #endif
  178         movl    %cr3,%ebx                       /* The same address space? */
  179         cmpl    %ebx,%eax
  180 #ifdef SWTCH_OPTIM_STATS
  181         je      2f                              /* Yes, skip all that cruft */
  182 #else
  183         je      sw1
  184 #endif
  185 #ifdef SWTCH_OPTIM_STATS
  186         incl    tlb_flush_count
  187 #endif
  188         movl    %eax,%cr3                       /* new address space */
  189 
  190         /* Release bit from old pmap->pm_active */
  191         movl    TD_PROC(%edi), %eax             /* oldproc */
  192         movl    P_VMSPACE(%eax), %ebx
  193 #ifdef SMP
  194         lock
  195 #endif
  196         btrl    %esi, VM_PMAP+PM_ACTIVE(%ebx)   /* clear old */
  197 
  198         /* Set bit in new pmap->pm_active */
  199         movl    TD_PROC(%ecx),%eax              /* newproc */
  200         movl    P_VMSPACE(%eax), %ebx
  201 #ifdef SMP
  202         lock
  203 #endif
  204         btsl    %esi, VM_PMAP+PM_ACTIVE(%ebx)   /* set new */
  205 
  206 #ifdef LAZY_SWITCH
  207 #ifdef SWTCH_OPTIM_STATS
  208         jmp     sw1
  209 
  210 2:                                              /* same address space */
  211         incl    swtch_optim_stats
  212         jmp     sw1
  213 
  214 3:                                              /* kernel address space */
  215         incl    lazy_flush_count
  216 #endif
  217 #endif
  218 
  219 sw1:
  220         /*
  221          * At this point, we've switched address spaces and are ready
  222          * to load up the rest of the next context.
  223          */
  224         cmpl    $0, PCB_EXT(%edx)               /* has pcb extension? */
  225         je      1f                              /* If not, use the default */
  226         btsl    %esi, private_tss               /* mark use of private tss */
  227         movl    PCB_EXT(%edx), %edi             /* new tss descriptor */
  228         jmp     2f                              /* Load it up */
  229 
  230 1:      /*
  231          * Use the common default TSS instead of our own.
  232          * Set our stack pointer into the TSS, it's set to just
  233          * below the PCB.  In C, common_tss.tss_esp0 = &pcb - 16;
  234          */
  235         leal    -16(%edx), %ebx                 /* leave space for vm86 */
  236         movl    %ebx, PCPU(COMMON_TSS) + TSS_ESP0
  237 
  238         /*
  239          * Test this CPU's  bit in the bitmap to see if this
  240          * CPU was using a private TSS.
  241          */
  242         btrl    %esi, private_tss               /* Already using the common? */
  243         jae     3f                              /* if so, skip reloading */
  244         PCPU_ADDR(COMMON_TSSD, %edi)
  245 2:
  246         /* Move correct tss descriptor into GDT slot, then reload tr. */
  247         movl    PCPU(TSS_GDT), %ebx             /* entry in GDT */
  248         movl    0(%edi), %eax
  249         movl    %eax, 0(%ebx)
  250         movl    4(%edi), %eax
  251         movl    %eax, 4(%ebx)
  252         movl    $GPROC0_SEL*8, %esi             /* GSEL(entry, SEL_KPL) */
  253         ltr     %si
  254 3:
  255 
  256         /* Restore context. */
  257         movl    PCB_EBX(%edx),%ebx
  258         movl    PCB_ESP(%edx),%esp
  259         movl    PCB_EBP(%edx),%ebp
  260         movl    PCB_ESI(%edx),%esi
  261         movl    PCB_EDI(%edx),%edi
  262         movl    PCB_EIP(%edx),%eax
  263         movl    %eax,(%esp)
  264         pushl   PCB_PSL(%edx)
  265         popfl
  266 
  267         movl    %edx, PCPU(CURPCB)
  268         movl    %ecx, PCPU(CURTHREAD)           /* into next thread */
  269 
  270         /*
  271          * Determine the LDT to use and load it if is the default one and
  272          * that is not the current one.
  273          */
  274         movl    TD_PROC(%ecx),%eax
  275         cmpl    $0,P_MD+MD_LDT(%eax)
  276         jnz     1f
  277         movl    _default_ldt,%eax
  278         cmpl    PCPU(CURRENTLDT),%eax
  279         je      2f
  280         lldt    _default_ldt
  281         movl    %eax,PCPU(CURRENTLDT)
  282         jmp     2f
  283 1:
  284         /* Load the LDT when it is not the default one. */
  285         pushl   %edx                            /* Preserve pointer to pcb. */
  286         addl    $P_MD,%eax                      /* Pointer to mdproc is arg. */
  287         pushl   %eax
  288         call    set_user_ldt
  289         addl    $4,%esp
  290         popl    %edx
  291 2:
  292 
  293         /* This must be done after loading the user LDT. */
  294         .globl  cpu_switch_load_gs
  295 cpu_switch_load_gs:
  296         movl    PCB_GS(%edx),%gs
  297 
  298         /* Test if debug registers should be restored. */
  299         testl   $PCB_DBREGS,PCB_FLAGS(%edx)
  300         jz      1f
  301 
  302         /*
  303          * Restore debug registers.  The special code for dr7 is to
  304          * preserve the current values of its reserved bits.
  305          */
  306         movl    PCB_DR6(%edx),%eax
  307         movl    %eax,%dr6
  308         movl    PCB_DR3(%edx),%eax
  309         movl    %eax,%dr3
  310         movl    PCB_DR2(%edx),%eax
  311         movl    %eax,%dr2
  312         movl    PCB_DR1(%edx),%eax
  313         movl    %eax,%dr1
  314         movl    PCB_DR0(%edx),%eax
  315         movl    %eax,%dr0
  316         movl    %dr7,%eax
  317         andl    $0x0000fc00,%eax
  318         movl    PCB_DR7(%edx),%ecx
  319         andl    $~0x0000fc00,%ecx
  320         orl     %ecx,%eax
  321         movl    %eax,%dr7
  322 1:
  323         ret
  324 
  325 #ifdef INVARIANTS
  326 badsw1:
  327         pushal
  328         pushl   $sw0_1
  329         call    panic
  330 sw0_1:  .asciz  "cpu_throw: no newthread supplied"
  331 
  332 badsw2:
  333         pushal
  334         pushl   $sw0_2
  335         call    panic
  336 sw0_2:  .asciz  "cpu_switch: no curthread supplied"
  337 
  338 badsw3:
  339         pushal
  340         pushl   $sw0_3
  341         call    panic
  342 sw0_3:  .asciz  "cpu_switch: no newthread supplied"
  343 #endif
  344 
  345 /*
  346  * savectx(pcb)
  347  * Update pcb, saving current processor state.
  348  */
  349 ENTRY(savectx)
  350         /* Fetch PCB. */
  351         movl    4(%esp),%ecx
  352 
  353         /* Save caller's return address.  Child won't execute this routine. */
  354         movl    (%esp),%eax
  355         movl    %eax,PCB_EIP(%ecx)
  356 
  357         movl    %cr3,%eax
  358         movl    %eax,PCB_CR3(%ecx)
  359 
  360         movl    %ebx,PCB_EBX(%ecx)
  361         movl    %esp,PCB_ESP(%ecx)
  362         movl    %ebp,PCB_EBP(%ecx)
  363         movl    %esi,PCB_ESI(%ecx)
  364         movl    %edi,PCB_EDI(%ecx)
  365         movl    %gs,PCB_GS(%ecx)
  366         pushfl
  367         popl    PCB_PSL(%ecx)
  368 
  369 #ifdef DEV_NPX
  370         /*
  371          * If fpcurthread == NULL, then the npx h/w state is irrelevant and the
  372          * state had better already be in the pcb.  This is true for forks
  373          * but not for dumps (the old book-keeping with FP flags in the pcb
  374          * always lost for dumps because the dump pcb has 0 flags).
  375          *
  376          * If fpcurthread != NULL, then we have to save the npx h/w state to
  377          * fpcurthread's pcb and copy it to the requested pcb, or save to the
  378          * requested pcb and reload.  Copying is easier because we would
  379          * have to handle h/w bugs for reloading.  We used to lose the
  380          * parent's npx state for forks by forgetting to reload.
  381          */
  382         pushfl
  383         cli
  384         movl    PCPU(FPCURTHREAD),%eax
  385         testl   %eax,%eax
  386         je      1f
  387 
  388         pushl   %ecx
  389         movl    TD_PCB(%eax),%eax
  390         leal    PCB_SAVEFPU(%eax),%eax
  391         pushl   %eax
  392         pushl   %eax
  393         call    npxsave
  394         addl    $4,%esp
  395         popl    %eax
  396         popl    %ecx
  397 
  398         pushl   $PCB_SAVEFPU_SIZE
  399         leal    PCB_SAVEFPU(%ecx),%ecx
  400         pushl   %ecx
  401         pushl   %eax
  402         call    bcopy
  403         addl    $12,%esp
  404 1:
  405         popfl
  406 #endif  /* DEV_NPX */
  407 
  408         ret

Cache object: 1934a235479d14e430ae2977f1ef2624


[ 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.