2 * Copyright (c) 1990 The Regents of the University of California.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
40 #include "opt_user_ldt.h"
42 #include <sys/rtprio.h>
44 #include <machine/asmacros.h>
47 #include <machine/pmap.h>
48 #include <machine/apic.h>
49 #include <machine/smptests.h> /** GRAB_LOPRIO */
50 #include <machine/lock.h>
56 /*****************************************************************************/
58 /*****************************************************************************/
64 #if defined(SWTCH_OPTIM_STATS)
65 .globl _swtch_optim_stats, _tlb_flush_count
66 _swtch_optim_stats: .long 0 /* number of _swtch_optims */
67 _tlb_flush_count: .long 0
83 /* switch to new process. first, save context as needed */
87 /* if no process to save, don't bother */
92 movb P_ONCPU(%ecx), %al /* save "last" cpu */
93 movb %al, P_LASTCPU(%ecx)
94 movb $0xff, P_ONCPU(%ecx) /* "leave" the cpu */
96 movl P_VMSPACE(%ecx), %edx
102 btrl %eax, VM_PMAP+PM_ACTIVE(%edx)
104 movl P_ADDR(%ecx),%edx
106 movl (%esp),%eax /* Hardware registers */
107 movl %eax,PCB_EIP(%edx)
108 movl %ebx,PCB_EBX(%edx)
109 movl %esp,PCB_ESP(%edx)
110 movl %ebp,PCB_EBP(%edx)
111 movl %esi,PCB_ESI(%edx)
112 movl %edi,PCB_EDI(%edx)
113 movl %gs,PCB_GS(%edx)
115 /* test if debug registers should be saved */
116 movb PCB_FLAGS(%edx),%al
118 jz 1f /* no, skip over */
119 movl %dr7,%eax /* yes, do the save */
120 movl %eax,PCB_DR7(%edx)
121 andl $0x0000ff00, %eax /* disable all watchpoints */
124 movl %eax,PCB_DR6(%edx)
126 movl %eax,PCB_DR3(%edx)
128 movl %eax,PCB_DR2(%edx)
130 movl %eax,PCB_DR1(%edx)
132 movl %eax,PCB_DR0(%edx)
135 /* save sched_lock recursion count */
136 movl _sched_lock+MTX_RECURSE,%eax
137 movl %eax,PCB_SCHEDNEST(%edx)
140 /* XXX FIXME: we should be saving the local APIC TPR */
144 /* have we used fp, and need a save? */
147 addl $PCB_SAVEFPU,%edx /* h/w bugs make saving complicated */
149 call _npxsave /* do it in a big C function */
152 #endif /* NNPX > 0 */
154 /* save is done, now choose a new process */
158 /* Stop scheduling if smp_active goes zero and we are not BSP */
170 * Choose a new process to schedule. chooseproc() returns idleproc
171 * if it cannot find another process to run.
174 call _chooseproc /* trash ecx, edx, ret eax*/
177 testl %eax,%eax /* no process? */
178 jz badsw3 /* no, panic */
184 andl $~AST_RESCHED,_astpending
187 cmpl %eax,P_WCHAN(%ecx)
189 cmpb $SRUN,P_STAT(%ecx)
193 movl P_ADDR(%ecx),%edx
195 #if defined(SWTCH_OPTIM_STATS)
196 incl _swtch_optim_stats
198 /* switch address space */
200 cmpl PCB_CR3(%edx),%ebx
202 #if defined(SWTCH_OPTIM_STATS)
203 decl _swtch_optim_stats
204 incl _tlb_flush_count
206 movl PCB_CR3(%edx),%ebx
215 cmpl $0, PCB_EXT(%edx) /* has pcb extension? */
217 btsl %esi, _private_tss /* mark use of private tss */
218 movl PCB_EXT(%edx), %edi /* new tss descriptor */
222 /* update common_tss.tss_esp0 pointer */
223 movl %edx, %ebx /* pcb */
224 addl $(UPAGES * PAGE_SIZE - 16), %ebx
225 movl %ebx, _common_tss + TSS_ESP0
227 btrl %esi, _private_tss
230 movl $gd_common_tssd, %edi
233 movl $_common_tssd, %edi
236 /* move correct tss descriptor into GDT slot, then reload tr */
237 movl _tss_gdt, %ebx /* entry in GDT */
242 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */
245 movl P_VMSPACE(%ecx), %ebx
251 btsl %eax, VM_PMAP+PM_ACTIVE(%ebx)
253 /* restore context */
254 movl PCB_EBX(%edx),%ebx
255 movl PCB_ESP(%edx),%esp
256 movl PCB_EBP(%edx),%ebp
257 movl PCB_ESI(%edx),%esi
258 movl PCB_EDI(%edx),%edi
259 movl PCB_EIP(%edx),%eax
263 #ifdef GRAB_LOPRIO /* hold LOPRIO for INTs */
267 andl $~APIC_TPR_PRIO, lapic_tpr
268 #endif /** CHEAP_TPR */
269 #endif /** GRAB_LOPRIO */
271 movb %al, P_ONCPU(%ecx)
274 movl %ecx, _curproc /* into next process */
277 /* XXX FIXME: we should be restoring the local APIC TPR */
281 cmpl $0, PCB_USERLDT(%edx)
283 movl __default_ldt,%eax
284 cmpl _currentldt,%eax
287 movl %eax,_currentldt
295 /* This must be done after loading the user LDT. */
296 .globl cpu_switch_load_gs
298 movl PCB_GS(%edx),%gs
300 /* test if debug regisers should be restored */
301 movb PCB_FLAGS(%edx),%al
303 jz 1f /* no, skip over */
304 movl PCB_DR6(%edx),%eax /* yes, do the restore */
306 movl PCB_DR3(%edx),%eax
308 movl PCB_DR2(%edx),%eax
310 movl PCB_DR1(%edx),%eax
312 movl PCB_DR0(%edx),%eax
314 movl PCB_DR7(%edx),%eax
319 * restore sched_lock recursion count and transfer ownership to
322 movl PCB_SCHEDNEST(%edx),%eax
323 movl %eax,_sched_lock+MTX_RECURSE
326 movl %eax,_sched_lock+MTX_LOCK
331 testl $0x200, %ecx /* interrupts enabled? */
332 jnz badsw6 /* that way madness lies */
336 CROSSJUMPTARGET(sw1a)
343 sw0_1: .asciz "cpu_switch: has wchan"
349 sw0_2: .asciz "cpu_switch: not SRUN"
355 sw0_3: .asciz "cpu_switch: chooseproc returned NULL"
364 sw0_5: .asciz "cpu_switch: interrupts enabled (again)"
369 sw0_6: .asciz "cpu_switch: interrupts enabled"
374 * Update pcb, saving current processor state.
380 /* caller's return address - child won't execute this routine */
382 movl %eax,PCB_EIP(%ecx)
384 movl %ebx,PCB_EBX(%ecx)
385 movl %esp,PCB_ESP(%ecx)
386 movl %ebp,PCB_EBP(%ecx)
387 movl %esi,PCB_ESI(%ecx)
388 movl %edi,PCB_EDI(%ecx)
389 movl %gs,PCB_GS(%ecx)
393 * If npxproc == NULL, then the npx h/w state is irrelevant and the
394 * state had better already be in the pcb. This is true for forks
395 * but not for dumps (the old book-keeping with FP flags in the pcb
396 * always lost for dumps because the dump pcb has 0 flags).
398 * If npxproc != NULL, then we have to save the npx h/w state to
399 * npxproc's pcb and copy it to the requested pcb, or save to the
400 * requested pcb and reload. Copying is easier because we would
401 * have to handle h/w bugs for reloading. We used to lose the
402 * parent's npx state for forks by forgetting to reload.
409 movl P_ADDR(%eax),%eax
410 leal PCB_SAVEFPU(%eax),%eax
418 pushl $PCB_SAVEFPU_SIZE
419 leal PCB_SAVEFPU(%ecx),%ecx
424 #endif /* NNPX > 0 */