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/amd64/amd64/cpu_switch.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/amd64/amd64/cpu_switch.S 115006 2003-05-15 00:23:40Z peter $
   37  */
   38 
   39 #include <machine/asmacros.h>
   40 
   41 #include "assym.s"
   42 
   43 /*****************************************************************************/
   44 /* Scheduling                                                                */
   45 /*****************************************************************************/
   46 
   47         .text
   48 
   49 /*
   50  * cpu_throw()
   51  *
   52  * This is the second half of cpu_swtch(). It is used when the current
   53  * thread is either a dummy or slated to die, and we no longer care
   54  * about its state.  This is only a slight optimization and is probably
   55  * not worth it anymore.  Note that we need to clear the pm_active bits so
   56  * we do need the old proc if it still exists.
   57  * %rdi = oldtd
   58  * %rsi = newtd
   59  */
   60 ENTRY(cpu_throw)
   61         xorq    %rax, %rax
   62         movl    PCPU(CPUID), %eax
   63         testq   %rdi,%rdi                       /* no thread? */
   64         jz      1f
   65         /* release bit from old pm_active */
   66         movq    TD_PROC(%rdi), %rdx             /* oldtd->td_proc */
   67         movq    P_VMSPACE(%rdx), %rdx           /* proc->p_vmspace */
   68         btrq    %rax, VM_PMAP+PM_ACTIVE(%rdx)   /* clear old */
   69 1:
   70         movq    TD_PCB(%rsi),%rdx               /* newtd->td_proc */
   71         movq    PCB_CR3(%rdx),%rdx
   72         movq    %rdx,%cr3                       /* new address space */
   73         /* set bit in new pm_active */
   74         movq    TD_PROC(%rsi),%rdx
   75         movq    P_VMSPACE(%rdx), %rdx
   76         btsq    %rax, VM_PMAP+PM_ACTIVE(%rdx)   /* set new */
   77         jmp     sw1
   78 
   79 /*
   80  * cpu_switch(old, new)
   81  *
   82  * Save the current thread state, then select the next thread to run
   83  * and load its state.
   84  * %rdi = oldtd
   85  * %rsi = newtd
   86  */
   87 ENTRY(cpu_switch)
   88 
   89         /* Switch to new thread.  First, save context. */
   90 #ifdef INVARIANTS
   91         testq   %rdi,%rdi                       /* no thread? */
   92         jz      badsw2                          /* no, panic */
   93 #endif
   94 
   95         movq    TD_PCB(%rdi),%r8
   96 
   97         movq    (%rsp),%rax                     /* Hardware registers */
   98         movq    %rax,PCB_RIP(%r8)
   99         movq    %rbx,PCB_RBX(%r8)
  100         movq    %rsp,PCB_RSP(%r8)
  101         movq    %rbp,PCB_RBP(%r8)
  102         movq    %r12,PCB_R12(%r8)
  103         movq    %r13,PCB_R13(%r8)
  104         movq    %r14,PCB_R14(%r8)
  105         movq    %r15,PCB_R15(%r8)
  106         pushfq                                  /* PSL */
  107         popq    PCB_RFLAGS(%r8)
  108 
  109         /* Save userland %fs */
  110         movl    $MSR_FSBASE,%ecx
  111         rdmsr
  112         movl    %eax,PCB_FSBASE(%r8)
  113         movl    %edx,PCB_FSBASE+4(%r8)
  114 
  115         /* Save userland %gs */
  116         movl    $MSR_KGSBASE,%ecx
  117         rdmsr
  118         movl    %eax,PCB_GSBASE(%r8)
  119         movl    %edx,PCB_GSBASE+4(%r8)
  120 
  121         /* Save segment selector numbers */
  122         movl    %ds,PCB_DS(%r8)
  123         movl    %es,PCB_ES(%r8)
  124         movl    %fs,PCB_FS(%r8)
  125         movl    %gs,PCB_GS(%r8)
  126 
  127         /* have we used fp, and need a save? */
  128         cmpq    %rdi,PCPU(FPCURTHREAD)
  129         jne     1f
  130         pushq   %rdi
  131         pushq   %rsi
  132         addq    $PCB_SAVEFPU,%r8                /* h/w bugs make saving complicated */
  133         movq    %r8, %rdi
  134         call    npxsave                         /* do it in a big C function */
  135         popq    %rsi
  136         popq    %rdi
  137 1:
  138 
  139         /* Save is done.  Now fire up new thread. Leave old vmspace. */
  140 #ifdef INVARIANTS
  141         testq   %rsi,%rsi                       /* no thread? */
  142         jz      badsw3                          /* no, panic */
  143 #endif
  144         movq    TD_PCB(%rsi),%r8
  145         xorq    %rax, %rax
  146         movl    PCPU(CPUID), %eax
  147 
  148         /* switch address space */
  149         movq    PCB_CR3(%r8),%rdx
  150         movq    %rdx,%cr3                       /* new address space */
  151 
  152         /* Release bit from old pmap->pm_active */
  153         movq    TD_PROC(%rdi), %rdx             /* oldproc */
  154         movq    P_VMSPACE(%rdx), %rdx
  155         btrq    %rax, VM_PMAP+PM_ACTIVE(%rdx)   /* clear old */
  156 
  157         /* Set bit in new pmap->pm_active */
  158         movq    TD_PROC(%rsi),%rdx              /* newproc */
  159         movq    P_VMSPACE(%rdx), %rdx
  160         btsq    %rax, VM_PMAP+PM_ACTIVE(%rdx)   /* set new */
  161 
  162 sw1:
  163         /*
  164          * At this point, we've switched address spaces and are ready
  165          * to load up the rest of the next context.
  166          */
  167         movq    TD_PCB(%rsi),%r8
  168 
  169         /* Restore segment selector numbers */
  170         movl    PCB_DS(%r8),%ds
  171         movl    PCB_ES(%r8),%es
  172         movl    PCB_FS(%r8),%fs
  173 
  174         /* Restore userland %gs while preserving kernel gsbase */
  175         movl    $MSR_GSBASE,%ecx
  176         rdmsr
  177         movl    PCB_GS(%r8),%gs
  178         wrmsr
  179 
  180         /* Restore userland %fs */
  181         movl    $MSR_FSBASE,%ecx
  182         movl    PCB_FSBASE(%r8),%eax
  183         movl    PCB_FSBASE+4(%r8),%edx
  184         wrmsr
  185 
  186         /* Restore userland %gs */
  187         movl    $MSR_KGSBASE,%ecx
  188         movl    PCB_GSBASE(%r8),%eax
  189         movl    PCB_GSBASE+4(%r8),%edx
  190         wrmsr
  191 
  192         /* Update the TSS_RSP0 pointer for the next interrupt */
  193         leaq    -16(%r8), %rbx
  194         movq    %rbx, common_tss + COMMON_TSS_RSP0
  195 
  196         /* Restore context. */
  197         movq    PCB_RBX(%r8),%rbx
  198         movq    PCB_RSP(%r8),%rsp
  199         movq    PCB_RBP(%r8),%rbp
  200         movq    PCB_R12(%r8),%r12
  201         movq    PCB_R13(%r8),%r13
  202         movq    PCB_R14(%r8),%r14
  203         movq    PCB_R15(%r8),%r15
  204         movq    PCB_RIP(%r8),%rax
  205         movq    %rax,(%rsp)
  206         pushq   PCB_RFLAGS(%r8)
  207         popfq
  208 
  209         movq    %r8, PCPU(CURPCB)
  210         movq    %rsi, PCPU(CURTHREAD)           /* into next thread */
  211 
  212         ret
  213 
  214 #ifdef INVARIANTS
  215 badsw1:
  216         pushq   %rax
  217         pushq   %rcx
  218         pushq   %rdx
  219         pushq   %rbx
  220         pushq   %rbp
  221         pushq   %rsi
  222         pushq   %rdi
  223         pushq   %r8
  224         pushq   %r9
  225         pushq   %r10
  226         pushq   %r11
  227         pushq   %r12
  228         pushq   %r13
  229         pushq   %r14
  230         pushq   %r15
  231         pushq   $sw0_1
  232         call    panic
  233 sw0_1:  .asciz  "cpu_throw: no newthread supplied"
  234 
  235 badsw2:
  236         pushq   %rax
  237         pushq   %rcx
  238         pushq   %rdx
  239         pushq   %rbx
  240         pushq   %rbp
  241         pushq   %rsi
  242         pushq   %rdi
  243         pushq   %r8
  244         pushq   %r9
  245         pushq   %r10
  246         pushq   %r11
  247         pushq   %r12
  248         pushq   %r13
  249         pushq   %r14
  250         pushq   %r15
  251         pushq   $sw0_2
  252         call    panic
  253 sw0_2:  .asciz  "cpu_switch: no curthread supplied"
  254 
  255 badsw3:
  256         pushq   %rax
  257         pushq   %rcx
  258         pushq   %rdx
  259         pushq   %rbx
  260         pushq   %rbp
  261         pushq   %rsi
  262         pushq   %rdi
  263         pushq   %r8
  264         pushq   %r9
  265         pushq   %r10
  266         pushq   %r11
  267         pushq   %r12
  268         pushq   %r13
  269         pushq   %r14
  270         pushq   %r15
  271         pushq   $sw0_3
  272         call    panic
  273 sw0_3:  .asciz  "cpu_switch: no newthread supplied"
  274 #endif
  275 
  276 noswitch:       .asciz  "cpu_switch: called!"
  277 nothrow:        .asciz  "cpu_throw: called!"
  278 /*
  279  * savectx(pcb)
  280  * Update pcb, saving current processor state.
  281  */
  282 ENTRY(savectx)
  283         /* Fetch PCB. */
  284         movq    %rdi,%rcx
  285 
  286         /* Save caller's return address. */
  287         movq    (%rsp),%rax
  288         movq    %rax,PCB_RIP(%rcx)
  289 
  290         movq    %cr3,%rax
  291         movq    %rax,PCB_CR3(%rcx)
  292 
  293         movq    %rbx,PCB_RBX(%rcx)
  294         movq    %rsp,PCB_RSP(%rcx)
  295         movq    %rbp,PCB_RBP(%rcx)
  296         movq    %r12,PCB_R12(%rcx)
  297         movq    %r13,PCB_R13(%rcx)
  298         movq    %r14,PCB_R14(%rcx)
  299         movq    %r15,PCB_R15(%rcx)
  300         pushfq
  301         popq    PCB_RFLAGS(%rcx)
  302 
  303         /*
  304          * If fpcurthread == NULL, then the npx h/w state is irrelevant and the
  305          * state had better already be in the pcb.  This is true for forks
  306          * but not for dumps (the old book-keeping with FP flags in the pcb
  307          * always lost for dumps because the dump pcb has 0 flags).
  308          *
  309          * If fpcurthread != NULL, then we have to save the npx h/w state to
  310          * fpcurthread's pcb and copy it to the requested pcb, or save to the
  311          * requested pcb and reload.  Copying is easier because we would
  312          * have to handle h/w bugs for reloading.  We used to lose the
  313          * parent's npx state for forks by forgetting to reload.
  314          */
  315         pushfq
  316         cli
  317         movq    PCPU(FPCURTHREAD),%rax
  318         testq   %rax,%rax
  319         je      1f
  320 
  321         pushq   %rcx
  322         pushq   %rax
  323         movq    TD_PCB(%rax),%rdi
  324         leaq    PCB_SAVEFPU(%rdi),%rdi
  325         call    npxsave
  326         popq    %rax
  327         popq    %rcx
  328 
  329         movq    $PCB_SAVEFPU_SIZE,%rdx  /* arg 3 */
  330         leaq    PCB_SAVEFPU(%rcx),%rsi  /* arg 2 */
  331         movq    %rax,%rdi               /* arg 1 */
  332         call    bcopy
  333 1:
  334         popfq
  335 
  336         ret

Cache object: 2b757cffab76cc2e65048d725f7fae55


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