cpu_switch.S revision 1888
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 * $Id: swtch.s,v 1.8 1994/08/03 02:45:30 davidg Exp $ 37 */ 38 39#include "npx.h" /* for NNPX */ 40#include "assym.s" /* for preprocessor defines */ 41#include "errno.h" /* for error codes */ 42 43#include "machine/asmacros.h" /* for miscellaneous assembly macros */ 44#define LOCORE /* XXX inhibit C declarations */ 45#include "machine/spl.h" /* for SWI_AST_MASK ... */ 46 47 48/*****************************************************************************/ 49/* Scheduling */ 50/*****************************************************************************/ 51 52/* 53 * The following primitives manipulate the run queues. 54 * _whichqs tells which of the 32 queues _qs 55 * have processes in them. setrunqueue puts processes into queues, Remrq 56 * removes them from queues. The running process is on no queue, 57 * other processes are on a queue related to p->p_priority, divided by 4 58 * actually to shrink the 0-127 range of priorities into the 32 available 59 * queues. 60 */ 61 .data 62 .globl _curpcb, _whichqs 63_curpcb: .long 0 /* pointer to curproc's PCB area */ 64_whichqs: .long 0 /* which run queues have data */ 65 66 .globl _qs,_cnt,_panic 67 .comm _noproc,4 68 .comm _runrun,4 69 70 .globl _want_resched 71_want_resched: .long 0 /* we need to re-run the scheduler */ 72 73 .text 74/* 75 * setrunqueue(p) 76 * 77 * Call should be made at spl6(), and p->p_stat should be SRUN 78 */ 79ENTRY(setrunqueue) 80 movl 4(%esp),%eax 81 cmpl $0,P_RLINK(%eax) /* should not be on q already */ 82 je set1 83 pushl $set2 84 call _panic 85set1: 86 movzbl P_PRI(%eax),%edx 87 shrl $2,%edx 88 btsl %edx,_whichqs /* set q full bit */ 89 shll $3,%edx 90 addl $_qs,%edx /* locate q hdr */ 91 movl %edx,P_LINK(%eax) /* link process on tail of q */ 92 movl P_RLINK(%edx),%ecx 93 movl %ecx,P_RLINK(%eax) 94 movl %eax,P_RLINK(%edx) 95 movl %eax,P_LINK(%ecx) 96 ret 97 98set2: .asciz "setrunqueue" 99 100/* 101 * Remrq(p) 102 * 103 * Call should be made at spl6(). 104 */ 105ENTRY(remrq) 106 movl 4(%esp),%eax 107 movzbl P_PRI(%eax),%edx 108 shrl $2,%edx 109 btrl %edx,_whichqs /* clear full bit, panic if clear already */ 110 jb rem1 111 pushl $rem3 112 call _panic 113rem1: 114 pushl %edx 115 movl P_LINK(%eax),%ecx /* unlink process */ 116 movl P_RLINK(%eax),%edx 117 movl %edx,P_RLINK(%ecx) 118 movl P_RLINK(%eax),%ecx 119 movl P_LINK(%eax),%edx 120 movl %edx,P_LINK(%ecx) 121 popl %edx 122 movl $_qs,%ecx 123 shll $3,%edx 124 addl %edx,%ecx 125 cmpl P_LINK(%ecx),%ecx /* q still has something? */ 126 je rem2 127 shrl $3,%edx /* yes, set bit as still full */ 128 btsl %edx,_whichqs 129rem2: 130 movl $0,P_RLINK(%eax) /* zap reverse link to indicate off list */ 131 ret 132 133rem3: .asciz "remrq" 134sw0: .asciz "cpu_switch" 135 136/* 137 * When no processes are on the runq, cpu_switch() branches to _idle 138 * to wait for something to come ready. 139 */ 140 ALIGN_TEXT 141_idle: 142 MCOUNT 143 movl _IdlePTD,%ecx 144 movl %ecx,%cr3 145 movl $tmpstk,%esp 146 sti 147 148 /* 149 * XXX callers of cpu_switch() do a bogus splclock(). Locking should 150 * be left to cpu_switch(). 151 */ 152 movl $SWI_AST_MASK,_cpl 153 testl $~SWI_AST_MASK,_ipending 154 je idle_loop 155 call _splz 156 157 ALIGN_TEXT 158idle_loop: 159 cli 160 cmpl $0,_whichqs 161 jne sw1a 162 sti 163 hlt /* wait for interrupt */ 164 jmp idle_loop 165 166badsw: 167 pushl $sw0 168 call _panic 169 /*NOTREACHED*/ 170 171/* 172 * cpu_switch() 173 */ 174ENTRY(cpu_switch) 175 incl _cnt+V_SWTCH 176 177 /* switch to new process. first, save context as needed */ 178 179 movl _curproc,%ecx 180 181 /* if no process to save, don't bother */ 182 testl %ecx,%ecx 183 je sw1 184 185 movl P_ADDR(%ecx),%ecx 186 187 movl (%esp),%eax /* Hardware registers */ 188 movl %eax,PCB_EIP(%ecx) 189 movl %ebx,PCB_EBX(%ecx) 190 movl %esp,PCB_ESP(%ecx) 191 movl %ebp,PCB_EBP(%ecx) 192 movl %esi,PCB_ESI(%ecx) 193 movl %edi,PCB_EDI(%ecx) 194 195#if NNPX > 0 196 /* have we used fp, and need a save? */ 197 mov _curproc,%eax 198 cmp %eax,_npxproc 199 jne 1f 200 pushl %ecx /* h/w bugs make saving complicated */ 201 leal PCB_SAVEFPU(%ecx),%eax 202 pushl %eax 203 call _npxsave /* do it in a big C function */ 204 popl %eax 205 popl %ecx 2061: 207#endif /* NNPX > 0 */ 208 209 movl $0,_curproc /* out of process */ 210 211# movw _cpl,%ax 212# movw %ax,PCB_IML(%ecx) /* save ipl */ 213 214 /* save is done, now choose a new process or idle */ 215sw1: 216 cli 217sw1a: 218 movl _whichqs,%edi 2192: 220 /* XXX - bsf is sloow */ 221 bsfl %edi,%eax /* find a full q */ 222 je _idle /* if none, idle */ 223 224 /* XX update whichqs? */ 225 btrl %eax,%edi /* clear q full status */ 226 jnb 2b /* if it was clear, look for another */ 227 movl %eax,%ebx /* save which one we are using */ 228 229 shll $3,%eax 230 addl $_qs,%eax /* select q */ 231 movl %eax,%esi 232 233#ifdef DIAGNOSTIC 234 cmpl P_LINK(%eax),%eax /* linked to self? (e.g. not on list) */ 235 je badsw /* not possible */ 236#endif 237 238 movl P_LINK(%eax),%ecx /* unlink from front of process q */ 239 movl P_LINK(%ecx),%edx 240 movl %edx,P_LINK(%eax) 241 movl P_RLINK(%ecx),%eax 242 movl %eax,P_RLINK(%edx) 243 244 cmpl P_LINK(%ecx),%esi /* q empty */ 245 je 3f 246 btsl %ebx,%edi /* nope, set to indicate full */ 2473: 248 movl %edi,_whichqs /* update q status */ 249 250 movl $0,%eax 251 movl %eax,_want_resched 252 253#ifdef DIAGNOSTIC 254 cmpl %eax,P_WCHAN(%ecx) 255 jne badsw 256 cmpb $SRUN,P_STAT(%ecx) 257 jne badsw 258#endif 259 260 movl %eax,P_RLINK(%ecx) /* isolate process to run */ 261 movl P_ADDR(%ecx),%edx 262 movl PCB_CR3(%edx),%ebx 263 264 /* switch address space */ 265 movl %ebx,%cr3 266 267 /* restore context */ 268 movl PCB_EBX(%edx),%ebx 269 movl PCB_ESP(%edx),%esp 270 movl PCB_EBP(%edx),%ebp 271 movl PCB_ESI(%edx),%esi 272 movl PCB_EDI(%edx),%edi 273 movl PCB_EIP(%edx),%eax 274 movl %eax,(%esp) 275 276 movl %ecx,_curproc /* into next process */ 277 movl %edx,_curpcb 278 279#ifdef USER_LDT 280 cmpl $0, PCB_USERLDT(%edx) 281 jnz 1f 282 movl __default_ldt,%eax 283 cmpl _currentldt,%eax 284 je 2f 285 lldt __default_ldt 286 movl %eax,_currentldt 287 jmp 2f 2881: pushl %edx 289 call _set_user_ldt 290 popl %edx 2912: 292#endif 293 294 pushl %edx /* save p to return */ 295/* 296 * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1? 297 * I think restoring the cpl is unnecessary, but we must turn off the cli 298 * now that spl*() don't do it as a side affect. 299 */ 300 pushl PCB_IML(%edx) 301 sti 302#if 0 303 call _splx 304#endif 305 addl $4,%esp 306/* 307 * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the 308 * same way. Better return a value. 309 */ 310 popl %eax /* return(p); */ 311 ret 312 313ENTRY(mvesp) 314 movl %esp,%eax 315 ret 316/* 317 * struct proc *swtch_to_inactive(struct proc *p); 318 * 319 * At exit of a process, move off the address space of the 320 * process and onto a "safe" one. Then, on a temporary stack 321 * return and run code that disposes of the old state. 322 * Since this code requires a parameter from the "old" stack, 323 * pass it back as a return value. 324 */ 325ENTRY(swtch_to_inactive) 326 popl %edx /* old pc */ 327 popl %eax /* arg, our return value */ 328 movl _IdlePTD,%ecx 329 movl %ecx,%cr3 /* good bye address space */ 330 #write buffer? 331 movl $tmpstk-4,%esp /* temporary stack, compensated for call */ 332 MEXITCOUNT 333 jmp %edx /* return, execute remainder of cleanup */ 334 335/* 336 * savectx(pcb, altreturn) 337 * Update pcb, saving current processor state and arranging 338 * for alternate return ala longjmp in cpu_switch if altreturn is true. 339 */ 340ENTRY(savectx) 341 movl 4(%esp),%ecx 342 movw _cpl,%ax 343 movw %ax,PCB_IML(%ecx) 344 movl (%esp),%eax 345 movl %eax,PCB_EIP(%ecx) 346 movl %ebx,PCB_EBX(%ecx) 347 movl %esp,PCB_ESP(%ecx) 348 movl %ebp,PCB_EBP(%ecx) 349 movl %esi,PCB_ESI(%ecx) 350 movl %edi,PCB_EDI(%ecx) 351 352#if NNPX > 0 353 /* 354 * If npxproc == NULL, then the npx h/w state is irrelevant and the 355 * state had better already be in the pcb. This is true for forks 356 * but not for dumps (the old book-keeping with FP flags in the pcb 357 * always lost for dumps because the dump pcb has 0 flags). 358 * 359 * If npxproc != NULL, then we have to save the npx h/w state to 360 * npxproc's pcb and copy it to the requested pcb, or save to the 361 * requested pcb and reload. Copying is easier because we would 362 * have to handle h/w bugs for reloading. We used to lose the 363 * parent's npx state for forks by forgetting to reload. 364 */ 365 mov _npxproc,%eax 366 testl %eax,%eax 367 je 1f 368 369 pushl %ecx 370 movl P_ADDR(%eax),%eax 371 leal PCB_SAVEFPU(%eax),%eax 372 pushl %eax 373 pushl %eax 374 call _npxsave 375 popl %eax 376 popl %eax 377 popl %ecx 378 379 pushl %ecx 380 pushl $108+8*2 /* XXX h/w state size + padding */ 381 leal PCB_SAVEFPU(%ecx),%ecx 382 pushl %ecx 383 pushl %eax 384 call _bcopy 385 addl $12,%esp 386 popl %ecx 3871: 388#endif /* NNPX > 0 */ 389 390 movl _CMAP2,%edx /* save temporary map PTE */ 391 movl %edx,PCB_CMAP2(%ecx) /* in our context */ 392 393 cmpl $0,8(%esp) 394 je 1f 395 movl %esp,%edx /* relocate current sp relative to pcb */ 396 subl $_kstack,%edx /* (sp is relative to kstack): */ 397 addl %edx,%ecx /* pcb += sp - kstack; */ 398 movl %eax,(%ecx) /* write return pc at (relocated) sp@ */ 399 400/* this mess deals with replicating register state gcc hides */ 401 movl 12(%esp),%eax 402 movl %eax,12(%ecx) 403 movl 16(%esp),%eax 404 movl %eax,16(%ecx) 405 movl 20(%esp),%eax 406 movl %eax,20(%ecx) 407 movl 24(%esp),%eax 408 movl %eax,24(%ecx) 4091: 410 xorl %eax,%eax /* return 0 */ 411 ret 412 413/* 414 * addupc(int pc, struct uprof *up, int ticks): 415 * update profiling information for the user process. 416 */ 417ENTRY(addupc) 418 pushl %ebp 419 movl %esp,%ebp 420 movl 12(%ebp),%edx /* up */ 421 movl 8(%ebp),%eax /* pc */ 422 423 subl PR_OFF(%edx),%eax /* pc -= up->pr_off */ 424 jb L1 /* if (pc was < off) return */ 425 426 shrl $1,%eax /* praddr = pc >> 1 */ 427 imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */ 428 shrl $15,%eax /* praddr = praddr << 15 */ 429 andl $-2,%eax /* praddr &= ~1 */ 430 431 cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */ 432 ja L1 433 434/* addl %eax,%eax /* praddr -> word offset */ 435 addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */ 436 movl 16(%ebp),%ecx /* ticks */ 437 438 movl _curpcb,%edx 439 movl $proffault,PCB_ONFAULT(%edx) 440 addl %ecx,(%eax) /* storage location += ticks */ 441 movl $0,PCB_ONFAULT(%edx) 442L1: 443 leave 444 ret 445 446 ALIGN_TEXT 447proffault: 448 /* if we get a fault, then kill profiling all together */ 449 movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */ 450 movl 12(%ebp),%ecx 451 movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */ 452 leave 453 ret 454