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