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