swtch.s revision 72358
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: head/sys/i386/i386/swtch.s 72358 2001-02-11 10:44:09Z markm $ 37 */ 38 39#include "opt_npx.h" 40#include "opt_user_ldt.h" 41 42#include <sys/rtprio.h> 43 44#include <machine/asmacros.h> 45#include <machine/ipl.h> 46 47#ifdef SMP 48#include <machine/pmap.h> 49#include <machine/apic.h> 50#include <machine/smptests.h> /** GRAB_LOPRIO */ 51#endif /* SMP */ 52 53#include "assym.s" 54 55 56/*****************************************************************************/ 57/* Scheduling */ 58/*****************************************************************************/ 59 60 .data 61 62 .globl _panic 63 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 68#endif 69 70 .text 71 72/* 73 * cpu_throw() 74 */ 75ENTRY(cpu_throw) 76 jmp sw1 77 78/* 79 * cpu_switch() 80 */ 81ENTRY(cpu_switch) 82 83 /* switch to new process. first, save context as needed */ 84 movl PCPU(CURPROC),%ecx 85 86 /* if no process to save, don't bother */ 87 testl %ecx,%ecx 88 jz sw1 89 90#ifdef SMP 91 movb P_ONCPU(%ecx), %al /* save "last" cpu */ 92 movb %al, P_LASTCPU(%ecx) 93 movb $0xff, P_ONCPU(%ecx) /* "leave" the cpu */ 94#endif /* SMP */ 95 movl P_VMSPACE(%ecx), %edx 96#ifdef SMP 97 movl PCPU(CPUID), %eax 98#else 99 xorl %eax, %eax 100#endif /* SMP */ 101 btrl %eax, VM_PMAP+PM_ACTIVE(%edx) 102 103 movl P_ADDR(%ecx),%edx 104 105 movl (%esp),%eax /* Hardware registers */ 106 movl %eax,PCB_EIP(%edx) 107 movl %ebx,PCB_EBX(%edx) 108 movl %esp,PCB_ESP(%edx) 109 movl %ebp,PCB_EBP(%edx) 110 movl %esi,PCB_ESI(%edx) 111 movl %edi,PCB_EDI(%edx) 112 movl %gs,PCB_GS(%edx) 113 114 /* test if debug registers should be saved */ 115 movb PCB_FLAGS(%edx),%al 116 andb $PCB_DBREGS,%al 117 jz 1f /* no, skip over */ 118 movl %dr7,%eax /* yes, do the save */ 119 movl %eax,PCB_DR7(%edx) 120 andl $0x0000ff00, %eax /* disable all watchpoints */ 121 movl %eax,%dr7 122 movl %dr6,%eax 123 movl %eax,PCB_DR6(%edx) 124 movl %dr3,%eax 125 movl %eax,PCB_DR3(%edx) 126 movl %dr2,%eax 127 movl %eax,PCB_DR2(%edx) 128 movl %dr1,%eax 129 movl %eax,PCB_DR1(%edx) 130 movl %dr0,%eax 131 movl %eax,PCB_DR0(%edx) 1321: 133 134 /* save sched_lock recursion count */ 135 movl _sched_lock+MTX_RECURSECNT,%eax 136 movl %eax,PCB_SCHEDNEST(%edx) 137 138#ifdef SMP 139 /* XXX FIXME: we should be saving the local APIC TPR */ 140#endif /* SMP */ 141 142#ifdef DEV_NPX 143 /* have we used fp, and need a save? */ 144 cmpl %ecx,PCPU(NPXPROC) 145 jne 1f 146 addl $PCB_SAVEFPU,%edx /* h/w bugs make saving complicated */ 147 pushl %edx 148 call _npxsave /* do it in a big C function */ 149 popl %eax 1501: 151#endif /* DEV_NPX */ 152 153 /* save is done, now choose a new process */ 154sw1: 155 156#ifdef SMP 157 /* Stop scheduling if smp_active goes zero and we are not BSP */ 158 cmpl $0,_smp_active 159 jne 1f 160 cmpl $0,PCPU(CPUID) 161 je 1f 162 163 movl PCPU(IDLEPROC), %eax 164 jmp sw1b 1651: 166#endif 167 168 /* 169 * Choose a new process to schedule. chooseproc() returns idleproc 170 * if it cannot find another process to run. 171 */ 172sw1a: 173 call _chooseproc /* trash ecx, edx, ret eax*/ 174 175#ifdef INVARIANTS 176 testl %eax,%eax /* no process? */ 177 jz badsw3 /* no, panic */ 178#endif 179sw1b: 180 movl %eax,%ecx 181 182#ifdef INVARIANTS 183 cmpb $SRUN,P_STAT(%ecx) 184 jne badsw2 185#endif 186 187 movl P_ADDR(%ecx),%edx 188 189#if defined(SWTCH_OPTIM_STATS) 190 incl _swtch_optim_stats 191#endif 192 /* switch address space */ 193 movl %cr3,%ebx 194 cmpl PCB_CR3(%edx),%ebx 195 je 4f 196#if defined(SWTCH_OPTIM_STATS) 197 decl _swtch_optim_stats 198 incl _tlb_flush_count 199#endif 200 movl PCB_CR3(%edx),%ebx 201 movl %ebx,%cr3 2024: 203 204#ifdef SMP 205 movl PCPU(CPUID), %esi 206#else 207 xorl %esi, %esi 208#endif 209 cmpl $0, PCB_EXT(%edx) /* has pcb extension? */ 210 je 1f 211 btsl %esi, _private_tss /* mark use of private tss */ 212 movl PCB_EXT(%edx), %edi /* new tss descriptor */ 213 jmp 2f 2141: 215 216 /* update common_tss.tss_esp0 pointer */ 217 movl %edx, %ebx /* pcb */ 218 addl $(UPAGES * PAGE_SIZE - 16), %ebx 219 movl %ebx, PCPU(COMMON_TSS) + TSS_ESP0 220 221 btrl %esi, _private_tss 222 jae 3f 223 PCPU_ADDR(COMMON_TSSD, %edi) 2242: 225 /* move correct tss descriptor into GDT slot, then reload tr */ 226 movl PCPU(TSS_GDT), %ebx /* entry in GDT */ 227 movl 0(%edi), %eax 228 movl %eax, 0(%ebx) 229 movl 4(%edi), %eax 230 movl %eax, 4(%ebx) 231 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */ 232 ltr %si 2333: 234 movl P_VMSPACE(%ecx), %ebx 235#ifdef SMP 236 movl PCPU(CPUID), %eax 237#else 238 xorl %eax, %eax 239#endif 240 btsl %eax, VM_PMAP+PM_ACTIVE(%ebx) 241 242 /* restore context */ 243 movl PCB_EBX(%edx),%ebx 244 movl PCB_ESP(%edx),%esp 245 movl PCB_EBP(%edx),%ebp 246 movl PCB_ESI(%edx),%esi 247 movl PCB_EDI(%edx),%edi 248 movl PCB_EIP(%edx),%eax 249 movl %eax,(%esp) 250 251#ifdef SMP 252#ifdef GRAB_LOPRIO /* hold LOPRIO for INTs */ 253#ifdef CHEAP_TPR 254 movl $0, _lapic+LA_TPR 255#else 256 andl $~APIC_TPR_PRIO, _lapic+LA_TPR 257#endif /** CHEAP_TPR */ 258#endif /** GRAB_LOPRIO */ 259 movl PCPU(CPUID),%eax 260 movb %al, P_ONCPU(%ecx) 261#endif /* SMP */ 262 movl %edx, PCPU(CURPCB) 263 movl %ecx, PCPU(CURPROC) /* into next process */ 264 265#ifdef SMP 266 /* XXX FIXME: we should be restoring the local APIC TPR */ 267#endif /* SMP */ 268 269#ifdef USER_LDT 270 cmpl $0, PCB_USERLDT(%edx) 271 jnz 1f 272 movl __default_ldt,%eax 273 cmpl PCPU(CURRENTLDT),%eax 274 je 2f 275 lldt __default_ldt 276 movl %eax,PCPU(CURRENTLDT) 277 jmp 2f 2781: pushl %edx 279 call _set_user_ldt 280 popl %edx 2812: 282#endif 283 284 /* This must be done after loading the user LDT. */ 285 .globl cpu_switch_load_gs 286cpu_switch_load_gs: 287 movl PCB_GS(%edx),%gs 288 289 /* test if debug regisers should be restored */ 290 movb PCB_FLAGS(%edx),%al 291 andb $PCB_DBREGS,%al 292 jz 1f /* no, skip over */ 293 movl PCB_DR6(%edx),%eax /* yes, do the restore */ 294 movl %eax,%dr6 295 movl PCB_DR3(%edx),%eax 296 movl %eax,%dr3 297 movl PCB_DR2(%edx),%eax 298 movl %eax,%dr2 299 movl PCB_DR1(%edx),%eax 300 movl %eax,%dr1 301 movl PCB_DR0(%edx),%eax 302 movl %eax,%dr0 303 movl PCB_DR7(%edx),%eax 304 movl %eax,%dr7 3051: 306 307 /* 308 * restore sched_lock recursion count and transfer ownership to 309 * new process 310 */ 311 movl PCB_SCHEDNEST(%edx),%eax 312 movl %eax,_sched_lock+MTX_RECURSECNT 313 314 movl PCPU(CURPROC),%eax 315 movl %eax,_sched_lock+MTX_LOCK 316 317 ret 318 319CROSSJUMPTARGET(sw1a) 320 321#ifdef INVARIANTS 322badsw2: 323 pushl $sw0_2 324 call _panic 325 326sw0_2: .asciz "cpu_switch: not SRUN" 327 328badsw3: 329 pushl $sw0_3 330 call _panic 331 332sw0_3: .asciz "cpu_switch: chooseproc returned NULL" 333#endif 334 335/* 336 * savectx(pcb) 337 * Update pcb, saving current processor state. 338 */ 339ENTRY(savectx) 340 /* fetch PCB */ 341 movl 4(%esp),%ecx 342 343 /* caller's return address - child won't execute this routine */ 344 movl (%esp),%eax 345 movl %eax,PCB_EIP(%ecx) 346 347 movl %cr3,%eax 348 movl %eax,PCB_CR3(%ecx) 349 350 movl %ebx,PCB_EBX(%ecx) 351 movl %esp,PCB_ESP(%ecx) 352 movl %ebp,PCB_EBP(%ecx) 353 movl %esi,PCB_ESI(%ecx) 354 movl %edi,PCB_EDI(%ecx) 355 movl %gs,PCB_GS(%ecx) 356 357#ifdef DEV_NPX 358 /* 359 * If npxproc == NULL, then the npx h/w state is irrelevant and the 360 * state had better already be in the pcb. This is true for forks 361 * but not for dumps (the old book-keeping with FP flags in the pcb 362 * always lost for dumps because the dump pcb has 0 flags). 363 * 364 * If npxproc != NULL, then we have to save the npx h/w state to 365 * npxproc's pcb and copy it to the requested pcb, or save to the 366 * requested pcb and reload. Copying is easier because we would 367 * have to handle h/w bugs for reloading. We used to lose the 368 * parent's npx state for forks by forgetting to reload. 369 */ 370 movl PCPU(NPXPROC),%eax 371 testl %eax,%eax 372 je 1f 373 374 pushl %ecx 375 movl P_ADDR(%eax),%eax 376 leal PCB_SAVEFPU(%eax),%eax 377 pushl %eax 378 pushl %eax 379 call _npxsave 380 addl $4,%esp 381 popl %eax 382 popl %ecx 383 384 pushl $PCB_SAVEFPU_SIZE 385 leal PCB_SAVEFPU(%ecx),%ecx 386 pushl %ecx 387 pushl %eax 388 call _bcopy 389 addl $12,%esp 390#endif /* DEV_NPX */ 391 3921: 393 ret 394