swtch.s revision 128019
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 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: head/sys/i386/i386/swtch.s 128019 2004-04-07 20:46:16Z imp $ 33 */ 34 35#include "opt_npx.h" 36 37#include <machine/asmacros.h> 38 39#include "assym.s" 40 41/*****************************************************************************/ 42/* Scheduling */ 43/*****************************************************************************/ 44 45 .text 46 47/* 48 * cpu_throw() 49 * 50 * This is the second half of cpu_swtch(). It is used when the current 51 * thread is either a dummy or slated to die, and we no longer care 52 * about its state. This is only a slight optimization and is probably 53 * not worth it anymore. Note that we need to clear the pm_active bits so 54 * we do need the old proc if it still exists. 55 * 0(%esp) = ret 56 * 4(%esp) = oldtd 57 * 8(%esp) = newtd 58 */ 59ENTRY(cpu_throw) 60 movl PCPU(CPUID), %esi 61 movl 4(%esp),%ecx /* Old thread */ 62 testl %ecx,%ecx /* no thread? */ 63 jz 1f 64 /* release bit from old pm_active */ 65 movl PCPU(CURPMAP), %ebx 66#ifdef SMP 67 lock 68#endif 69 btrl %esi, PM_ACTIVE(%ebx) /* clear old */ 701: 71 movl 8(%esp),%ecx /* New thread */ 72 movl TD_PCB(%ecx),%edx 73 movl PCB_CR3(%edx),%eax 74 movl %eax,%cr3 /* new address space */ 75 /* set bit in new pm_active */ 76 movl TD_PROC(%ecx),%eax 77 movl P_VMSPACE(%eax), %ebx 78 addl $VM_PMAP, %ebx 79 movl %ebx, PCPU(CURPMAP) 80#ifdef SMP 81 lock 82#endif 83 btsl %esi, PM_ACTIVE(%ebx) /* set new */ 84 jmp sw1 85 86/* 87 * cpu_switch(old, new) 88 * 89 * Save the current thread state, then select the next thread to run 90 * and load its state. 91 * 0(%esp) = ret 92 * 4(%esp) = oldtd 93 * 8(%esp) = newtd 94 */ 95ENTRY(cpu_switch) 96 97 /* Switch to new thread. First, save context. */ 98 movl 4(%esp),%ecx 99 100#ifdef INVARIANTS 101 testl %ecx,%ecx /* no thread? */ 102 jz badsw2 /* no, panic */ 103#endif 104 105 movl TD_PCB(%ecx),%edx 106 107 movl (%esp),%eax /* Hardware registers */ 108 movl %eax,PCB_EIP(%edx) 109 movl %ebx,PCB_EBX(%edx) 110 movl %esp,PCB_ESP(%edx) 111 movl %ebp,PCB_EBP(%edx) 112 movl %esi,PCB_ESI(%edx) 113 movl %edi,PCB_EDI(%edx) 114 movl %gs,PCB_GS(%edx) 115 pushfl /* PSL */ 116 popl PCB_PSL(%edx) 117 /* Check to see if we need to call a switchout function. */ 118 movl PCB_SWITCHOUT(%edx),%eax 119 cmpl $0, %eax 120 je 1f 121 call *%eax 1221: 123 /* Test if debug registers should be saved. */ 124 testl $PCB_DBREGS,PCB_FLAGS(%edx) 125 jz 1f /* no, skip over */ 126 movl %dr7,%eax /* yes, do the save */ 127 movl %eax,PCB_DR7(%edx) 128 andl $0x0000fc00, %eax /* disable all watchpoints */ 129 movl %eax,%dr7 130 movl %dr6,%eax 131 movl %eax,PCB_DR6(%edx) 132 movl %dr3,%eax 133 movl %eax,PCB_DR3(%edx) 134 movl %dr2,%eax 135 movl %eax,PCB_DR2(%edx) 136 movl %dr1,%eax 137 movl %eax,PCB_DR1(%edx) 138 movl %dr0,%eax 139 movl %eax,PCB_DR0(%edx) 1401: 141 142#ifdef DEV_NPX 143 /* have we used fp, and need a save? */ 144 cmpl %ecx,PCPU(FPCURTHREAD) 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 152 153 /* Save is done. Now fire up new thread. Leave old vmspace. */ 154 movl %ecx,%edi 155 movl 8(%esp),%ecx /* New thread */ 156#ifdef INVARIANTS 157 testl %ecx,%ecx /* no thread? */ 158 jz badsw3 /* no, panic */ 159#endif 160 movl TD_PCB(%ecx),%edx 161 movl PCPU(CPUID), %esi 162 163 /* switch address space */ 164 movl PCB_CR3(%edx),%eax 165#ifdef PAE 166 cmpl %eax,IdlePDPT /* Kernel address space? */ 167#else 168 cmpl %eax,IdlePTD /* Kernel address space? */ 169#endif 170 je sw1 171 movl %cr3,%ebx /* The same address space? */ 172 cmpl %ebx,%eax 173 je sw1 174 movl %eax,%cr3 /* new address space */ 175 176 /* Release bit from old pmap->pm_active */ 177 movl PCPU(CURPMAP), %ebx 178#ifdef SMP 179 lock 180#endif 181 btrl %esi, PM_ACTIVE(%ebx) /* clear old */ 182 183 /* Set bit in new pmap->pm_active */ 184 movl TD_PROC(%ecx),%eax /* newproc */ 185 movl P_VMSPACE(%eax), %ebx 186 addl $VM_PMAP, %ebx 187 movl %ebx, PCPU(CURPMAP) 188#ifdef SMP 189 lock 190#endif 191 btsl %esi, PM_ACTIVE(%ebx) /* set new */ 192 193sw1: 194 /* 195 * At this point, we've switched address spaces and are ready 196 * to load up the rest of the next context. 197 */ 198 cmpl $0, PCB_EXT(%edx) /* has pcb extension? */ 199 je 1f /* If not, use the default */ 200 btsl %esi, private_tss /* mark use of private tss */ 201 movl PCB_EXT(%edx), %edi /* new tss descriptor */ 202 jmp 2f /* Load it up */ 203 2041: /* 205 * Use the common default TSS instead of our own. 206 * Set our stack pointer into the TSS, it's set to just 207 * below the PCB. In C, common_tss.tss_esp0 = &pcb - 16; 208 */ 209 leal -16(%edx), %ebx /* leave space for vm86 */ 210 movl %ebx, PCPU(COMMON_TSS) + TSS_ESP0 211 212 /* 213 * Test this CPU's bit in the bitmap to see if this 214 * CPU was using a private TSS. 215 */ 216 btrl %esi, private_tss /* Already using the common? */ 217 jae 3f /* if so, skip reloading */ 218 PCPU_ADDR(COMMON_TSSD, %edi) 2192: 220 /* Move correct tss descriptor into GDT slot, then reload tr. */ 221 movl PCPU(TSS_GDT), %ebx /* entry in GDT */ 222 movl 0(%edi), %eax 223 movl %eax, 0(%ebx) 224 movl 4(%edi), %eax 225 movl %eax, 4(%ebx) 226 movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */ 227 ltr %si 2283: 229 230 /* Restore context. */ 231 movl PCB_EBX(%edx),%ebx 232 movl PCB_ESP(%edx),%esp 233 movl PCB_EBP(%edx),%ebp 234 movl PCB_ESI(%edx),%esi 235 movl PCB_EDI(%edx),%edi 236 movl PCB_EIP(%edx),%eax 237 movl %eax,(%esp) 238 pushl PCB_PSL(%edx) 239 popfl 240 241 movl %edx, PCPU(CURPCB) 242 movl %ecx, PCPU(CURTHREAD) /* into next thread */ 243 244 /* 245 * Determine the LDT to use and load it if is the default one and 246 * that is not the current one. 247 */ 248 movl TD_PROC(%ecx),%eax 249 cmpl $0,P_MD+MD_LDT(%eax) 250 jnz 1f 251 movl _default_ldt,%eax 252 cmpl PCPU(CURRENTLDT),%eax 253 je 2f 254 lldt _default_ldt 255 movl %eax,PCPU(CURRENTLDT) 256 jmp 2f 2571: 258 /* Load the LDT when it is not the default one. */ 259 pushl %edx /* Preserve pointer to pcb. */ 260 addl $P_MD,%eax /* Pointer to mdproc is arg. */ 261 pushl %eax 262 call set_user_ldt 263 addl $4,%esp 264 popl %edx 2652: 266 267 /* This must be done after loading the user LDT. */ 268 .globl cpu_switch_load_gs 269cpu_switch_load_gs: 270 movl PCB_GS(%edx),%gs 271 272 /* Test if debug registers should be restored. */ 273 testl $PCB_DBREGS,PCB_FLAGS(%edx) 274 jz 1f 275 276 /* 277 * Restore debug registers. The special code for dr7 is to 278 * preserve the current values of its reserved bits. 279 */ 280 movl PCB_DR6(%edx),%eax 281 movl %eax,%dr6 282 movl PCB_DR3(%edx),%eax 283 movl %eax,%dr3 284 movl PCB_DR2(%edx),%eax 285 movl %eax,%dr2 286 movl PCB_DR1(%edx),%eax 287 movl %eax,%dr1 288 movl PCB_DR0(%edx),%eax 289 movl %eax,%dr0 290 movl %dr7,%eax 291 andl $0x0000fc00,%eax 292 movl PCB_DR7(%edx),%ecx 293 andl $~0x0000fc00,%ecx 294 orl %ecx,%eax 295 movl %eax,%dr7 2961: 297 ret 298 299#ifdef INVARIANTS 300badsw1: 301 pushal 302 pushl $0 303 pushl $0 304 pushl $sw0_1 305 call __panic 306sw0_1: .asciz "cpu_throw: no newthread supplied" 307 308badsw2: 309 pushal 310 pushl $0 311 pushl $0 312 pushl $sw0_2 313 call __panic 314sw0_2: .asciz "cpu_switch: no curthread supplied" 315 316badsw3: 317 pushal 318 pushl $0 319 pushl $0 320 pushl $sw0_3 321 call __panic 322sw0_3: .asciz "cpu_switch: no newthread supplied" 323#endif 324 325/* 326 * savectx(pcb) 327 * Update pcb, saving current processor state. 328 */ 329ENTRY(savectx) 330 /* Fetch PCB. */ 331 movl 4(%esp),%ecx 332 333 /* Save caller's return address. Child won't execute this routine. */ 334 movl (%esp),%eax 335 movl %eax,PCB_EIP(%ecx) 336 337 movl %cr3,%eax 338 movl %eax,PCB_CR3(%ecx) 339 340 movl %ebx,PCB_EBX(%ecx) 341 movl %esp,PCB_ESP(%ecx) 342 movl %ebp,PCB_EBP(%ecx) 343 movl %esi,PCB_ESI(%ecx) 344 movl %edi,PCB_EDI(%ecx) 345 movl %gs,PCB_GS(%ecx) 346 pushfl 347 popl PCB_PSL(%ecx) 348 349#ifdef DEV_NPX 350 /* 351 * If fpcurthread == NULL, then the npx h/w state is irrelevant and the 352 * state had better already be in the pcb. This is true for forks 353 * but not for dumps (the old book-keeping with FP flags in the pcb 354 * always lost for dumps because the dump pcb has 0 flags). 355 * 356 * If fpcurthread != NULL, then we have to save the npx h/w state to 357 * fpcurthread's pcb and copy it to the requested pcb, or save to the 358 * requested pcb and reload. Copying is easier because we would 359 * have to handle h/w bugs for reloading. We used to lose the 360 * parent's npx state for forks by forgetting to reload. 361 */ 362 pushfl 363 cli 364 movl PCPU(FPCURTHREAD),%eax 365 testl %eax,%eax 366 je 1f 367 368 pushl %ecx 369 movl TD_PCB(%eax),%eax 370 leal PCB_SAVEFPU(%eax),%eax 371 pushl %eax 372 pushl %eax 373 call npxsave 374 addl $4,%esp 375 popl %eax 376 popl %ecx 377 378 pushl $PCB_SAVEFPU_SIZE 379 leal PCB_SAVEFPU(%ecx),%ecx 380 pushl %ecx 381 pushl %eax 382 call bcopy 383 addl $12,%esp 3841: 385 popfl 386#endif /* DEV_NPX */ 387 388 ret 389