1/* $NetBSD: locore.s,v 1.81 2001/08/04 04:06:29 chs Exp $ */ 2 3/* 4 * Copyright (c) 1994, 1995 Gordon W. Ross 5 * Copyright (c) 1993 Adam Glass 6 * Copyright (c) 1988 University of Utah. 7 * Copyright (c) 1980, 1990, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * the Systems Programming Group of the University of Utah Computer 12 * Science Department. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * from: Utah $Hdr: locore.s 1.66 92/12/22$ 43 * @(#)locore.s 8.6 (Berkeley) 5/27/94 44 */ 45 46#include "opt_compat_netbsd.h" 47#include "opt_compat_svr4.h" 48#include "opt_compat_sunos.h" 49#include "opt_kgdb.h" 50#include "opt_lockdebug.h" 51 52#include "assym.h" 53#include <machine/asm.h> 54#include <machine/trap.h> 55 56| Remember this is a fun project! 57 58| This is for kvm_mkdb, and should be the address of the beginning 59| of the kernel text segment (not necessarily the same as kernbase). 60 .text 61GLOBAL(kernel_text) 62 63| This is the entry point, as well as the end of the temporary stack 64| used during process switch (one 8K page ending at start) 65ASGLOBAL(tmpstk) 66ASGLOBAL(start) 67 68| First we need to set it up so we can access the sun MMU, and be otherwise 69| undisturbed. Until otherwise noted, all code must be position independent 70| as the boot loader put us low in memory, but we are linked high. 71 movw #PSL_HIGHIPL,%sr | no interrupts 72 moveq #FC_CONTROL,%d0 | make movs access "control" 73 movc %d0,%sfc | space where the sun3 designers 74 movc %d0,%dfc | put all the "useful" stuff 75 76| Set context zero and stay there until pmap_bootstrap. 77 moveq #0,%d0 78 movsb %d0,CONTEXT_REG 79 80| In order to "move" the kernel to high memory, we are going to copy the 81| first 4 Mb of pmegs such that we will be mapped at the linked address. 82| This is all done by copying in the segment map (top-level MMU table). 83| We will unscramble which PMEGs we actually need later. 84 85 movl #(SEGMAP_BASE+0),%a0 | src 86 movl #(SEGMAP_BASE+KERNBASE),%a1 | dst 87 movl #(0x400000/NBSG),%d0 | count 88 89L_per_pmeg: 90 movsb %a0@,%d1 | copy segmap entry 91 movsb %d1,%a1@ 92 addl #NBSG,%a0 | increment pointers 93 addl #NBSG,%a1 94 subql #1,%d0 | decrement count 95 bgt L_per_pmeg 96 97| Kernel is now double mapped at zero and KERNBASE. 98| Force a long jump to the relocated code (high VA). 99 movl #IC_CLEAR,%d0 | Flush the I-cache 100 movc %d0,%cacr 101 jmp L_high_code:l | long jump 102 103L_high_code: 104| We are now running in the correctly relocated kernel, so 105| we are no longer restricted to position-independent code. 106 107| Do bootstrap stuff needed before main() gets called. 108| Make sure the initial frame pointer is zero so that 109| the backtrace algorithm used by KGDB terminates nicely. 110 lea _ASM_LABEL(tmpstk),%sp 111 movl #0,%a6 112 jsr _C_LABEL(_bootstrap) | See locore2.c 113 114| Now that _bootstrap() is done using the PROM functions, 115| we can safely set the %sfc/dfc to something != FC_CONTROL 116 moveq #FC_USERD,%d0 | make movs access "user data" 117 movc %d0,%sfc | space for copyin/copyout 118 movc %d0,%dfc 119 120| Setup process zero user/kernel stacks. 121 movl _C_LABEL(proc0paddr),%a1 | get proc0 pcb addr 122 lea %a1@(USPACE-4),%sp | set SSP to last word 123 movl #USRSTACK-4,%a2 124 movl %a2,%usp | init user SP 125 126| Note curpcb was already set in _bootstrap(). 127| Will do fpu initialization during autoconfig (see fpu.c) 128| The interrupt vector table and stack are now ready. 129| Interrupts will be enabled later, AFTER autoconfiguration 130| is finished, to avoid spurrious interrupts. 131 132/* 133 * Final preparation for calling main. 134 * 135 * Create a fake exception frame that returns to user mode, 136 * and save its address in p->p_md.md_regs for cpu_fork(). 137 * The new frames for process 1 and 2 will be adjusted by 138 * cpu_set_kpc() to arrange for a call to a kernel function 139 * before the new process does its rte out to user mode. 140 */ 141 clrw %sp@- | tf_format,tf_vector 142 clrl %sp@- | tf_pc (filled in later) 143 movw #PSL_USER,%sp@- | tf_sr for user mode 144 clrl %sp@- | tf_stackadj 145 lea %sp@(-64),%sp | tf_regs[16] 146 movl %sp,%a1 | %a1=trapframe 147 lea _C_LABEL(proc0),%a0 | proc0.p_md.md_regs = 148 movl %a1,%a0@(P_MDREGS) | trapframe 149 movl %a2,%a1@(FR_SP) | a2 == usp (from above) 150 pea %a1@ | push &trapframe 151 jbsr _C_LABEL(main) | main(&trapframe) 152 addql #4,%sp | help DDB backtrace 153 trap #15 | should not get here 154 155| This is used by cpu_fork() to return to user mode. 156| It is called with SP pointing to a struct trapframe. 157GLOBAL(proc_do_uret) 158 movl %sp@(FR_SP),%a0 | grab and load 159 movl %a0,%usp | user SP 160 moveml %sp@+,#0x7FFF | load most registers (all but SSP) 161 addql #8,%sp | pop SSP and stack adjust count 162 rte 163 164/* 165 * proc_trampoline: 166 * This is used by cpu_set_kpc() to "push" a function call onto the 167 * kernel stack of some process, very much like a signal delivery. 168 * When we get here, the stack has: 169 * 170 * SP+8: switchframe from before cpu_set_kpc 171 * SP+4: void *arg; 172 * SP: u_long func; 173 * 174 * On entry, the switchframe pushed by cpu_set_kpc has already been 175 * popped off the stack, so all this needs to do is pop the function 176 * pointer into a register, call it, then pop the arg, and finally 177 * return using the switchframe that remains on the stack. 178 */ 179GLOBAL(proc_trampoline) 180 movl %sp@+,%a0 | function pointer 181 jbsr %a0@ | (*func)(arg) 182 addql #4,%sp | toss the arg 183 rts | as cpu_switch would do 184 185| That is all the assembly startup code we need on the sun3! 186| The rest of this is like the hp300/locore.s where possible. 187 188/* 189 * Trap/interrupt vector routines 190 */ 191#include <m68k/m68k/trap_subr.s> 192 193GLOBAL(buserr) 194 tstl _C_LABEL(nofault) | device probe? 195 jeq _C_LABEL(addrerr) | no, handle as usual 196 movl _C_LABEL(nofault),%sp@- | yes, 197 jbsr _C_LABEL(longjmp) | longjmp(nofault) 198GLOBAL(addrerr) 199 clrl %sp@- | stack adjust count 200 moveml #0xFFFF,%sp@- | save user registers 201 movl %usp,%a0 | save the user SP 202 movl %a0,%sp@(FR_SP) | in the savearea 203 lea %sp@(FR_HW),%a1 | grab base of HW berr frame 204 moveq #0,%d0 205 movw %a1@(10),%d0 | grab SSW for fault processing 206 btst #12,%d0 | RB set? 207 jeq LbeX0 | no, test RC 208 bset #14,%d0 | yes, must set FB 209 movw %d0,%a1@(10) | for hardware too 210LbeX0: 211 btst #13,%d0 | RC set? 212 jeq LbeX1 | no, skip 213 bset #15,%d0 | yes, must set FC 214 movw %d0,%a1@(10) | for hardware too 215LbeX1: 216 btst #8,%d0 | data fault? 217 jeq Lbe0 | no, check for hard cases 218 movl %a1@(16),%d1 | fault address is as given in frame 219 jra Lbe10 | thats it 220Lbe0: 221 btst #4,%a1@(6) | long (type B) stack frame? 222 jne Lbe4 | yes, go handle 223 movl %a1@(2),%d1 | no, can use save PC 224 btst #14,%d0 | FB set? 225 jeq Lbe3 | no, try FC 226 addql #4,%d1 | yes, adjust address 227 jra Lbe10 | done 228Lbe3: 229 btst #15,%d0 | FC set? 230 jeq Lbe10 | no, done 231 addql #2,%d1 | yes, adjust address 232 jra Lbe10 | done 233Lbe4: 234 movl %a1@(36),%d1 | long format, use stage B address 235 btst #15,%d0 | FC set? 236 jeq Lbe10 | no, all done 237 subql #2,%d1 | yes, adjust address 238Lbe10: 239 movl %d1,%sp@- | push fault VA 240 movl %d0,%sp@- | and padded SSW 241 movw %a1@(6),%d0 | get frame format/vector offset 242 andw #0x0FFF,%d0 | clear out frame format 243 cmpw #12,%d0 | address error vector? 244 jeq Lisaerr | yes, go to it 245 246/* 247 * the sun3 specific code 248 * 249 * our mission: figure out whether what we are looking at is 250 * bus error in the UNIX sense, or 251 * a memory error i.e a page fault 252 * 253 * [this code replaces similarly mmu specific code in the hp300 code] 254 */ 255sun3_mmu_specific: 256 clrl %d0 | make sure top bits are cleard too 257 movl %d1,%sp@- | save %d1 258 movc %sfc,%d1 | save %sfc to %d1 259 moveq #FC_CONTROL,%d0 | %sfc = FC_CONTROL 260 movc %d0,%sfc 261 movsb BUSERR_REG,%d0 | get value of bus error register 262 movc %d1,%sfc | restore %sfc 263 movl %sp@+,%d1 | restore %d1 264 andb #BUSERR_MMU,%d0 | is this an MMU fault? 265 jeq Lisberr | non-MMU bus error 266/* End of sun3 specific code. */ 267 268Lismerr: 269 movl #T_MMUFLT,%sp@- | show that we are an MMU fault 270 jra _ASM_LABEL(faultstkadj) | and deal with it 271Lisaerr: 272 movl #T_ADDRERR,%sp@- | mark address error 273 jra _ASM_LABEL(faultstkadj) | and deal with it 274Lisberr: 275 movl #T_BUSERR,%sp@- | mark bus error 276 jra _ASM_LABEL(faultstkadj) | and deal with it 277 278/* 279 * FP exceptions. 280 */ 281GLOBAL(fpfline) 282 clrl %sp@- | stack adjust count 283 moveml #0xFFFF,%sp@- | save registers 284 moveq #T_FPEMULI,%d0 | denote as FP emulation trap 285 jra _ASM_LABEL(fault) | do it 286 287GLOBAL(fpunsupp) 288 clrl %sp@- | stack adjust count 289 moveml #0xFFFF,%sp@- | save registers 290 moveq #T_FPEMULD,%d0 | denote as FP emulation trap 291 jra _ASM_LABEL(fault) | do it 292 293/* 294 * Handles all other FP coprocessor exceptions. 295 * Note that since some FP exceptions generate mid-instruction frames 296 * and may cause signal delivery, we need to test for stack adjustment 297 * after the trap call. 298 */ 299GLOBAL(fpfault) 300 clrl %sp@- | stack adjust count 301 moveml #0xFFFF,%sp@- | save user registers 302 movl %usp,%a0 | and save 303 movl %a0,%sp@(FR_SP) | the user stack pointer 304 clrl %sp@- | no VA arg 305 movl _C_LABEL(curpcb),%a0 | current pcb 306 lea %a0@(PCB_FPCTX),%a0 | address of FP savearea 307 fsave %a0@ | save state 308 tstb %a0@ | null state frame? 309 jeq Lfptnull | yes, safe 310 clrw %d0 | no, need to tweak BIU 311 movb %a0@(1),%d0 | get frame size 312 bset #3,%a0@(0,%d0:w) | set exc_pend bit of BIU 313Lfptnull: 314 fmovem %fpsr,%sp@- | push fpsr as code argument 315 frestore %a0@ | restore state 316 movl #T_FPERR,%sp@- | push type arg 317 jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup 318 319/* 320 * Other exceptions only cause four and six word stack frame and require 321 * no post-trap stack adjustment. 322 */ 323GLOBAL(badtrap) 324 clrl %sp@- | stack adjust count 325 moveml #0xFFFF,%sp@- | save std frame regs 326 jbsr _C_LABEL(straytrap) | report 327 moveml %sp@+,#0xFFFF | restore regs 328 addql #4,%sp | stack adjust count 329 jra _ASM_LABEL(rei) | all done 330 331/* 332 * Trap 0 is for system calls 333 */ 334GLOBAL(trap0) 335 clrl %sp@- | stack adjust count 336 moveml #0xFFFF,%sp@- | save user registers 337 movl %usp,%a0 | save the user SP 338 movl %a0,%sp@(FR_SP) | in the savearea 339 movl %d0,%sp@- | push syscall number 340 jbsr _C_LABEL(syscall) | handle it 341 addql #4,%sp | pop syscall arg 342 movl %sp@(FR_SP),%a0 | grab and restore 343 movl %a0,%usp | user SP 344 moveml %sp@+,#0x7FFF | restore most registers 345 addql #8,%sp | pop SP and stack adjust 346 jra _ASM_LABEL(rei) | all done 347 348/* 349 * Trap 12 is the entry point for the cachectl "syscall" 350 * cachectl(command, addr, length) 351 * command in %d0, addr in %a1, length in %d1 352 */ 353GLOBAL(trap12) 354 movl _C_LABEL(curproc),%sp@- | push curproc pointer 355 movl %d1,%sp@- | push length 356 movl %a1,%sp@- | push addr 357 movl %d0,%sp@- | push command 358 jbsr _C_LABEL(cachectl1) | do it 359 lea %sp@(16),%sp | pop args 360 jra _ASM_LABEL(rei) | all done 361 362/* 363 * Trace (single-step) trap. Kernel-mode is special. 364 * User mode traps are simply passed on to trap(). 365 */ 366GLOBAL(trace) 367 clrl %sp@- | stack adjust count 368 moveml #0xFFFF,%sp@- 369 moveq #T_TRACE,%d0 370 371 | Check PSW and see what happen. 372 | T=0 S=0 (should not happen) 373 | T=1 S=0 trace trap from user mode 374 | T=0 S=1 trace trap on a trap instruction 375 | T=1 S=1 trace trap from system mode (kernel breakpoint) 376 377 movw %sp@(FR_HW),%d1 | get PSW 378 notw %d1 | XXX no support for T0 on 680[234]0 379 andw #PSL_TS,%d1 | from system mode (T=1, S=1)? 380 jeq _ASM_LABEL(kbrkpt) | yes, kernel brkpt 381 jra _ASM_LABEL(fault) | no, user-mode fault 382 383/* 384 * Trap 15 is used for: 385 * - GDB breakpoints (in user programs) 386 * - KGDB breakpoints (in the kernel) 387 * - trace traps for SUN binaries (not fully supported yet) 388 * User mode traps are simply passed to trap(). 389 */ 390GLOBAL(trap15) 391 clrl %sp@- | stack adjust count 392 moveml #0xFFFF,%sp@- 393 moveq #T_TRAP15,%d0 394 btst #5,%sp@(FR_HW) | was supervisor mode? 395 jne _ASM_LABEL(kbrkpt) | yes, kernel brkpt 396 jra _ASM_LABEL(fault) | no, user-mode fault 397 398ASLOCAL(kbrkpt) 399 | Kernel-mode breakpoint or trace trap. (%d0=trap_type) 400 | Save the system sp rather than the user sp. 401 movw #PSL_HIGHIPL,%sr | lock out interrupts 402 lea %sp@(FR_SIZE),%a6 | Save stack pointer 403 movl %a6,%sp@(FR_SP) | from before trap 404 405 | If we are not on tmpstk switch to it. 406 | (so debugger can change the stack pointer) 407 movl %a6,%d1 408 cmpl #_ASM_LABEL(tmpstk),%d1 409 jls Lbrkpt2 | already on tmpstk 410 | Copy frame to the temporary stack 411 movl %sp,%a0 | %a0=src 412 lea _ASM_LABEL(tmpstk)-96,%a1 | %a1=dst 413 movl %a1,%sp | sp=new frame 414 moveq #FR_SIZE,%d1 415Lbrkpt1: 416 movl %a0@+,%a1@+ 417 subql #4,%d1 418 bgt Lbrkpt1 419 420Lbrkpt2: 421 | Call the trap handler for the kernel debugger. 422 | Do not call trap() to handle it, so that we can 423 | set breakpoints in trap() if we want. We know 424 | the trap type is either T_TRACE or T_BREAKPOINT. 425 movl %d0,%sp@- | push trap type 426 jbsr _C_LABEL(trap_kdebug) 427 addql #4,%sp | pop args 428 429 | The stack pointer may have been modified, or 430 | data below it modified (by kgdb push call), 431 | so push the hardware frame at the current sp 432 | before restoring registers and returning. 433 movl %sp@(FR_SP),%a0 | modified sp 434 lea %sp@(FR_SIZE),%a1 | end of our frame 435 movl %a1@-,%a0@- | copy 2 longs with 436 movl %a1@-,%a0@- | ... predecrement 437 movl %a0,%sp@(FR_SP) | sp = h/w frame 438 moveml %sp@+,#0x7FFF | restore all but sp 439 movl %sp@,%sp | ... and sp 440 rte | all done 441 442/* Use common m68k sigreturn */ 443#include <m68k/m68k/sigreturn.s> 444 445/* 446 * Interrupt handlers. Most are auto-vectored, 447 * and hard-wired the same way on all sun3 models. 448 * Format in the stack is: 449 * %d0,%d1,%a0,%a1, sr, pc, vo 450 */ 451 452#define INTERRUPT_SAVEREG \ 453 moveml #0xC0C0,%sp@- 454 455#define INTERRUPT_RESTORE \ 456 moveml %sp@+,#0x0303 457 458/* 459 * This is the common auto-vector interrupt handler, 460 * for which the CPU provides the vector=0x18+level. 461 * These are installed in the interrupt vector table. 462 */ 463#ifdef __ELF__ 464 .align 4 465#else 466 .align 2 467#endif 468GLOBAL(_isr_autovec) 469 INTERRUPT_SAVEREG 470 jbsr _C_LABEL(isr_autovec) 471 INTERRUPT_RESTORE 472 jra _ASM_LABEL(rei) 473 474/* clock: see clock.c */ 475#ifdef __ELF__ 476 .align 4 477#else 478 .align 2 479#endif 480GLOBAL(_isr_clock) 481 INTERRUPT_SAVEREG 482 jbsr _C_LABEL(clock_intr) 483 INTERRUPT_RESTORE 484 jra _ASM_LABEL(rei) 485 486| Handler for all vectored interrupts (i.e. VME interrupts) 487#ifdef __ELF__ 488 .align 4 489#else 490 .align 2 491#endif 492GLOBAL(_isr_vectored) 493 INTERRUPT_SAVEREG 494 jbsr _C_LABEL(isr_vectored) 495 INTERRUPT_RESTORE 496 jra _ASM_LABEL(rei) 497 498#undef INTERRUPT_SAVEREG 499#undef INTERRUPT_RESTORE 500 501/* interrupt counters (needed by vmstat) */ 502GLOBAL(intrnames) 503 .asciz "spur" | 0 504 .asciz "lev1" | 1 505 .asciz "lev2" | 2 506 .asciz "lev3" | 3 507 .asciz "lev4" | 4 508 .asciz "clock" | 5 509 .asciz "lev6" | 6 510 .asciz "nmi" | 7 511GLOBAL(eintrnames) 512 513 .data 514 .even 515GLOBAL(intrcnt) 516 .long 0,0,0,0,0,0,0,0,0,0 517GLOBAL(eintrcnt) 518 .text 519 520/* 521 * Emulation of VAX REI instruction. 522 * 523 * This code is (mostly) un-altered from the hp300 code, 524 * except that sun machines do not need a simulated SIR 525 * because they have a real software interrupt register. 526 * 527 * This code deals with checking for and servicing ASTs 528 * (profiling, scheduling) and software interrupts (network, softclock). 529 * We check for ASTs first, just like the VAX. To avoid excess overhead 530 * the T_ASTFLT handling code will also check for software interrupts so we 531 * do not have to do it here. After identifying that we need an AST we 532 * drop the IPL to allow device interrupts. 533 * 534 * This code is complicated by the fact that sendsig may have been called 535 * necessitating a stack cleanup. 536 */ 537 538ASGLOBAL(rei) 539#ifdef DIAGNOSTIC 540 tstl _C_LABEL(panicstr) | have we paniced? 541 jne Ldorte | yes, do not make matters worse 542#endif 543 tstl _C_LABEL(astpending) | AST pending? 544 jeq Ldorte | no, done 545Lrei1: 546 btst #5,%sp@ | yes, are we returning to user mode? 547 jne Ldorte | no, done 548 movw #PSL_LOWIPL,%sr | lower SPL 549 clrl %sp@- | stack adjust 550 moveml #0xFFFF,%sp@- | save all registers 551 movl %usp,%a1 | including 552 movl %a1,%sp@(FR_SP) | the users SP 553 clrl %sp@- | VA == none 554 clrl %sp@- | code == none 555 movl #T_ASTFLT,%sp@- | type == async system trap 556 jbsr _C_LABEL(trap) | go handle it 557 lea %sp@(12),%sp | pop value args 558 movl %sp@(FR_SP),%a0 | restore user SP 559 movl %a0,%usp | from save area 560 movw %sp@(FR_ADJ),%d0 | need to adjust stack? 561 jne Laststkadj | yes, go to it 562 moveml %sp@+,#0x7FFF | no, restore most user regs 563 addql #8,%sp | toss SP and stack adjust 564 rte | and do real RTE 565Laststkadj: 566 lea %sp@(FR_HW),%a1 | pointer to HW frame 567 addql #8,%a1 | source pointer 568 movl %a1,%a0 | source 569 addw %d0,%a0 | + hole size = dest pointer 570 movl %a1@-,%a0@- | copy 571 movl %a1@-,%a0@- | 8 bytes 572 movl %a0,%sp@(FR_SP) | new SSP 573 moveml %sp@+,#0x7FFF | restore user registers 574 movl %sp@,%sp | and our SP 575Ldorte: 576 rte | real return 577 578/* 579 * Initialization is at the beginning of this file, because the 580 * kernel entry point needs to be at zero for compatibility with 581 * the Sun boot loader. This works on Sun machines because the 582 * interrupt vector table for reset is NOT at address zero. 583 * (The MMU has a "boot" bit that forces access to the PROM) 584 */ 585 586/* 587 * Use common m68k sigcode. 588 */ 589#include <m68k/m68k/sigcode.s> 590#ifdef COMPAT_SUNOS 591#include <m68k/m68k/sunos_sigcode.s> 592#endif 593#ifdef COMPAT_SVR4 594#include <m68k/m68k/svr4_sigcode.s> 595#endif 596 597 .text 598 599/* 600 * Primitives 601 */ 602 603/* 604 * Use common m68k support routines. 605 */ 606#include <m68k/m68k/support.s> 607 608BSS(want_resched,4) 609 610/* 611 * Use common m68k process manipulation routines. 612 */ 613#include <m68k/m68k/proc_subr.s> 614 615| Message for Lbadsw panic 616Lsw0: 617 .asciz "cpu_switch" 618 .even 619 620 .data 621GLOBAL(masterpaddr) | XXX compatibility (debuggers) 622GLOBAL(curpcb) 623 .long 0 624ASBSS(nullpcb,SIZEOF_PCB) 625 .text 626 627/* 628 * At exit of a process, do a cpu_switch for the last time. 629 * Switch to a safe stack and PCB, and select a new process to run. The 630 * old stack and u-area will be freed by the reaper. 631 */ 632ENTRY(switch_exit) 633 movl %sp@(4),%a0 | struct proc *p 634 | save state into garbage pcb 635 movl #_ASM_LABEL(nullpcb),_C_LABEL(curpcb) 636 lea _ASM_LABEL(tmpstk),%sp | goto a tmp stack 637 638 /* Schedule the vmspace and stack to be freed. */ 639 movl %a0,%sp@- | exit2(p) 640 jbsr _C_LABEL(exit2) 641 lea %sp@(4),%sp | pop args 642 643#if defined(LOCKDEBUG) 644 /* Acquire sched_lock */ 645 jbsr _C_LABEL(sched_lock_idle) 646#endif 647 648 jra _C_LABEL(cpu_switch) 649 650/* 651 * When no processes are on the runq, cpu_switch() branches to idle 652 * to wait for something to come ready. 653 */ 654Lidle: 655#if defined(LOCKDEBUG) 656 /* Release sched_lock */ 657 jbsr _C_LABEL(sched_unlock_idle) 658#endif 659 stop #PSL_LOWIPL 660GLOBAL(_Idle) | See clock.c 661 movw #PSL_HIGHIPL,%sr 662#if defined(LOCKDEBUG) 663 /* Acquire sched_lock */ 664 jbsr _C_LABEL(sched_lock_idle) 665#endif 666 movl _C_LABEL(sched_whichqs),%d0 667 jeq Lidle 668 jra Lsw1 669 670Lbadsw: 671 movl #Lsw0,%sp@- 672 jbsr _C_LABEL(panic) 673 /*NOTREACHED*/ 674 675/* 676 * cpu_switch() 677 * Hacked for sun3 678 */ 679ENTRY(cpu_switch) 680 movl _C_LABEL(curpcb),%a0 | current pcb 681 movw %sr,%a0@(PCB_PS) | save sr before changing ipl 682#ifdef notyet 683 movl _C_LABEL(curproc),%sp@- | remember last proc running 684#endif 685 clrl _C_LABEL(curproc) 686 687 /* 688 * Find the highest-priority queue that isn't empty, 689 * then take the first proc from that queue. 690 */ 691 movl _C_LABEL(sched_whichqs),%d0 692 jeq Lidle 693Lsw1: 694 /* 695 * Interrupts are blocked, sched_lock is held. If 696 * we come here via Idle, %d0 contains the contents 697 * of a non-zero sched_whichqs. 698 */ 699 movl %d0,%d1 700 negl %d0 701 andl %d1,%d0 702 bfffo %d0{#0:#32},%d1 703 eorib #31,%d1 704 705 movl %d1,%d0 706 lslb #3,%d1 | convert queue number to index 707 addl #_C_LABEL(sched_qs),%d1 | locate queue (q) 708 movl %d1,%a1 709 movl %a1@(P_FORW),%a0 | p = q->p_forw 710 cmpal %d1,%a0 | anyone on queue? 711 jeq Lbadsw | no, panic 712#ifdef DIAGNOSTIC 713 tstl %a0@(P_WCHAN) 714 jne Lbadsw 715 cmpb #SRUN,%a0@(P_STAT) 716 jne Lbadsw 717#endif 718 movl %a0@(P_FORW),%a1@(P_FORW) | q->p_forw = p->p_forw 719 movl %a0@(P_FORW),%a1 | n = p->p_forw 720 movl %a0@(P_BACK),%a1@(P_BACK) | n->p_back = q 721 cmpal %d1,%a1 | anyone left on queue? 722 jne Lsw2 | yes, skip 723 movl _C_LABEL(sched_whichqs),%d1 724 bclr %d0,%d1 | no, clear bit 725 movl %d1,_C_LABEL(sched_whichqs) 726Lsw2: 727 /* p->p_cpu initialized in fork1() for single-processor */ 728 movb #SONPROC,%a0@(P_STAT) | p->p_stat = SONPROC 729 movl %a0,_C_LABEL(curproc) 730 clrl _C_LABEL(want_resched) 731#ifdef notyet 732 movl %sp@+,%a1 | XXX - Make this work! 733 cmpl %a0,%a1 | switching to same proc? 734 jeq Lswdone | yes, skip save and restore 735#endif 736 /* 737 * Save state of previous process in its pcb. 738 */ 739 movl _C_LABEL(curpcb),%a1 740 moveml #0xFCFC,%a1@(PCB_REGS) | save non-scratch registers 741 movl %usp,%a2 | grab USP (a2 has been saved) 742 movl %a2,%a1@(PCB_USP) | and save it 743 744 tstl _C_LABEL(fputype) | Do we have an fpu? 745 jeq Lswnofpsave | No? Then don't try save. 746 lea %a1@(PCB_FPCTX),%a2 | pointer to FP save area 747 fsave %a2@ | save FP state 748 tstb %a2@ | null state frame? 749 jeq Lswnofpsave | yes, all done 750 fmovem %fp0-%fp7,%a2@(FPF_REGS) | save FP general regs 751 fmovem %fpcr/%fpsr/%fpi,%a2@(FPF_FPCR) | save FP control regs 752Lswnofpsave: 753 754 /* 755 * Now that we have saved all the registers that must be 756 * preserved, we are free to use those registers until 757 * we load the registers for the switched-to process. 758 * In this section, keep: %a0=curproc, %a1=curpcb 759 */ 760 761 clrl %a0@(P_BACK) | clear back link 762 movl %a0@(P_ADDR),%a1 | get p_addr 763 movl %a1,_C_LABEL(curpcb) 764 765#if defined(LOCKDEBUG) 766 /* 767 * Done mucking with the run queues, release the 768 * scheduler lock, but keep interrupts out. 769 */ 770 movl %a0,%sp@- | not args... 771 movl %a1,%sp@- | ...just saving 772 jbsr _C_LABEL(sched_unlock_idle) 773 movl %sp@+,%a1 774 movl %sp@+,%a0 775#endif 776 777 /* 778 * Load the new VM context (new MMU root pointer) 779 */ 780 movl %a0@(P_VMSPACE),%a2 | vm = p->p_vmspace 781#ifdef DIAGNOSTIC 782 tstl %a2 | vm == VM_MAP_NULL? 783 jeq Lbadsw | panic 784#endif 785#if 1 /* XXX: PMAP_DEBUG */ 786 /* 787 * Just call _pmap_switch() for now. Later on, 788 * use the in-line version below (for speed). 789 */ 790 movl %a2@(VM_PMAP),%a2 | pmap = vm->vm_map.pmap 791 pea %a2@ | push pmap 792 jbsr _C_LABEL(_pmap_switch) | _pmap_switch(pmap) 793 addql #4,%sp 794 movl _C_LABEL(curpcb),%a1 | restore p_addr 795| Note: pmap_switch will clear the cache if needed. 796#else 797 /* XXX - Later, use this unfinished inline.. */ 798 XXX XXX (PM_CTXNUM) 799 movl #IC_CLEAR,%d0 800 movc %d0,%cacr | invalidate cache(s) 801#endif 802 803 /* 804 * Reload the registers for the new process. 805 * After this point we can only use %d0,%d1,%a0,%a1 806 */ 807 moveml %a1@(PCB_REGS),#0xFCFC | reload registers 808 movl %a1@(PCB_USP),%a0 809 movl %a0,%usp | and USP 810 811 tstl _C_LABEL(fputype) | If we don't have an fpu, 812 jeq Lres_skip | don't try to restore it. 813 lea %a1@(PCB_FPCTX),%a0 | pointer to FP save area 814 tstb %a0@ | null state frame? 815 jeq Lresfprest | yes, easy 816 fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control regs 817 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general regs 818Lresfprest: 819 frestore %a0@ | restore state 820Lres_skip: 821 movw %a1@(PCB_PS),%d0 | no, restore PS 822#ifdef DIAGNOSTIC 823 btst #13,%d0 | supervisor mode? 824 jeq Lbadsw | no? panic! 825#endif 826 movw %d0,%sr | OK, restore PS 827 moveq #1,%d0 | return 1 (for alternate returns) 828 movl %d0,%a0 829 rts 830 831/* 832 * savectx(pcb) 833 * Update pcb, saving current processor state. 834 */ 835ENTRY(savectx) 836 movl %sp@(4),%a1 837 movw %sr,%a1@(PCB_PS) 838 movl %usp,%a0 | grab USP 839 movl %a0,%a1@(PCB_USP) | and save it 840 moveml #0xFCFC,%a1@(PCB_REGS) | save non-scratch registers 841 842 tstl _C_LABEL(fputype) | Do we have FPU? 843 jeq Lsavedone | No? Then don't save state. 844 lea %a1@(PCB_FPCTX),%a0 | pointer to FP save area 845 fsave %a0@ | save FP state 846 tstb %a0@ | null state frame? 847 jeq Lsavedone | yes, all done 848 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general regs 849 fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control regs 850Lsavedone: 851 moveq #0,%d0 | return 0 852 movl %d0,%a0 853 rts 854 855/* suline() */ 856/* TBIA, TBIS, TBIAS, TBIAU */ 857 858/* 859 * Invalidate instruction cache 860 */ 861ENTRY(ICIA) 862 movl #IC_CLEAR,%d0 863 movc %d0,%cacr | invalidate i-cache 864 rts 865 866/* DCIA, DCIS */ 867 868/* 869 * Invalidate data cache. 870 */ 871ENTRY(DCIU) 872 rts 873 874/* ICPL, ICPP, DCPL, DCPP, DCPA, DCFL, DCFP */ 875/* PCIA, ecacheon, ecacheoff */ 876 877/* 878 * Get callers current SP value. 879 * Note that simply taking the address of a local variable in a C function 880 * doesn't work because callee saved registers may be outside the stack frame 881 * defined by A6 (e.g. GCC generated code). 882 * 883 * [I don't think the ENTRY() macro will do the right thing with this -- glass] 884 */ 885GLOBAL(getsp) 886 movl %sp,%d0 | get current SP 887 addql #4,%d0 | compensate for return address 888 movl %d0,%a0 889 rts 890 891ENTRY(getsfc) 892 movc %sfc,%d0 893 movl %d0,%a0 894 rts 895 896ENTRY(getdfc) 897 movc %dfc,%d0 898 movl %d0,%a0 899 rts 900 901ENTRY(getvbr) 902 movc %vbr,%a0 903 rts 904 905ENTRY(setvbr) 906 movl %sp@(4),%d0 907 movc %d0,%vbr 908 rts 909 910/* loadustp, ptest_addr */ 911 912/* 913 * Set processor priority level calls. Most are implemented with 914 * inline asm expansions. However, we need one instantiation here 915 * in case some non-optimized code makes external references. 916 * Most places will use the inlined functions param.h supplies. 917 */ 918 919ENTRY(_getsr) 920 clrl %d0 921 movw %sr,%d0 922 movl %d0,%a0 923 rts 924 925ENTRY(_spl) 926 clrl %d0 927 movw %sr,%d0 928 movl %sp@(4),%d1 929 movw %d1,%sr 930 rts 931 932ENTRY(_splraise) 933 clrl %d0 934 movw %sr,%d0 935 movl %d0,%d1 936 andl #PSL_HIGHIPL,%d1 | old &= PSL_HIGHIPL 937 cmpl %sp@(4),%d1 | (old - new) 938 bge Lsplr 939 movl %sp@(4),%d1 940 movw %d1,%sr 941Lsplr: 942 rts 943 944/* 945 * Save and restore 68881 state. 946 */ 947ENTRY(m68881_save) 948 movl %sp@(4),%a0 | save area pointer 949 fsave %a0@ | save state 950 tstb %a0@ | null state frame? 951 jeq Lm68881sdone | yes, all done 952 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general regs 953 fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control regs 954Lm68881sdone: 955 rts 956 957ENTRY(m68881_restore) 958 movl %sp@(4),%a0 | save area pointer 959 tstb %a0@ | null state frame? 960 jeq Lm68881rdone | yes, easy 961 fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control regs 962 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general regs 963Lm68881rdone: 964 frestore %a0@ | restore state 965 rts 966 967/* 968 * _delay(unsigned N) 969 * Delay for at least (N/256) microseconds. 970 * This routine depends on the variable: delay_divisor 971 * which should be set based on the CPU clock rate. 972 * XXX: Currently this is set based on the CPU model, 973 * XXX: but this should be determined at run time... 974 */ 975GLOBAL(_delay) 976 | %d0 = arg = (usecs << 8) 977 movl %sp@(4),%d0 978 | %d1 = delay_divisor; 979 movl _C_LABEL(delay_divisor),%d1 980 jra L_delay /* Jump into the loop! */ 981 982 /* 983 * Align the branch target of the loop to a half-line (8-byte) 984 * boundary to minimize cache effects. This guarantees both 985 * that there will be no prefetch stalls due to cache line burst 986 * operations and that the loop will run from a single cache 987 * half-line. 988 */ 989#ifdef __ELF__ 990 .align 8 991#else 992 .align 3 993#endif 994L_delay: 995 subl %d1,%d0 996 jgt L_delay 997 rts 998 999/* 1000 * void set_segmap_allctx(vaddr_t va, int sme) 1001 */ 1002ENTRY(set_segmap_allctx) 1003 linkw %fp,#0 1004 moveml #0x3000,%sp@- 1005 movl 8(%fp),%d3 | d3 = va 1006 andl #0xffffffc,%d3 1007 bset #29,%d3 1008 movl %d3,%a1 | a1 = ctrladdr, d3 avail 1009 movl 12(%fp),%d1 | d1 = sme 1010 moveq #FC_CONTROL,%d0 1011 movl #CONTEXT_REG,%a0 | a0 = ctxreg 1012 movc %sfc,%d3 | d3 = oldsfc 1013 movc %d0,%sfc 1014 movsb %a0@,%d2 1015 andi #7,%d2 | d2 = oldctx 1016 movc %d3,%sfc | restore sfc, d3 avail 1017 movc %dfc,%d3 | d3 = olddfc 1018 movc %d0,%dfc 1019 movl #(CONTEXT_NUM - 1),%d0 | d0 = ctx number 10201: 1021 movsb %d0,%a0@ | change to ctx 1022 movsb %d1,%a1@ | set segmap 1023 dbf %d0,1b | loop setting each ctx 1024 movsb %d2,%a0@ | restore ctx 1025 movc %d3,%dfc | restore dfc 1026 moveml %sp@+,#0x000c 1027 unlk %fp 1028 rts 1029 1030| Define some addresses, mostly so DDB can print useful info. 1031| Not using _C_LABEL() here because these symbols are never 1032| referenced by any C code, and if the leading underscore 1033| ever goes away, these lines turn into syntax errors... 1034 .set _KERNBASE,KERNBASE 1035 .set _MONSTART,SUN3_MONSTART 1036 .set _PROM_BASE,SUN3_PROM_BASE 1037 .set _MONEND,SUN3_MONEND 1038 1039|The end! 1040