locore.s revision 1.35
1/* $NetBSD: locore.s,v 1.35 1999/04/30 09:21:54 christos 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 48#include "assym.h" 49#include <machine/asm.h> 50#include <machine/trap.h> 51 52| Remember this is a fun project! 53 54 .data 55GLOBAL(mon_crp) 56 .long 0,0 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| The first step, after disabling interrupts, is to map enough of the kernel 69| into high virtual address space so that we can use position dependent code. 70| This is a tricky task on the sun3x because the MMU is already enabled and 71| the ROM monitor provides no indication of where the root MMU table is mapped. 72| Therefore we must use one of the 68030's 'transparent translation' registers 73| to define a range in the address space where the MMU translation is 74| turned off. Once this is complete we can modify the MMU table directly 75| without the need for it to be mapped into virtual memory. 76| All code must be position independent until otherwise noted, as the 77| boot loader has loaded us into low memory but all the symbols in this 78| code have been linked high. 79 movw #PSL_HIGHIPL, sr | no interrupts 80 movl #KERNBASE, a5 | for vtop conversion 81 lea _C_LABEL(mon_crp), a0 | where to store the CRP 82 subl a5, a0 83 | Note: borrowing mon_crp for tt0 setup... 84 movl #0x3F8107, a0@ | map the low 1GB v=p with the 85 .long 0xf0100800 | transparent translation reg0 86 | [ pmove a0@, tt0 ] 87| In order to map the kernel into high memory we will copy the root table 88| entry which maps the 16 megabytes of memory starting at 0x0 into the 89| entry which maps the 16 megabytes starting at KERNBASE. 90 pmove crp, a0@ | Get monitor CPU root pointer 91 movl a0@(4), a1 | 2nd word is PA of level A table 92 93 movl a1, a0 | compute the descriptor address 94 addl #0x3e0, a1 | for VA starting at KERNBASE 95 movl a0@, a1@ | copy descriptor type 96 movl a0@(4), a1@(4) | copy physical address 97 98| Kernel is now double mapped at zero and KERNBASE. 99| Force a long jump to the relocated code (high VA). 100 movl #IC_CLEAR, d0 | Flush the I-cache 101 movc d0, cacr 102 jmp L_high_code:l | long jump 103 104L_high_code: 105| We are now running in the correctly relocated kernel, so 106| we are no longer restricted to position-independent code. 107| It is handy to leave transparent translation enabled while 108| for the low 1GB while _bootstrap() is doing its thing. 109 110| Do bootstrap stuff needed before main() gets called. 111| Our boot loader leaves a copy of the kernel's exec header 112| just before the start of the kernel text segment, so the 113| kernel can sanity-check the DDB symbols at [end...esym]. 114| Pass the struct exec at tmpstk-32 to _bootstrap(). 115| Also, make sure the initial frame pointer is zero so that 116| the backtrace algorithm used by KGDB terminates nicely. 117 lea _ASM_LABEL(tmpstk)-32, sp 118 movl #0,a6 119 jsr _C_LABEL(_bootstrap) | See locore2.c 120 121| Now turn off the transparent translation of the low 1GB. 122| (this also flushes the ATC) 123 clrl sp@- 124 .long 0xf0170800 | pmove sp@,tt0 125 addql #4,sp 126 127| Now that _bootstrap() is done using the PROM functions, 128| we can safely set the sfc/dfc to something != FC_CONTROL 129 moveq #FC_USERD, d0 | make movs access "user data" 130 movc d0, sfc | space for copyin/copyout 131 movc d0, dfc 132 133| Setup process zero user/kernel stacks. 134 movl _C_LABEL(proc0paddr),a1 | get proc0 pcb addr 135 lea a1@(USPACE-4),sp | set SSP to last word 136 movl #USRSTACK-4,a2 137 movl a2,usp | init user SP 138 139| Note curpcb was already set in _bootstrap(). 140| Will do fpu initialization during autoconfig (see fpu.c) 141| The interrupt vector table and stack are now ready. 142| Interrupts will be enabled later, AFTER autoconfiguration 143| is finished, to avoid spurrious interrupts. 144 145/* 146 * Final preparation for calling main. 147 * 148 * Create a fake exception frame that returns to user mode, 149 * and save its address in p->p_md.md_regs for cpu_fork(). 150 * The new frames for process 1 and 2 will be adjusted by 151 * cpu_set_kpc() to arrange for a call to a kernel function 152 * before the new process does its rte out to user mode. 153 */ 154 clrw sp@- | tf_format,tf_vector 155 clrl sp@- | tf_pc (filled in later) 156 movw #PSL_USER,sp@- | tf_sr for user mode 157 clrl sp@- | tf_stackadj 158 lea sp@(-64),sp | tf_regs[16] 159 movl sp,a1 | a1=trapframe 160 lea _C_LABEL(proc0),a0 | proc0.p_md.md_regs = 161 movl a1,a0@(P_MDREGS) | trapframe 162 movl a2,a1@(FR_SP) | a2 == usp (from above) 163 pea a1@ | push &trapframe 164 jbsr _C_LABEL(main) | main(&trapframe) 165 addql #4,sp | help DDB backtrace 166 trap #15 | should not get here 167 168| This is used by cpu_fork() to return to user mode. 169| It is called with SP pointing to a struct trapframe. 170GLOBAL(proc_do_uret) 171 movl sp@(FR_SP),a0 | grab and load 172 movl a0,usp | user SP 173 moveml sp@+,#0x7FFF | load most registers (all but SSP) 174 addql #8,sp | pop SSP and stack adjust count 175 rte 176 177/* 178 * proc_trampoline: 179 * This is used by cpu_set_kpc() to "push" a function call onto the 180 * kernel stack of some process, very much like a signal delivery. 181 * When we get here, the stack has: 182 * 183 * SP+8: switchframe from before cpu_set_kpc 184 * SP+4: void *arg; 185 * SP: u_long func; 186 * 187 * On entry, the switchframe pushed by cpu_set_kpc has already been 188 * popped off the stack, so all this needs to do is pop the function 189 * pointer into a register, call it, then pop the arg, and finally 190 * return using the switchframe that remains on the stack. 191 */ 192GLOBAL(proc_trampoline) 193 movl sp@+,a0 | function pointer 194 jbsr a0@ | (*func)(arg) 195 addql #4,sp | toss the arg 196 rts | as cpu_switch would do 197 198| That is all the assembly startup code we need on the sun3x! 199| The rest of this is like the hp300/locore.s where possible. 200 201/* 202 * Trap/interrupt vector routines 203 */ 204#include <m68k/m68k/trap_subr.s> 205 206GLOBAL(buserr) 207 tstl _C_LABEL(nofault) | device probe? 208 jeq _C_LABEL(addrerr) | no, handle as usual 209 movl _C_LABEL(nofault),sp@- | yes, 210 jbsr _C_LABEL(longjmp) | longjmp(nofault) 211GLOBAL(addrerr) 212 clrl sp@- | stack adjust count 213 moveml #0xFFFF,sp@- | save user registers 214 movl usp,a0 | save the user SP 215 movl a0,sp@(FR_SP) | in the savearea 216 lea sp@(FR_HW),a1 | grab base of HW berr frame 217 moveq #0,d0 218 movw a1@(10),d0 | grab SSW for fault processing 219 btst #12,d0 | RB set? 220 jeq LbeX0 | no, test RC 221 bset #14,d0 | yes, must set FB 222 movw d0,a1@(10) | for hardware too 223LbeX0: 224 btst #13,d0 | RC set? 225 jeq LbeX1 | no, skip 226 bset #15,d0 | yes, must set FC 227 movw d0,a1@(10) | for hardware too 228LbeX1: 229 btst #8,d0 | data fault? 230 jeq Lbe0 | no, check for hard cases 231 movl a1@(16),d1 | fault address is as given in frame 232 jra Lbe10 | thats it 233Lbe0: 234 btst #4,a1@(6) | long (type B) stack frame? 235 jne Lbe4 | yes, go handle 236 movl a1@(2),d1 | no, can use save PC 237 btst #14,d0 | FB set? 238 jeq Lbe3 | no, try FC 239 addql #4,d1 | yes, adjust address 240 jra Lbe10 | done 241Lbe3: 242 btst #15,d0 | FC set? 243 jeq Lbe10 | no, done 244 addql #2,d1 | yes, adjust address 245 jra Lbe10 | done 246Lbe4: 247 movl a1@(36),d1 | long format, use stage B address 248 btst #15,d0 | FC set? 249 jeq Lbe10 | no, all done 250 subql #2,d1 | yes, adjust address 251Lbe10: 252 movl d1,sp@- | push fault VA 253 movl d0,sp@- | and padded SSW 254 movw a1@(6),d0 | get frame format/vector offset 255 andw #0x0FFF,d0 | clear out frame format 256 cmpw #12,d0 | address error vector? 257 jeq Lisaerr | yes, go to it 258 259/* MMU-specific code to determine reason for bus error. */ 260 movl d1,a0 | fault address 261 movl sp@,d0 | function code from ssw 262 btst #8,d0 | data fault? 263 jne Lbe10a 264 movql #1,d0 | user program access FC 265 | (we dont separate data/program) 266 btst #5,a1@ | supervisor mode? 267 jeq Lbe10a | if no, done 268 movql #5,d0 | else supervisor program access 269Lbe10a: 270 ptestr d0,a0@,#7 | do a table search 271 pmove psr,sp@ | save result 272 movb sp@,d1 273 btst #2,d1 | invalid? (incl. limit viol and berr) 274 jeq Lmightnotbemerr | no -> wp check 275 btst #7,d1 | is it MMU table berr? 276 jeq Lismerr | no, must be fast 277 jra Lisberr1 | real bus err needs not be fast 278Lmightnotbemerr: 279 btst #3,d1 | write protect bit set? 280 jeq Lisberr1 | no, must be bus error 281 movl sp@,d0 | ssw into low word of d0 282 andw #0xc0,d0 | write protect is set on page: 283 cmpw #0x40,d0 | was it read cycle? 284 jeq Lisberr1 | yes, was not WPE, must be bus err 285/* End of MMU-specific bus error code. */ 286 287Lismerr: 288 movl #T_MMUFLT,sp@- | show that we are an MMU fault 289 jra _ASM_LABEL(faultstkadj) | and deal with it 290Lisaerr: 291 movl #T_ADDRERR,sp@- | mark address error 292 jra _ASM_LABEL(faultstkadj) | and deal with it 293Lisberr1: 294 clrw sp@ | re-clear pad word 295Lisberr: 296 movl #T_BUSERR,sp@- | mark bus error 297 jra _ASM_LABEL(faultstkadj) | and deal with it 298 299/* 300 * FP exceptions. 301 */ 302GLOBAL(fpfline) 303 clrl sp@- | stack adjust count 304 moveml #0xFFFF,sp@- | save registers 305 moveq #T_FPEMULI,d0 | denote as FP emulation trap 306 jra _ASM_LABEL(fault) | do it 307 308GLOBAL(fpunsupp) 309 clrl sp@- | stack adjust count 310 moveml #0xFFFF,sp@- | save registers 311 moveq #T_FPEMULD,d0 | denote as FP emulation trap 312 jra _ASM_LABEL(fault) | do it 313 314/* 315 * Handles all other FP coprocessor exceptions. 316 * Note that since some FP exceptions generate mid-instruction frames 317 * and may cause signal delivery, we need to test for stack adjustment 318 * after the trap call. 319 */ 320GLOBAL(fpfault) 321 clrl sp@- | stack adjust count 322 moveml #0xFFFF,sp@- | save user registers 323 movl usp,a0 | and save 324 movl a0,sp@(FR_SP) | the user stack pointer 325 clrl sp@- | no VA arg 326 movl _C_LABEL(curpcb),a0 | current pcb 327 lea a0@(PCB_FPCTX),a0 | address of FP savearea 328 fsave a0@ | save state 329 tstb a0@ | null state frame? 330 jeq Lfptnull | yes, safe 331 clrw d0 | no, need to tweak BIU 332 movb a0@(1),d0 | get frame size 333 bset #3,a0@(0,d0:w) | set exc_pend bit of BIU 334Lfptnull: 335 fmovem fpsr,sp@- | push fpsr as code argument 336 frestore a0@ | restore state 337 movl #T_FPERR,sp@- | push type arg 338 jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup 339 340/* 341 * Other exceptions only cause four and six word stack frame and require 342 * no post-trap stack adjustment. 343 */ 344GLOBAL(badtrap) 345 clrl sp@- | stack adjust count 346 moveml #0xFFFF,sp@- | save std frame regs 347 jbsr _C_LABEL(straytrap) | report 348 moveml sp@+,#0xFFFF | restore regs 349 addql #4, sp | stack adjust count 350 jra _ASM_LABEL(rei) | all done 351 352/* 353 * Trap 0 is for system calls 354 */ 355GLOBAL(trap0) 356 clrl sp@- | stack adjust count 357 moveml #0xFFFF,sp@- | save user registers 358 movl usp,a0 | save the user SP 359 movl a0,sp@(FR_SP) | in the savearea 360 movl d0,sp@- | push syscall number 361 jbsr _C_LABEL(syscall) | handle it 362 addql #4,sp | pop syscall arg 363 movl sp@(FR_SP),a0 | grab and restore 364 movl a0,usp | user SP 365 moveml sp@+,#0x7FFF | restore most registers 366 addql #8,sp | pop SP and stack adjust 367 jra _ASM_LABEL(rei) | all done 368 369/* 370 * Trap 12 is the entry point for the cachectl "syscall" 371 * cachectl(command, addr, length) 372 * command in d0, addr in a1, length in d1 373 */ 374GLOBAL(trap12) 375 movl _C_LABEL(curproc),sp@- | push curproc pointer 376 movl d1,sp@- | push length 377 movl a1,sp@- | push addr 378 movl d0,sp@- | push command 379 jbsr _C_LABEL(cachectl1) | do it 380 lea sp@(16),sp | pop args 381 jra _ASM_LABEL(rei) | all done 382 383/* 384 * Trace (single-step) trap. Kernel-mode is special. 385 * User mode traps are simply passed on to trap(). 386 */ 387GLOBAL(trace) 388 clrl sp@- | stack adjust count 389 moveml #0xFFFF,sp@- 390 moveq #T_TRACE,d0 391 btst #5,sp@(FR_HW) | was supervisor mode? 392 jne _ASM_LABEL(kbrkpt) | yes, kernel brkpt 393 jra _ASM_LABEL(fault) | no, user-mode fault 394 395/* 396 * Trap 15 is used for: 397 * - GDB breakpoints (in user programs) 398 * - KGDB breakpoints (in the kernel) 399 * - trace traps for SUN binaries (not fully supported yet) 400 * User mode traps are simply passed to trap(). 401 */ 402GLOBAL(trap15) 403 clrl sp@- | stack adjust count 404 moveml #0xFFFF,sp@- 405 moveq #T_TRAP15,d0 406 btst #5,sp@(FR_HW) | was supervisor mode? 407 jne _ASM_LABEL(kbrkpt) | yes, kernel brkpt 408 jra _ASM_LABEL(fault) | no, user-mode fault 409 410ASLOCAL(kbrkpt) 411 | Kernel-mode breakpoint or trace trap. (d0=trap_type) 412 | Save the system sp rather than the user sp. 413 movw #PSL_HIGHIPL,sr | lock out interrupts 414 lea sp@(FR_SIZE),a6 | Save stack pointer 415 movl a6,sp@(FR_SP) | from before trap 416 417 | If we are not on tmpstk switch to it. 418 | (so debugger can change the stack pointer) 419 movl a6,d1 420 cmpl #_ASM_LABEL(tmpstk),d1 421 jls Lbrkpt2 | already on tmpstk 422 | Copy frame to the temporary stack 423 movl sp,a0 | a0=src 424 lea _ASM_LABEL(tmpstk)-96,a1 | a1=dst 425 movl a1,sp | sp=new frame 426 moveq #FR_SIZE,d1 427Lbrkpt1: 428 movl a0@+,a1@+ 429 subql #4,d1 430 bgt Lbrkpt1 431 432Lbrkpt2: 433 | Call the trap handler for the kernel debugger. 434 | Do not call trap() to handle it, so that we can 435 | set breakpoints in trap() if we want. We know 436 | the trap type is either T_TRACE or T_BREAKPOINT. 437 movl d0,sp@- | push trap type 438 jbsr _C_LABEL(trap_kdebug) 439 addql #4,sp | pop args 440 441 | The stack pointer may have been modified, or 442 | data below it modified (by kgdb push call), 443 | so push the hardware frame at the current sp 444 | before restoring registers and returning. 445 movl sp@(FR_SP),a0 | modified sp 446 lea sp@(FR_SIZE),a1 | end of our frame 447 movl a1@-,a0@- | copy 2 longs with 448 movl a1@-,a0@- | ... predecrement 449 movl a0,sp@(FR_SP) | sp = h/w frame 450 moveml sp@+,#0x7FFF | restore all but sp 451 movl sp@,sp | ... and sp 452 rte | all done 453 454/* Use common m68k sigreturn */ 455#include <m68k/m68k/sigreturn.s> 456 457/* 458 * Interrupt handlers. Most are auto-vectored, 459 * and hard-wired the same way on all sun3 models. 460 * Format in the stack is: 461 * d0,d1,a0,a1, sr, pc, vo 462 */ 463 464#define INTERRUPT_SAVEREG \ 465 moveml #0xC0C0,sp@- 466 467#define INTERRUPT_RESTORE \ 468 moveml sp@+,#0x0303 469 470/* 471 * This is the common auto-vector interrupt handler, 472 * for which the CPU provides the vector=0x18+level. 473 * These are installed in the interrupt vector table. 474 */ 475 .align 2 476GLOBAL(_isr_autovec) 477 INTERRUPT_SAVEREG 478 jbsr _C_LABEL(isr_autovec) 479 INTERRUPT_RESTORE 480 jra _ASM_LABEL(rei) 481 482/* clock: see clock.c */ 483 .align 2 484GLOBAL(_isr_clock) 485 INTERRUPT_SAVEREG 486 jbsr _C_LABEL(clock_intr) 487 INTERRUPT_RESTORE 488 jra _ASM_LABEL(rei) 489 490| Handler for all vectored interrupts (i.e. VME interrupts) 491 .align 2 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 591 .text 592 593/* 594 * Primitives 595 */ 596 597/* 598 * Use common m68k support routines. 599 */ 600#include <m68k/m68k/support.s> 601 602BSS(want_resched,4) 603 604/* 605 * Use common m68k process manipulation routines. 606 */ 607#include <m68k/m68k/proc_subr.s> 608 609| Message for Lbadsw panic 610Lsw0: 611 .asciz "cpu_switch" 612 .even 613 614 .data 615GLOBAL(masterpaddr) | XXX compatibility (debuggers) 616GLOBAL(curpcb) 617 .long 0 618ASBSS(nullpcb,SIZEOF_PCB) 619 .text 620 621/* 622 * At exit of a process, do a cpu_switch for the last time. 623 * Switch to a safe stack and PCB, and select a new process to run. The 624 * old stack and u-area will be freed by the reaper. 625 */ 626ENTRY(switch_exit) 627 movl sp@(4),a0 | struct proc *p 628 | save state into garbage pcb 629 movl #_ASM_LABEL(nullpcb),_C_LABEL(curpcb) 630 lea _ASM_LABEL(tmpstk),sp | goto a tmp stack 631 632 /* Schedule the vmspace and stack to be freed. */ 633 movl a0,sp@- | exit2(p) 634 jbsr _C_LABEL(exit2) 635 636 /* Don't pop the proc; pass it to cpu_switch(). */ 637 638 jra _C_LABEL(cpu_switch) 639 640/* 641 * When no processes are on the runq, cpu_switch() branches to idle 642 * to wait for something to come ready. 643 */ 644 .data 645GLOBAL(Idle_count) 646 .long 0 647 .text 648 649Lidle: 650 stop #PSL_LOWIPL 651GLOBAL(_Idle) | See clock.c 652 movw #PSL_HIGHIPL,sr 653 addql #1, _C_LABEL(Idle_count) 654 tstl _C_LABEL(whichqs) 655 jeq Lidle 656 movw #PSL_LOWIPL,sr 657 jra Lsw1 658 659Lbadsw: 660 movl #Lsw0,sp@- 661 jbsr _C_LABEL(panic) 662 /*NOTREACHED*/ 663 664/* 665 * cpu_switch() 666 * Hacked for sun3 667 * XXX - Arg 1 is a proc pointer (curproc) but this doesn't use it. 668 * XXX - Sould we use p->p_addr instead of curpcb? -gwr 669 */ 670ENTRY(cpu_switch) 671 movl _C_LABEL(curpcb),a1 | current pcb 672 movw sr,a1@(PCB_PS) | save sr before changing ipl 673#ifdef notyet 674 movl _C_LABEL(curproc),sp@- | remember last proc running 675#endif 676 clrl _C_LABEL(curproc) 677 678Lsw1: 679 /* 680 * Find the highest-priority queue that isn't empty, 681 * then take the first proc from that queue. 682 */ 683 clrl d0 684 lea _C_LABEL(whichqs),a0 685 movl a0@,d1 686Lswchk: 687 btst d0,d1 688 jne Lswfnd 689 addqb #1,d0 690 cmpb #32,d0 691 jne Lswchk 692 jra _C_LABEL(_Idle) 693Lswfnd: 694 movw #PSL_HIGHIPL,sr | lock out interrupts 695 movl a0@,d1 | and check again... 696 bclr d0,d1 697 jeq Lsw1 | proc moved, rescan 698 movl d1,a0@ | update whichqs 699 moveq #1,d1 | double check for higher priority 700 lsll d0,d1 | process (which may have snuck in 701 subql #1,d1 | while we were finding this one) 702 andl a0@,d1 703 jeq Lswok | no one got in, continue 704 movl a0@,d1 705 bset d0,d1 | otherwise put this one back 706 movl d1,a0@ 707 jra Lsw1 | and rescan 708Lswok: 709 movl d0,d1 710 lslb #3,d1 | convert queue number to index 711 addl #_qs,d1 | locate queue (q) 712 movl d1,a1 713 cmpl a1@(P_FORW),a1 | anyone on queue? 714 jeq Lbadsw | no, panic 715 movl a1@(P_FORW),a0 | p = q->p_forw 716 movl a0@(P_FORW),a1@(P_FORW) | q->p_forw = p->p_forw 717 movl a0@(P_FORW),a1 | q = p->p_forw 718 movl a0@(P_BACK),a1@(P_BACK) | q->p_back = p->p_back 719 cmpl a0@(P_FORW),d1 | anyone left on queue? 720 jeq Lsw2 | no, skip 721 movl _C_LABEL(whichqs),d1 722 bset d0,d1 | yes, reset bit 723 movl d1,_C_LABEL(whichqs) 724Lsw2: 725 movl a0,_C_LABEL(curproc) 726 clrl _C_LABEL(want_resched) 727#ifdef notyet 728 movl sp@+,a1 | XXX - Make this work! 729 cmpl a0,a1 | switching to same proc? 730 jeq Lswdone | yes, skip save and restore 731#endif 732 /* 733 * Save state of previous process in its pcb. 734 */ 735 movl _C_LABEL(curpcb),a1 736 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 737 movl usp,a2 | grab USP (a2 has been saved) 738 movl a2,a1@(PCB_USP) | and save it 739 740 tstl _C_LABEL(fputype) | Do we have an fpu? 741 jeq Lswnofpsave | No? Then don't try save. 742 lea a1@(PCB_FPCTX),a2 | pointer to FP save area 743 fsave a2@ | save FP state 744 tstb a2@ | null state frame? 745 jeq Lswnofpsave | yes, all done 746 fmovem fp0-fp7,a2@(FPF_REGS) | save FP general regs 747 fmovem fpcr/fpsr/fpi,a2@(FPF_FPCR) | save FP control regs 748Lswnofpsave: 749 750 /* 751 * Now that we have saved all the registers that must be 752 * preserved, we are free to use those registers until 753 * we load the registers for the switched-to process. 754 * In this section, keep: a0=curproc, a1=curpcb 755 */ 756 757#ifdef DIAGNOSTIC 758 tstl a0@(P_WCHAN) 759 jne Lbadsw 760 cmpb #SRUN,a0@(P_STAT) 761 jne Lbadsw 762#endif 763 clrl a0@(P_BACK) | clear back link 764 movl a0@(P_ADDR),a1 | get p_addr 765 movl a1,_C_LABEL(curpcb) 766 767 /* 768 * Load the new VM context (new MMU root pointer) 769 */ 770 movl a0@(P_VMSPACE),a2 | vm = p->p_vmspace 771#ifdef DIAGNOSTIC 772 tstl a2 | vm == VM_MAP_NULL? 773 jeq Lbadsw | panic 774#endif 775#ifdef PMAP_DEBUG 776 /* When debugging just call _pmap_switch(). */ 777 movl a2@(VM_PMAP),a2 | pmap = vm->vm_map.pmap 778 pea a2@ | push pmap 779 jbsr _C_LABEL(_pmap_switch) | _pmap_switch(pmap) 780 addql #4,sp 781 movl _C_LABEL(curpcb),a1 | restore p_addr 782#else 783 /* Otherwise, use this inline version. */ 784 lea _C_LABEL(kernel_crp), a3 | our CPU Root Ptr. (CRP) 785 movl a2@(VM_PMAP),a2 | pmap = vm->vm_map.pmap 786 movl a2@(PM_A_PHYS),d0 | phys = pmap->pm_a_phys 787 cmpl a3@(4),d0 | == kernel_crp.rp_addr ? 788 jeq Lsame_mmuctx | skip loadcrp/flush 789 /* OK, it is a new MMU context. Load it up. */ 790 movl d0,a3@(4) 791 movl #CACHE_CLR,d0 792 movc d0,cacr | invalidate cache(s) 793 pflusha | flush entire TLB 794 pmove a3@,crp | load new user root pointer 795Lsame_mmuctx: 796#endif 797 798 /* 799 * Reload the registers for the new process. 800 * After this point we can only use d0,d1,a0,a1 801 */ 802 moveml a1@(PCB_REGS),#0xFCFC | reload registers 803 movl a1@(PCB_USP),a0 804 movl a0,usp | and USP 805 806 tstl _C_LABEL(fputype) | If we don't have an fpu, 807 jeq Lres_skip | don't try to restore it. 808 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 809 tstb a0@ | null state frame? 810 jeq Lresfprest | yes, easy 811 fmovem a0@(FPF_FPCR),fpcr/fpsr/fpi | restore FP control regs 812 fmovem a0@(FPF_REGS),fp0-fp7 | restore FP general regs 813Lresfprest: 814 frestore a0@ | restore state 815Lres_skip: 816 movw a1@(PCB_PS),d0 | no, restore PS 817#ifdef DIAGNOSTIC 818 btst #13,d0 | supervisor mode? 819 jeq Lbadsw | no? panic! 820#endif 821 movw d0,sr | OK, restore PS 822 moveq #1,d0 | return 1 (for alternate returns) 823 rts 824 825/* 826 * savectx(pcb) 827 * Update pcb, saving current processor state. 828 */ 829ENTRY(savectx) 830 movl sp@(4),a1 831 movw sr,a1@(PCB_PS) 832 movl usp,a0 | grab USP 833 movl a0,a1@(PCB_USP) | and save it 834 moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers 835 836 tstl _C_LABEL(fputype) | Do we have FPU? 837 jeq Lsavedone | No? Then don't save state. 838 lea a1@(PCB_FPCTX),a0 | pointer to FP save area 839 fsave a0@ | save FP state 840 tstb a0@ | null state frame? 841 jeq Lsavedone | yes, all done 842 fmovem fp0-fp7,a0@(FPF_REGS) | save FP general regs 843 fmovem fpcr/fpsr/fpi,a0@(FPF_FPCR) | save FP control regs 844Lsavedone: 845 moveq #0,d0 | return 0 846 rts 847 848/* suline() */ 849 850#ifdef DEBUG 851 .data 852ASGLOBAL(fulltflush) 853 .long 0 854ASGLOBAL(fullcflush) 855 .long 0 856 .text 857#endif 858 859/* 860 * Invalidate entire TLB. 861 */ 862ENTRY(TBIA) 863_C_LABEL(_TBIA): 864 pflusha 865 movl #DC_CLEAR,d0 866 movc d0,cacr | invalidate on-chip d-cache 867 rts 868 869/* 870 * Invalidate any TLB entry for given VA (TB Invalidate Single) 871 */ 872ENTRY(TBIS) 873#ifdef DEBUG 874 tstl _ASM_LABEL(fulltflush) | being conservative? 875 jne _C_LABEL(_TBIA) | yes, flush entire TLB 876#endif 877 movl sp@(4),a0 878 pflush #0,#0,a0@ | flush address from both sides 879 movl #DC_CLEAR,d0 880 movc d0,cacr | invalidate on-chip data cache 881 rts 882 883/* 884 * Invalidate supervisor side of TLB 885 */ 886ENTRY(TBIAS) 887#ifdef DEBUG 888 tstl _ASM_LABEL(fulltflush) | being conservative? 889 jne _C_LABEL(_TBIA) | yes, flush everything 890#endif 891 pflush #4,#4 | flush supervisor TLB entries 892 movl #DC_CLEAR,d0 893 movc d0,cacr | invalidate on-chip d-cache 894 rts 895 896/* 897 * Invalidate user side of TLB 898 */ 899ENTRY(TBIAU) 900#ifdef DEBUG 901 tstl _ASM_LABEL(fulltflush) | being conservative? 902 jne _C_LABEL(_TBIA) | yes, flush everything 903#endif 904 pflush #0,#4 | flush user TLB entries 905 movl #DC_CLEAR,d0 906 movc d0,cacr | invalidate on-chip d-cache 907 rts 908 909/* 910 * Invalidate instruction cache 911 */ 912ENTRY(ICIA) 913 movl #IC_CLEAR,d0 914 movc d0,cacr | invalidate i-cache 915 rts 916 917/* 918 * Invalidate data cache. 919 * NOTE: we do not flush 68030 on-chip cache as there are no aliasing 920 * problems with DC_WA. The only cases we have to worry about are context 921 * switch and TLB changes, both of which are handled "in-line" in resume 922 * and TBI*. 923 */ 924ENTRY(DCIA) 925__DCIA: 926 rts 927 928ENTRY(DCIS) 929__DCIS: 930 rts 931 932/* 933 * Invalidate data cache. 934 */ 935ENTRY(DCIU) 936 movl #DC_CLEAR,d0 937 movc d0,cacr | invalidate on-chip d-cache 938 rts 939 940/* ICPL, ICPP, DCPL, DCPP, DCPA, DCFL, DCFP */ 941 942ENTRY(PCIA) 943 movl #DC_CLEAR,d0 944 movc d0,cacr | invalidate on-chip d-cache 945 rts 946 947ENTRY(ecacheon) 948 rts 949 950ENTRY(ecacheoff) 951 rts 952 953/* 954 * Get callers current SP value. 955 * Note that simply taking the address of a local variable in a C function 956 * doesn't work because callee saved registers may be outside the stack frame 957 * defined by A6 (e.g. GCC generated code). 958 * 959 * [I don't think the ENTRY() macro will do the right thing with this -- glass] 960 */ 961GLOBAL(getsp) 962 movl sp,d0 | get current SP 963 addql #4,d0 | compensate for return address 964 rts 965 966ENTRY(getsfc) 967 movc sfc,d0 968 rts 969 970ENTRY(getdfc) 971 movc dfc,d0 972 rts 973 974ENTRY(getvbr) 975 movc vbr, d0 976 rts 977 978ENTRY(setvbr) 979 movl sp@(4), d0 980 movc d0, vbr 981 rts 982 983/* 984 * Load a new CPU Root Pointer (CRP) into the MMU. 985 * void loadcrp(struct mmu_rootptr *); 986 */ 987ENTRY(loadcrp) 988 movl sp@(4),a0 | arg1: &CRP 989 movl #CACHE_CLR,d0 990 movc d0,cacr | invalidate cache(s) 991 pflusha | flush entire TLB 992 pmove a0@,crp | load new user root pointer 993 rts 994 995/* 996 * Get the physical address of the PTE for a given VA. 997 */ 998ENTRY(ptest_addr) 999 movl sp@(4),a0 | VA 1000 ptestr #5,a0@,#7,a1 | a1 = addr of PTE 1001 movl a1,d0 1002 rts 1003 1004/* 1005 * Set processor priority level calls. Most are implemented with 1006 * inline asm expansions. However, we need one instantiation here 1007 * in case some non-optimized code makes external references. 1008 * Most places will use the inlined functions param.h supplies. 1009 */ 1010 1011ENTRY(_getsr) 1012 clrl d0 1013 movw sr,d0 1014 rts 1015 1016ENTRY(_spl) 1017 clrl d0 1018 movw sr,d0 1019 movl sp@(4),d1 1020 movw d1,sr 1021 rts 1022 1023ENTRY(_splraise) 1024 clrl d0 1025 movw sr,d0 1026 movl d0,d1 1027 andl #PSL_HIGHIPL,d1 | old &= PSL_HIGHIPL 1028 cmpl sp@(4),d1 | (old - new) 1029 bge Lsplr 1030 movl sp@(4),d1 1031 movw d1,sr 1032Lsplr: 1033 rts 1034 1035/* 1036 * Save and restore 68881 state. 1037 */ 1038ENTRY(m68881_save) 1039 movl sp@(4),a0 | save area pointer 1040 fsave a0@ | save state 1041 tstb a0@ | null state frame? 1042 jeq Lm68881sdone | yes, all done 1043 fmovem fp0-fp7,a0@(FPF_REGS) | save FP general regs 1044 fmovem fpcr/fpsr/fpi,a0@(FPF_FPCR) | save FP control regs 1045Lm68881sdone: 1046 rts 1047 1048ENTRY(m68881_restore) 1049 movl sp@(4),a0 | save area pointer 1050 tstb a0@ | null state frame? 1051 jeq Lm68881rdone | yes, easy 1052 fmovem a0@(FPF_FPCR),fpcr/fpsr/fpi | restore FP control regs 1053 fmovem a0@(FPF_REGS),fp0-fp7 | restore FP general regs 1054Lm68881rdone: 1055 frestore a0@ | restore state 1056 rts 1057 1058/* 1059 * _delay(unsigned N) 1060 * Delay for at least (N/256) microseconds. 1061 * This routine depends on the variable: delay_divisor 1062 * which should be set based on the CPU clock rate. 1063 * XXX: Currently this is set based on the CPU model, 1064 * XXX: but this should be determined at run time... 1065 */ 1066GLOBAL(_delay) 1067 | d0 = arg = (usecs << 8) 1068 movl sp@(4),d0 1069 | d1 = delay_divisor; 1070 movl _C_LABEL(delay_divisor),d1 1071L_delay: 1072 subl d1,d0 1073 jgt L_delay 1074 rts 1075 1076 1077| Define some addresses, mostly so DDB can print useful info. 1078| Not using _C_LABEL() here because these symbols are never 1079| referenced by any C code, and if the leading underscore 1080| ever goes away, these lines turn into syntax errors... 1081 .set _KERNBASE,KERNBASE 1082 .set _MONSTART,SUN3X_MONSTART 1083 .set _PROM_BASE,SUN3X_PROM_BASE 1084 .set _MONEND,SUN3X_MONEND 1085 1086|The end! 1087