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