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/ipl.h>
51 #include <machine/lock.h>
57 /*****************************************************************************/
59 /*****************************************************************************/
64 _hlt_vector: .long _default_halt /* pointer to halt routine */
69 _want_resched: .long 0 /* we need to re-run the scheduler */
70 #if defined(SWTCH_OPTIM_STATS)
71 .globl _swtch_optim_stats, _tlb_flush_count
72 _swtch_optim_stats: .long 0 /* number of _swtch_optims */
73 _tlb_flush_count: .long 0
79 * When no processes are on the runq, cpu_switch() branches to _idle
80 * to wait for something to come ready.
90 /* when called, we have the mplock, intr disabled */
91 /* use our idleproc's "context" */
96 #if defined(SWTCH_OPTIM_STATS)
97 decl _swtch_optim_stats
102 /* Keep space for nonexisting return addr, or profiling bombs */
103 movl $gd_idlestack_top-4, %ecx
107 /* update common_tss.tss_esp0 pointer */
108 movl %ecx, _common_tss + TSS_ESP0
111 btrl %esi, _private_tss
114 movl $gd_common_tssd, %edi
117 /* move correct tss descriptor into GDT slot, then reload tr */
118 movl _tss_gdt, %ebx /* entry in GDT */
123 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */
130 * XXX callers of cpu_switch() do a bogus splclock(). Locking should
131 * be left to cpu_switch().
138 * _REALLY_ free the lock, no matter how deep the prior nesting.
139 * We will recover the nesting on the way out when we have a new
142 * XXX: we had damn well better be sure we had it before doing this!
144 movl $FREE_LOCK, %eax
147 /* do NOT have lock, intrs disabled */
162 cmpl $0,_do_page_zero_idle
165 /* XXX appears to cause panics */
167 * Inside zero_idle we enable interrupts and grab the mplock
168 * as needed. It needs to be careful about entry/exit mutexes.
170 call _vm_page_zero_idle /* internal locking */
175 /* enable intrs for a halt */
176 movl $0, lapic_tpr /* 1st candidate for an INT */
177 call *_hlt_vector /* wait for interrupt */
182 movl $LOPRIO_LEVEL, lapic_tpr /* arbitrate for INTs */
186 CROSSJUMP(jnz, sw1a, jz)
192 movl $HIDENAME(tmpstk),%esp
193 #if defined(OVERLY_CONSERVATIVE_PTD_MGMT)
194 #if defined(SWTCH_OPTIM_STATS)
195 incl _swtch_optim_stats
201 #if defined(SWTCH_OPTIM_STATS)
202 decl _swtch_optim_stats
203 incl _tlb_flush_count
209 /* update common_tss.tss_esp0 pointer */
210 movl %esp, _common_tss + TSS_ESP0
213 btrl %esi, _private_tss
216 movl $_common_tssd, %edi
218 /* move correct tss descriptor into GDT slot, then reload tr */
219 movl _tss_gdt, %ebx /* entry in GDT */
224 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */
231 * XXX callers of cpu_switch() do a bogus splclock(). Locking should
232 * be left to cpu_switch().
241 CROSSJUMP(jnz, sw1a, jz)
242 call _vm_page_zero_idle
245 call *_hlt_vector /* wait for interrupt */
250 CROSSJUMPTARGET(_idle)
255 hlt /* XXX: until a wakeup IPI */
264 /* switch to new process. first, save context as needed */
267 /* if no process to save, don't bother */
272 movb P_ONCPU(%ecx), %al /* save "last" cpu */
273 movb %al, P_LASTCPU(%ecx)
274 movb $0xff, P_ONCPU(%ecx) /* "leave" the cpu */
276 movl P_VMSPACE(%ecx), %edx
282 btrl %eax, VM_PMAP+PM_ACTIVE(%edx)
284 movl P_ADDR(%ecx),%edx
286 movl (%esp),%eax /* Hardware registers */
287 movl %eax,PCB_EIP(%edx)
288 movl %ebx,PCB_EBX(%edx)
289 movl %esp,PCB_ESP(%edx)
290 movl %ebp,PCB_EBP(%edx)
291 movl %esi,PCB_ESI(%edx)
292 movl %edi,PCB_EDI(%edx)
293 movl %gs,PCB_GS(%edx)
295 /* test if debug regisers should be saved */
296 movb PCB_FLAGS(%edx),%al
298 jz 1f /* no, skip over */
299 movl %dr7,%eax /* yes, do the save */
300 movl %eax,PCB_DR7(%edx)
301 andl $0x0000ff00, %eax /* disable all watchpoints */
304 movl %eax,PCB_DR6(%edx)
306 movl %eax,PCB_DR3(%edx)
308 movl %eax,PCB_DR2(%edx)
310 movl %eax,PCB_DR1(%edx)
312 movl %eax,PCB_DR0(%edx)
317 /* XXX FIXME: we should be saving the local APIC TPR */
319 cmpl $FREE_LOCK, %eax /* is it free? */
320 je badsw4 /* yes, bad medicine! */
321 #endif /* DIAGNOSTIC */
322 andl $COUNT_FIELD, %eax /* clear CPU portion */
323 movl %eax, PCB_MPNEST(%edx) /* store it */
327 /* have we used fp, and need a save? */
330 addl $PCB_SAVEFPU,%edx /* h/w bugs make saving complicated */
332 call _npxsave /* do it in a big C function */
335 #endif /* NNPX > 0 */
337 movl $0,_curproc /* out of process */
339 /* save is done, now choose a new process or idle */
344 /* Stop scheduling if smp_active goes zero and we are not BSP */
348 CROSSJUMP(je, _idle, jne) /* wind down */
353 call _chooseproc /* trash ecx, edx, ret eax*/
355 CROSSJUMP(je, _idle, jne) /* if no proc, idle */
359 movl %eax,_want_resched
362 cmpl %eax,P_WCHAN(%ecx)
364 cmpb $SRUN,P_STAT(%ecx)
368 movl P_ADDR(%ecx),%edx
370 #if defined(SWTCH_OPTIM_STATS)
371 incl _swtch_optim_stats
373 /* switch address space */
375 cmpl PCB_CR3(%edx),%ebx
377 #if defined(SWTCH_OPTIM_STATS)
378 decl _swtch_optim_stats
379 incl _tlb_flush_count
381 movl PCB_CR3(%edx),%ebx
390 cmpl $0, PCB_EXT(%edx) /* has pcb extension? */
392 btsl %esi, _private_tss /* mark use of private tss */
393 movl PCB_EXT(%edx), %edi /* new tss descriptor */
397 /* update common_tss.tss_esp0 pointer */
398 movl %edx, %ebx /* pcb */
399 addl $(UPAGES * PAGE_SIZE - 16), %ebx
400 movl %ebx, _common_tss + TSS_ESP0
402 btrl %esi, _private_tss
405 movl $gd_common_tssd, %edi
408 movl $_common_tssd, %edi
411 /* move correct tss descriptor into GDT slot, then reload tr */
412 movl _tss_gdt, %ebx /* entry in GDT */
417 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */
420 movl P_VMSPACE(%ecx), %ebx
426 btsl %eax, VM_PMAP+PM_ACTIVE(%ebx)
428 /* restore context */
429 movl PCB_EBX(%edx),%ebx
430 movl PCB_ESP(%edx),%esp
431 movl PCB_EBP(%edx),%ebp
432 movl PCB_ESI(%edx),%esi
433 movl PCB_EDI(%edx),%edi
434 movl PCB_EIP(%edx),%eax
438 #ifdef GRAB_LOPRIO /* hold LOPRIO for INTs */
442 andl $~APIC_TPR_PRIO, lapic_tpr
443 #endif /** CHEAP_TPR */
444 #endif /** GRAB_LOPRIO */
446 movb %al, P_ONCPU(%ecx)
449 movl %ecx, _curproc /* into next process */
452 movl _cpu_lockid, %eax
453 orl PCB_MPNEST(%edx), %eax /* add next count from PROC */
454 movl %eax, _mp_lock /* load the mp_lock */
455 /* XXX FIXME: we should be restoring the local APIC TPR */
459 cmpl $0, PCB_USERLDT(%edx)
461 movl __default_ldt,%eax
462 cmpl _currentldt,%eax
465 movl %eax,_currentldt
473 /* This must be done after loading the user LDT. */
474 .globl cpu_switch_load_gs
476 movl PCB_GS(%edx),%gs
478 /* test if debug regisers should be restored */
479 movb PCB_FLAGS(%edx),%al
481 jz 1f /* no, skip over */
482 movl PCB_DR6(%edx),%eax /* yes, do the restore */
484 movl PCB_DR3(%edx),%eax
486 movl PCB_DR2(%edx),%eax
488 movl PCB_DR1(%edx),%eax
490 movl PCB_DR0(%edx),%eax
492 movl PCB_DR7(%edx),%eax
499 CROSSJUMPTARGET(sw1a)
506 sw0_1: .asciz "cpu_switch: has wchan"
512 sw0_2: .asciz "cpu_switch: not SRUN"
515 #if defined(SMP) && defined(DIAGNOSTIC)
520 sw0_4: .asciz "cpu_switch: do not have lock"
521 #endif /* SMP && DIAGNOSTIC */
525 * Update pcb, saving current processor state.
531 /* caller's return address - child won't execute this routine */
533 movl %eax,PCB_EIP(%ecx)
535 movl %ebx,PCB_EBX(%ecx)
536 movl %esp,PCB_ESP(%ecx)
537 movl %ebp,PCB_EBP(%ecx)
538 movl %esi,PCB_ESI(%ecx)
539 movl %edi,PCB_EDI(%ecx)
540 movl %gs,PCB_GS(%ecx)
544 * If npxproc == NULL, then the npx h/w state is irrelevant and the
545 * state had better already be in the pcb. This is true for forks
546 * but not for dumps (the old book-keeping with FP flags in the pcb
547 * always lost for dumps because the dump pcb has 0 flags).
549 * If npxproc != NULL, then we have to save the npx h/w state to
550 * npxproc's pcb and copy it to the requested pcb, or save to the
551 * requested pcb and reload. Copying is easier because we would
552 * have to handle h/w bugs for reloading. We used to lose the
553 * parent's npx state for forks by forgetting to reload.
560 movl P_ADDR(%eax),%eax
561 leal PCB_SAVEFPU(%eax),%eax
569 pushl $PCB_SAVEFPU_SIZE
570 leal PCB_SAVEFPU(%ecx),%ecx
575 #endif /* NNPX > 0 */