1/* $NetBSD: locore.s,v 1.153 2002/02/04 08:36:36 pk Exp $ */ 2 3/* 4 * Copyright (c) 1996 Paul Kranenburg 5 * Copyright (c) 1996 6 * The President and Fellows of Harvard College. All rights reserved. 7 * Copyright (c) 1992, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * This software was developed by the Computer Systems Engineering group 11 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 12 * contributed to Berkeley. 13 * 14 * All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Lawrence Berkeley Laboratory. 18 * This product includes software developed by Harvard University. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 3. All advertising materials mentioning features or use of this software 29 * must display the following acknowledgement: 30 * This product includes software developed by the University of 31 * California, Berkeley and its contributors. 32 * This product includes software developed by Harvard University. 33 * This product includes software developed by Paul Kranenburg. 34 * 4. Neither the name of the University nor the names of its contributors 35 * may be used to endorse or promote products derived from this software 36 * without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * 50 * @(#)locore.s 8.4 (Berkeley) 12/10/93 51 */ 52 53#include "opt_ddb.h" 54#include "opt_kgdb.h" 55#include "opt_compat_svr4.h" 56#include "opt_compat_sunos.h" 57#include "opt_multiprocessor.h" 58#include "opt_lockdebug.h" 59 60#include "assym.h" 61#include <machine/param.h> 62#include <machine/asm.h> 63#include <sparc/sparc/intreg.h> 64#include <sparc/sparc/timerreg.h> 65#include <sparc/sparc/vaddrs.h> 66#ifdef notyet 67#include <sparc/dev/zsreg.h> 68#endif 69#include <machine/ctlreg.h> 70#include <machine/psl.h> 71#include <machine/signal.h> 72#include <machine/trap.h> 73#include <sys/syscall.h> 74 75/* 76 * GNU assembler does not understand `.empty' directive; Sun assembler 77 * gripes about labels without it. To allow cross-compilation using 78 * the Sun assembler, and because .empty directives are useful documentation, 79 * we use this trick. 80 */ 81#ifdef SUN_AS 82#define EMPTY .empty 83#else 84#define EMPTY /* .empty */ 85#endif 86 87/* use as needed to align things on longword boundaries */ 88#define _ALIGN .align 4 89 90/* 91 * CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if 92 * a function is to call C code. It should be just 64, but Sun defined 93 * their frame with space to hold arguments 0 through 5 (plus some junk), 94 * and varargs routines (such as printf) demand this, and gcc uses this 95 * area at times anyway. 96 */ 97#define CCFSZ 96 98 99/* 100 * A handy macro for maintaining instrumentation counters. 101 * Note that this clobbers %o0 and %o1. Normal usage is 102 * something like: 103 * foointr: 104 * TRAP_SETUP(...) ! makes %o registers safe 105 * INCR(cnt+V_FOO) ! count a foo 106 */ 107#define INCR(what) \ 108 sethi %hi(what), %o0; \ 109 ld [%o0 + %lo(what)], %o1; \ 110 inc %o1; \ 111 st %o1, [%o0 + %lo(what)] 112 113/* 114 * Another handy macro: load one register window, given `base' address. 115 * This can be either a simple register (e.g., %sp) or include an initial 116 * offset (e.g., %g6 + PCB_RW). 117 */ 118#define LOADWIN(addr) \ 119 ldd [addr], %l0; \ 120 ldd [addr + 8], %l2; \ 121 ldd [addr + 16], %l4; \ 122 ldd [addr + 24], %l6; \ 123 ldd [addr + 32], %i0; \ 124 ldd [addr + 40], %i2; \ 125 ldd [addr + 48], %i4; \ 126 ldd [addr + 56], %i6 127 128/* 129 * To return from trap we need the two-instruction sequence 130 * `jmp %l1; rett %l2', which is defined here for convenience. 131 */ 132#define RETT jmp %l1; rett %l2 133 134 .data 135/* 136 * The interrupt stack. 137 * 138 * This is the very first thing in the data segment, and therefore has 139 * the lowest kernel stack address. We count on this in the interrupt 140 * trap-frame setup code, since we may need to switch from the kernel 141 * stack to the interrupt stack (iff we are not already on the interrupt 142 * stack). One sethi+cmp is all we need since this is so carefully 143 * arranged. 144 * 145 * In SMP kernels, each CPU has its own interrupt stack and the computation 146 * to determine whether we're already on the interrupt stack is slightly 147 * more time consuming (see INTR_SETUP() below). 148 */ 149 .globl _C_LABEL(intstack) 150 .globl _C_LABEL(eintstack) 151_C_LABEL(intstack): 152 .skip INT_STACK_SIZE ! 16k = 128 128-byte stack frames 153_C_LABEL(eintstack): 154 155_EINTSTACKP = CPUINFO_VA + CPUINFO_EINTSTACK 156 157/* 158 * CPUINFO_VA is a CPU-local virtual address; cpi->ci_self is a global 159 * virtual address for the same structure. It must be stored in p->p_cpu 160 * upon context switch. 161 */ 162_CISELFP = CPUINFO_VA + CPUINFO_SELF 163_CIFLAGS = CPUINFO_VA + CPUINFO_FLAGS 164 165/* 166 * When a process exits and its u. area goes away, we set cpcb to point 167 * to this `u.', leaving us with something to use for an interrupt stack, 168 * and letting all the register save code have a pcb_uw to examine. 169 * This is also carefully arranged (to come just before u0, so that 170 * process 0's kernel stack can quietly overrun into it during bootup, if 171 * we feel like doing that). 172 */ 173 .globl _C_LABEL(idle_u) 174_C_LABEL(idle_u): 175 .skip USPACE 176/* 177 * On SMP kernels, there's an idle u-area for each CPU and we must 178 * read its location from cpuinfo. 179 */ 180IDLE_UP = CPUINFO_VA + CPUINFO_IDLE_U 181 182/* 183 * Process 0's u. 184 * 185 * This must be aligned on an 8 byte boundary. 186 */ 187 .globl _C_LABEL(u0) 188_C_LABEL(u0): .skip USPACE 189estack0: 190 191#ifdef KGDB 192/* 193 * Another item that must be aligned, easiest to put it here. 194 */ 195KGDB_STACK_SIZE = 2048 196 .globl _C_LABEL(kgdb_stack) 197_C_LABEL(kgdb_stack): 198 .skip KGDB_STACK_SIZE ! hope this is enough 199#endif 200 201/* 202 * cpcb points to the current pcb (and hence u. area). 203 * Initially this is the special one. 204 */ 205cpcb = CPUINFO_VA + CPUINFO_CURPCB 206 207/* curproc points to the current process that has the CPU */ 208curproc = CPUINFO_VA + CPUINFO_CURPROC 209 210/* 211 * cputyp is the current cpu type, used to distinguish between 212 * the many variations of different sun4* machines. It contains 213 * the value CPU_SUN4, CPU_SUN4C, or CPU_SUN4M. 214 */ 215 .globl _C_LABEL(cputyp) 216_C_LABEL(cputyp): 217 .word 1 218 219#if defined(SUN4C) || defined(SUN4M) 220cputypval: 221 .asciz "sun4c" 222 .ascii " " 223cputypvar: 224 .asciz "compatible" 225 _ALIGN 226#endif 227 228/* 229 * There variables are pointed to by the cpp symbols PGSHIFT, NBPG, 230 * and PGOFSET. 231 */ 232 .globl _C_LABEL(pgshift), _C_LABEL(nbpg), _C_LABEL(pgofset) 233_C_LABEL(pgshift): 234 .word 0 235_C_LABEL(nbpg): 236 .word 0 237_C_LABEL(pgofset): 238 .word 0 239 240 .globl _C_LABEL(trapbase) 241_C_LABEL(trapbase): 242 .word 0 243 244#if 0 245#if defined(SUN4M) 246_mapme: 247 .asciz "0 0 f8000000 15c6a0 map-pages" 248#endif 249#endif 250 251#if !defined(SUN4M) 252sun4m_notsup: 253 .asciz "cr .( NetBSD/sparc: this kernel does not support the sun4m) cr" 254#endif 255#if !defined(SUN4C) 256sun4c_notsup: 257 .asciz "cr .( NetBSD/sparc: this kernel does not support the sun4c) cr" 258#endif 259#if !defined(SUN4) 260sun4_notsup: 261 ! the extra characters at the end are to ensure the zs fifo drains 262 ! before we halt. Sick, eh? 263 .asciz "NetBSD/sparc: this kernel does not support the sun4\n\r \b" 264#endif 265 _ALIGN 266 267 .text 268 269/* 270 * The first thing in the real text segment is the trap vector table, 271 * which must be aligned on a 4096 byte boundary. The text segment 272 * starts beyond page 0 of KERNBASE so that there is a red zone 273 * between user and kernel space. Since the boot ROM loads us at 274 * PROM_LOADADDR, it is far easier to start at KERNBASE+PROM_LOADADDR than to 275 * buck the trend. This is two or four pages in (depending on if 276 * pagesize is 8192 or 4096). We place two items in this area: 277 * the message buffer (phys addr 0) and the cpu_softc structure for 278 * the first processor in the system (phys addr 0x2000). 279 * Because the message buffer is in our "red zone" between user and 280 * kernel space we remap it in configure() to another location and 281 * invalidate the mapping at KERNBASE. 282 */ 283 284/* 285 * Each trap has room for four instructions, of which one perforce must 286 * be a branch. On entry the hardware has copied pc and npc to %l1 and 287 * %l2 respectively. We use two more to read the psr into %l0, and to 288 * put the trap type value into %l3 (with a few exceptions below). 289 * We could read the trap type field of %tbr later in the code instead, 290 * but there is no need, and that would require more instructions 291 * (read+mask, vs 1 `mov' here). 292 * 293 * I used to generate these numbers by address arithmetic, but gas's 294 * expression evaluator has about as much sense as your average slug 295 * (oddly enough, the code looks about as slimy too). Thus, all the 296 * trap numbers are given as arguments to the trap macros. This means 297 * there is one line per trap. Sigh. 298 * 299 * Note that only the local registers may be used, since the trap 300 * window is potentially the last window. Its `in' registers are 301 * the previous window's outs (as usual), but more important, its 302 * `out' registers may be in use as the `topmost' window's `in' registers. 303 * The global registers are of course verboten (well, until we save 304 * them away). 305 * 306 * Hardware interrupt vectors can be `linked'---the linkage is to regular 307 * C code---or rewired to fast in-window handlers. The latter are good 308 * for unbuffered hardware like the Zilog serial chip and the AMD audio 309 * chip, where many interrupts can be handled trivially with pseudo-DMA or 310 * similar. Only one `fast' interrupt can be used per level, however, and 311 * direct and `fast' interrupts are incompatible. Routines in intr.c 312 * handle setting these, with optional paranoia. 313 */ 314 315 /* regular vectored traps */ 316#define VTRAP(type, label) \ 317 mov (type), %l3; b label; mov %psr, %l0; nop 318 319 /* hardware interrupts (can be linked or made `fast') */ 320#define HARDINT44C(lev) \ 321 mov (lev), %l3; b _C_LABEL(sparc_interrupt44c); mov %psr, %l0; nop 322 323 /* hardware interrupts (can be linked or made `fast') */ 324#define HARDINT4M(lev) \ 325 mov (lev), %l3; b _C_LABEL(sparc_interrupt4m); mov %psr, %l0; nop 326 327 /* software interrupts (may not be made direct, sorry---but you 328 should not be using them trivially anyway) */ 329#define SOFTINT44C(lev, bit) \ 330 mov (lev), %l3; mov (bit), %l4; b softintr_sun44c; mov %psr, %l0 331 332 /* There's no SOFTINT4M(): both hard and soft vector the same way */ 333 334 /* traps that just call trap() */ 335#define TRAP(type) VTRAP(type, slowtrap) 336 337 /* architecturally undefined traps (cause panic) */ 338#define UTRAP(type) VTRAP(type, slowtrap) 339 340 /* software undefined traps (may be replaced) */ 341#define STRAP(type) VTRAP(type, slowtrap) 342 343/* breakpoint acts differently under kgdb */ 344#ifdef KGDB 345#define BPT VTRAP(T_BREAKPOINT, bpt) 346#define BPT_KGDB_EXEC VTRAP(T_KGDB_EXEC, bpt) 347#else 348#define BPT TRAP(T_BREAKPOINT) 349#define BPT_KGDB_EXEC TRAP(T_KGDB_EXEC) 350#endif 351 352/* special high-speed 1-instruction-shaved-off traps (get nothing in %l3) */ 353#define SYSCALL b _C_LABEL(_syscall); mov %psr, %l0; nop; nop 354#define WINDOW_OF b window_of; mov %psr, %l0; nop; nop 355#define WINDOW_UF b window_uf; mov %psr, %l0; nop; nop 356#ifdef notyet 357#define ZS_INTERRUPT b zshard; mov %psr, %l0; nop; nop 358#else 359#define ZS_INTERRUPT44C HARDINT44C(12) 360#define ZS_INTERRUPT4M HARDINT4M(12) 361#endif 362 363 .globl _ASM_LABEL(start), _C_LABEL(kernel_text) 364 _C_LABEL(kernel_text) = start ! for kvm_mkdb(8) 365_ASM_LABEL(start): 366/* 367 * Put sun4 traptable first, since it needs the most stringent aligment (8192) 368 */ 369#if defined(SUN4) 370trapbase_sun4: 371 /* trap 0 is special since we cannot receive it */ 372 b dostart; nop; nop; nop ! 00 = reset (fake) 373 VTRAP(T_TEXTFAULT, memfault_sun4) ! 01 = instr. fetch fault 374 TRAP(T_ILLINST) ! 02 = illegal instruction 375 TRAP(T_PRIVINST) ! 03 = privileged instruction 376 TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr 377 WINDOW_OF ! 05 = window overflow 378 WINDOW_UF ! 06 = window underflow 379 TRAP(T_ALIGN) ! 07 = address alignment error 380 VTRAP(T_FPE, fp_exception) ! 08 = fp exception 381 VTRAP(T_DATAFAULT, memfault_sun4) ! 09 = data fetch fault 382 TRAP(T_TAGOF) ! 0a = tag overflow 383 UTRAP(0x0b) 384 UTRAP(0x0c) 385 UTRAP(0x0d) 386 UTRAP(0x0e) 387 UTRAP(0x0f) 388 UTRAP(0x10) 389 SOFTINT44C(1, IE_L1) ! 11 = level 1 interrupt 390 HARDINT44C(2) ! 12 = level 2 interrupt 391 HARDINT44C(3) ! 13 = level 3 interrupt 392 SOFTINT44C(4, IE_L4) ! 14 = level 4 interrupt 393 HARDINT44C(5) ! 15 = level 5 interrupt 394 SOFTINT44C(6, IE_L6) ! 16 = level 6 interrupt 395 HARDINT44C(7) ! 17 = level 7 interrupt 396 HARDINT44C(8) ! 18 = level 8 interrupt 397 HARDINT44C(9) ! 19 = level 9 interrupt 398 HARDINT44C(10) ! 1a = level 10 interrupt 399 HARDINT44C(11) ! 1b = level 11 interrupt 400 ZS_INTERRUPT44C ! 1c = level 12 (zs) interrupt 401 HARDINT44C(13) ! 1d = level 13 interrupt 402 HARDINT44C(14) ! 1e = level 14 interrupt 403 VTRAP(15, nmi_sun4) ! 1f = nonmaskable interrupt 404 UTRAP(0x20) 405 UTRAP(0x21) 406 UTRAP(0x22) 407 UTRAP(0x23) 408 TRAP(T_CPDISABLED) ! 24 = coprocessor instr, EC bit off in psr 409 UTRAP(0x25) 410 UTRAP(0x26) 411 UTRAP(0x27) 412 TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception 413 UTRAP(0x29) 414 UTRAP(0x2a) 415 UTRAP(0x2b) 416 UTRAP(0x2c) 417 UTRAP(0x2d) 418 UTRAP(0x2e) 419 UTRAP(0x2f) 420 UTRAP(0x30) 421 UTRAP(0x31) 422 UTRAP(0x32) 423 UTRAP(0x33) 424 UTRAP(0x34) 425 UTRAP(0x35) 426 UTRAP(0x36) 427 UTRAP(0x37) 428 UTRAP(0x38) 429 UTRAP(0x39) 430 UTRAP(0x3a) 431 UTRAP(0x3b) 432 UTRAP(0x3c) 433 UTRAP(0x3d) 434 UTRAP(0x3e) 435 UTRAP(0x3f) 436 UTRAP(0x40) 437 UTRAP(0x41) 438 UTRAP(0x42) 439 UTRAP(0x43) 440 UTRAP(0x44) 441 UTRAP(0x45) 442 UTRAP(0x46) 443 UTRAP(0x47) 444 UTRAP(0x48) 445 UTRAP(0x49) 446 UTRAP(0x4a) 447 UTRAP(0x4b) 448 UTRAP(0x4c) 449 UTRAP(0x4d) 450 UTRAP(0x4e) 451 UTRAP(0x4f) 452 UTRAP(0x50) 453 UTRAP(0x51) 454 UTRAP(0x52) 455 UTRAP(0x53) 456 UTRAP(0x54) 457 UTRAP(0x55) 458 UTRAP(0x56) 459 UTRAP(0x57) 460 UTRAP(0x58) 461 UTRAP(0x59) 462 UTRAP(0x5a) 463 UTRAP(0x5b) 464 UTRAP(0x5c) 465 UTRAP(0x5d) 466 UTRAP(0x5e) 467 UTRAP(0x5f) 468 UTRAP(0x60) 469 UTRAP(0x61) 470 UTRAP(0x62) 471 UTRAP(0x63) 472 UTRAP(0x64) 473 UTRAP(0x65) 474 UTRAP(0x66) 475 UTRAP(0x67) 476 UTRAP(0x68) 477 UTRAP(0x69) 478 UTRAP(0x6a) 479 UTRAP(0x6b) 480 UTRAP(0x6c) 481 UTRAP(0x6d) 482 UTRAP(0x6e) 483 UTRAP(0x6f) 484 UTRAP(0x70) 485 UTRAP(0x71) 486 UTRAP(0x72) 487 UTRAP(0x73) 488 UTRAP(0x74) 489 UTRAP(0x75) 490 UTRAP(0x76) 491 UTRAP(0x77) 492 UTRAP(0x78) 493 UTRAP(0x79) 494 UTRAP(0x7a) 495 UTRAP(0x7b) 496 UTRAP(0x7c) 497 UTRAP(0x7d) 498 UTRAP(0x7e) 499 UTRAP(0x7f) 500 SYSCALL ! 80 = sun syscall 501 BPT ! 81 = pseudo breakpoint instruction 502 TRAP(T_DIV0) ! 82 = divide by zero 503 TRAP(T_FLUSHWIN) ! 83 = flush windows 504 TRAP(T_CLEANWIN) ! 84 = provide clean windows 505 TRAP(T_RANGECHECK) ! 85 = ??? 506 TRAP(T_FIXALIGN) ! 86 = fix up unaligned accesses 507 TRAP(T_INTOF) ! 87 = integer overflow 508 SYSCALL ! 88 = svr4 syscall 509 SYSCALL ! 89 = bsd syscall 510 BPT_KGDB_EXEC ! 8a = enter kernel gdb on kernel startup 511 STRAP(0x8b) 512 STRAP(0x8c) 513 STRAP(0x8d) 514 STRAP(0x8e) 515 STRAP(0x8f) 516 STRAP(0x90) 517 STRAP(0x91) 518 STRAP(0x92) 519 STRAP(0x93) 520 STRAP(0x94) 521 STRAP(0x95) 522 STRAP(0x96) 523 STRAP(0x97) 524 STRAP(0x98) 525 STRAP(0x99) 526 STRAP(0x9a) 527 STRAP(0x9b) 528 STRAP(0x9c) 529 STRAP(0x9d) 530 STRAP(0x9e) 531 STRAP(0x9f) 532 STRAP(0xa0) 533 STRAP(0xa1) 534 STRAP(0xa2) 535 STRAP(0xa3) 536 STRAP(0xa4) 537 STRAP(0xa5) 538 STRAP(0xa6) 539 STRAP(0xa7) 540 STRAP(0xa8) 541 STRAP(0xa9) 542 STRAP(0xaa) 543 STRAP(0xab) 544 STRAP(0xac) 545 STRAP(0xad) 546 STRAP(0xae) 547 STRAP(0xaf) 548 STRAP(0xb0) 549 STRAP(0xb1) 550 STRAP(0xb2) 551 STRAP(0xb3) 552 STRAP(0xb4) 553 STRAP(0xb5) 554 STRAP(0xb6) 555 STRAP(0xb7) 556 STRAP(0xb8) 557 STRAP(0xb9) 558 STRAP(0xba) 559 STRAP(0xbb) 560 STRAP(0xbc) 561 STRAP(0xbd) 562 STRAP(0xbe) 563 STRAP(0xbf) 564 STRAP(0xc0) 565 STRAP(0xc1) 566 STRAP(0xc2) 567 STRAP(0xc3) 568 STRAP(0xc4) 569 STRAP(0xc5) 570 STRAP(0xc6) 571 STRAP(0xc7) 572 STRAP(0xc8) 573 STRAP(0xc9) 574 STRAP(0xca) 575 STRAP(0xcb) 576 STRAP(0xcc) 577 STRAP(0xcd) 578 STRAP(0xce) 579 STRAP(0xcf) 580 STRAP(0xd0) 581 STRAP(0xd1) 582 STRAP(0xd2) 583 STRAP(0xd3) 584 STRAP(0xd4) 585 STRAP(0xd5) 586 STRAP(0xd6) 587 STRAP(0xd7) 588 STRAP(0xd8) 589 STRAP(0xd9) 590 STRAP(0xda) 591 STRAP(0xdb) 592 STRAP(0xdc) 593 STRAP(0xdd) 594 STRAP(0xde) 595 STRAP(0xdf) 596 STRAP(0xe0) 597 STRAP(0xe1) 598 STRAP(0xe2) 599 STRAP(0xe3) 600 STRAP(0xe4) 601 STRAP(0xe5) 602 STRAP(0xe6) 603 STRAP(0xe7) 604 STRAP(0xe8) 605 STRAP(0xe9) 606 STRAP(0xea) 607 STRAP(0xeb) 608 STRAP(0xec) 609 STRAP(0xed) 610 STRAP(0xee) 611 STRAP(0xef) 612 STRAP(0xf0) 613 STRAP(0xf1) 614 STRAP(0xf2) 615 STRAP(0xf3) 616 STRAP(0xf4) 617 STRAP(0xf5) 618 STRAP(0xf6) 619 STRAP(0xf7) 620 STRAP(0xf8) 621 STRAP(0xf9) 622 STRAP(0xfa) 623 STRAP(0xfb) 624 STRAP(0xfc) 625 STRAP(0xfd) 626 STRAP(0xfe) 627 STRAP(0xff) 628#endif 629 630#if defined(SUN4C) 631trapbase_sun4c: 632/* trap 0 is special since we cannot receive it */ 633 b dostart; nop; nop; nop ! 00 = reset (fake) 634 VTRAP(T_TEXTFAULT, memfault_sun4c) ! 01 = instr. fetch fault 635 TRAP(T_ILLINST) ! 02 = illegal instruction 636 TRAP(T_PRIVINST) ! 03 = privileged instruction 637 TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr 638 WINDOW_OF ! 05 = window overflow 639 WINDOW_UF ! 06 = window underflow 640 TRAP(T_ALIGN) ! 07 = address alignment error 641 VTRAP(T_FPE, fp_exception) ! 08 = fp exception 642 VTRAP(T_DATAFAULT, memfault_sun4c) ! 09 = data fetch fault 643 TRAP(T_TAGOF) ! 0a = tag overflow 644 UTRAP(0x0b) 645 UTRAP(0x0c) 646 UTRAP(0x0d) 647 UTRAP(0x0e) 648 UTRAP(0x0f) 649 UTRAP(0x10) 650 SOFTINT44C(1, IE_L1) ! 11 = level 1 interrupt 651 HARDINT44C(2) ! 12 = level 2 interrupt 652 HARDINT44C(3) ! 13 = level 3 interrupt 653 SOFTINT44C(4, IE_L4) ! 14 = level 4 interrupt 654 HARDINT44C(5) ! 15 = level 5 interrupt 655 SOFTINT44C(6, IE_L6) ! 16 = level 6 interrupt 656 HARDINT44C(7) ! 17 = level 7 interrupt 657 HARDINT44C(8) ! 18 = level 8 interrupt 658 HARDINT44C(9) ! 19 = level 9 interrupt 659 HARDINT44C(10) ! 1a = level 10 interrupt 660 HARDINT44C(11) ! 1b = level 11 interrupt 661 ZS_INTERRUPT44C ! 1c = level 12 (zs) interrupt 662 HARDINT44C(13) ! 1d = level 13 interrupt 663 HARDINT44C(14) ! 1e = level 14 interrupt 664 VTRAP(15, nmi_sun4c) ! 1f = nonmaskable interrupt 665 UTRAP(0x20) 666 UTRAP(0x21) 667 UTRAP(0x22) 668 UTRAP(0x23) 669 TRAP(T_CPDISABLED) ! 24 = coprocessor instr, EC bit off in psr 670 UTRAP(0x25) 671 UTRAP(0x26) 672 UTRAP(0x27) 673 TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception 674 UTRAP(0x29) 675 UTRAP(0x2a) 676 UTRAP(0x2b) 677 UTRAP(0x2c) 678 UTRAP(0x2d) 679 UTRAP(0x2e) 680 UTRAP(0x2f) 681 UTRAP(0x30) 682 UTRAP(0x31) 683 UTRAP(0x32) 684 UTRAP(0x33) 685 UTRAP(0x34) 686 UTRAP(0x35) 687 UTRAP(0x36) 688 UTRAP(0x37) 689 UTRAP(0x38) 690 UTRAP(0x39) 691 UTRAP(0x3a) 692 UTRAP(0x3b) 693 UTRAP(0x3c) 694 UTRAP(0x3d) 695 UTRAP(0x3e) 696 UTRAP(0x3f) 697 UTRAP(0x40) 698 UTRAP(0x41) 699 UTRAP(0x42) 700 UTRAP(0x43) 701 UTRAP(0x44) 702 UTRAP(0x45) 703 UTRAP(0x46) 704 UTRAP(0x47) 705 UTRAP(0x48) 706 UTRAP(0x49) 707 UTRAP(0x4a) 708 UTRAP(0x4b) 709 UTRAP(0x4c) 710 UTRAP(0x4d) 711 UTRAP(0x4e) 712 UTRAP(0x4f) 713 UTRAP(0x50) 714 UTRAP(0x51) 715 UTRAP(0x52) 716 UTRAP(0x53) 717 UTRAP(0x54) 718 UTRAP(0x55) 719 UTRAP(0x56) 720 UTRAP(0x57) 721 UTRAP(0x58) 722 UTRAP(0x59) 723 UTRAP(0x5a) 724 UTRAP(0x5b) 725 UTRAP(0x5c) 726 UTRAP(0x5d) 727 UTRAP(0x5e) 728 UTRAP(0x5f) 729 UTRAP(0x60) 730 UTRAP(0x61) 731 UTRAP(0x62) 732 UTRAP(0x63) 733 UTRAP(0x64) 734 UTRAP(0x65) 735 UTRAP(0x66) 736 UTRAP(0x67) 737 UTRAP(0x68) 738 UTRAP(0x69) 739 UTRAP(0x6a) 740 UTRAP(0x6b) 741 UTRAP(0x6c) 742 UTRAP(0x6d) 743 UTRAP(0x6e) 744 UTRAP(0x6f) 745 UTRAP(0x70) 746 UTRAP(0x71) 747 UTRAP(0x72) 748 UTRAP(0x73) 749 UTRAP(0x74) 750 UTRAP(0x75) 751 UTRAP(0x76) 752 UTRAP(0x77) 753 UTRAP(0x78) 754 UTRAP(0x79) 755 UTRAP(0x7a) 756 UTRAP(0x7b) 757 UTRAP(0x7c) 758 UTRAP(0x7d) 759 UTRAP(0x7e) 760 UTRAP(0x7f) 761 SYSCALL ! 80 = sun syscall 762 BPT ! 81 = pseudo breakpoint instruction 763 TRAP(T_DIV0) ! 82 = divide by zero 764 TRAP(T_FLUSHWIN) ! 83 = flush windows 765 TRAP(T_CLEANWIN) ! 84 = provide clean windows 766 TRAP(T_RANGECHECK) ! 85 = ??? 767 TRAP(T_FIXALIGN) ! 86 = fix up unaligned accesses 768 TRAP(T_INTOF) ! 87 = integer overflow 769 SYSCALL ! 88 = svr4 syscall 770 SYSCALL ! 89 = bsd syscall 771 BPT_KGDB_EXEC ! 8a = enter kernel gdb on kernel startup 772 STRAP(0x8b) 773 STRAP(0x8c) 774 STRAP(0x8d) 775 STRAP(0x8e) 776 STRAP(0x8f) 777 STRAP(0x90) 778 STRAP(0x91) 779 STRAP(0x92) 780 STRAP(0x93) 781 STRAP(0x94) 782 STRAP(0x95) 783 STRAP(0x96) 784 STRAP(0x97) 785 STRAP(0x98) 786 STRAP(0x99) 787 STRAP(0x9a) 788 STRAP(0x9b) 789 STRAP(0x9c) 790 STRAP(0x9d) 791 STRAP(0x9e) 792 STRAP(0x9f) 793 STRAP(0xa0) 794 STRAP(0xa1) 795 STRAP(0xa2) 796 STRAP(0xa3) 797 STRAP(0xa4) 798 STRAP(0xa5) 799 STRAP(0xa6) 800 STRAP(0xa7) 801 STRAP(0xa8) 802 STRAP(0xa9) 803 STRAP(0xaa) 804 STRAP(0xab) 805 STRAP(0xac) 806 STRAP(0xad) 807 STRAP(0xae) 808 STRAP(0xaf) 809 STRAP(0xb0) 810 STRAP(0xb1) 811 STRAP(0xb2) 812 STRAP(0xb3) 813 STRAP(0xb4) 814 STRAP(0xb5) 815 STRAP(0xb6) 816 STRAP(0xb7) 817 STRAP(0xb8) 818 STRAP(0xb9) 819 STRAP(0xba) 820 STRAP(0xbb) 821 STRAP(0xbc) 822 STRAP(0xbd) 823 STRAP(0xbe) 824 STRAP(0xbf) 825 STRAP(0xc0) 826 STRAP(0xc1) 827 STRAP(0xc2) 828 STRAP(0xc3) 829 STRAP(0xc4) 830 STRAP(0xc5) 831 STRAP(0xc6) 832 STRAP(0xc7) 833 STRAP(0xc8) 834 STRAP(0xc9) 835 STRAP(0xca) 836 STRAP(0xcb) 837 STRAP(0xcc) 838 STRAP(0xcd) 839 STRAP(0xce) 840 STRAP(0xcf) 841 STRAP(0xd0) 842 STRAP(0xd1) 843 STRAP(0xd2) 844 STRAP(0xd3) 845 STRAP(0xd4) 846 STRAP(0xd5) 847 STRAP(0xd6) 848 STRAP(0xd7) 849 STRAP(0xd8) 850 STRAP(0xd9) 851 STRAP(0xda) 852 STRAP(0xdb) 853 STRAP(0xdc) 854 STRAP(0xdd) 855 STRAP(0xde) 856 STRAP(0xdf) 857 STRAP(0xe0) 858 STRAP(0xe1) 859 STRAP(0xe2) 860 STRAP(0xe3) 861 STRAP(0xe4) 862 STRAP(0xe5) 863 STRAP(0xe6) 864 STRAP(0xe7) 865 STRAP(0xe8) 866 STRAP(0xe9) 867 STRAP(0xea) 868 STRAP(0xeb) 869 STRAP(0xec) 870 STRAP(0xed) 871 STRAP(0xee) 872 STRAP(0xef) 873 STRAP(0xf0) 874 STRAP(0xf1) 875 STRAP(0xf2) 876 STRAP(0xf3) 877 STRAP(0xf4) 878 STRAP(0xf5) 879 STRAP(0xf6) 880 STRAP(0xf7) 881 STRAP(0xf8) 882 STRAP(0xf9) 883 STRAP(0xfa) 884 STRAP(0xfb) 885 STRAP(0xfc) 886 STRAP(0xfd) 887 STRAP(0xfe) 888 STRAP(0xff) 889#endif 890 891#if defined(SUN4M) 892trapbase_sun4m: 893/* trap 0 is special since we cannot receive it */ 894 b dostart; nop; nop; nop ! 00 = reset (fake) 895 VTRAP(T_TEXTFAULT, memfault_sun4m) ! 01 = instr. fetch fault 896 TRAP(T_ILLINST) ! 02 = illegal instruction 897 TRAP(T_PRIVINST) ! 03 = privileged instruction 898 TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr 899 WINDOW_OF ! 05 = window overflow 900 WINDOW_UF ! 06 = window underflow 901 TRAP(T_ALIGN) ! 07 = address alignment error 902 VTRAP(T_FPE, fp_exception) ! 08 = fp exception 903 VTRAP(T_DATAFAULT, memfault_sun4m) ! 09 = data fetch fault 904 TRAP(T_TAGOF) ! 0a = tag overflow 905 UTRAP(0x0b) 906 UTRAP(0x0c) 907 UTRAP(0x0d) 908 UTRAP(0x0e) 909 UTRAP(0x0f) 910 UTRAP(0x10) 911 HARDINT4M(1) ! 11 = level 1 interrupt 912 HARDINT4M(2) ! 12 = level 2 interrupt 913 HARDINT4M(3) ! 13 = level 3 interrupt 914 HARDINT4M(4) ! 14 = level 4 interrupt 915 HARDINT4M(5) ! 15 = level 5 interrupt 916 HARDINT4M(6) ! 16 = level 6 interrupt 917 HARDINT4M(7) ! 17 = level 7 interrupt 918 HARDINT4M(8) ! 18 = level 8 interrupt 919 HARDINT4M(9) ! 19 = level 9 interrupt 920 HARDINT4M(10) ! 1a = level 10 interrupt 921 HARDINT4M(11) ! 1b = level 11 interrupt 922 ZS_INTERRUPT4M ! 1c = level 12 (zs) interrupt 923 HARDINT4M(13) ! 1d = level 13 interrupt 924 HARDINT4M(14) ! 1e = level 14 interrupt 925 VTRAP(15, nmi_sun4m) ! 1f = nonmaskable interrupt 926 UTRAP(0x20) 927 UTRAP(0x21) 928 UTRAP(0x22) 929 UTRAP(0x23) 930 TRAP(T_CPDISABLED) ! 24 = coprocessor instr, EC bit off in psr 931 UTRAP(0x25) 932 UTRAP(0x26) 933 UTRAP(0x27) 934 TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception 935 UTRAP(0x29) 936 UTRAP(0x2a) 937 VTRAP(T_STOREBUFFAULT, memfault_sun4m) ! 2b = SuperSPARC store buffer fault 938 UTRAP(0x2c) 939 UTRAP(0x2d) 940 UTRAP(0x2e) 941 UTRAP(0x2f) 942 UTRAP(0x30) 943 UTRAP(0x31) 944 UTRAP(0x32) 945 UTRAP(0x33) 946 UTRAP(0x34) 947 UTRAP(0x35) 948 UTRAP(0x36) 949 UTRAP(0x37) 950 UTRAP(0x38) 951 UTRAP(0x39) 952 UTRAP(0x3a) 953 UTRAP(0x3b) 954 UTRAP(0x3c) 955 UTRAP(0x3d) 956 UTRAP(0x3e) 957 UTRAP(0x3f) 958 UTRAP(0x40) 959 UTRAP(0x41) 960 UTRAP(0x42) 961 UTRAP(0x43) 962 UTRAP(0x44) 963 UTRAP(0x45) 964 UTRAP(0x46) 965 UTRAP(0x47) 966 UTRAP(0x48) 967 UTRAP(0x49) 968 UTRAP(0x4a) 969 UTRAP(0x4b) 970 UTRAP(0x4c) 971 UTRAP(0x4d) 972 UTRAP(0x4e) 973 UTRAP(0x4f) 974 UTRAP(0x50) 975 UTRAP(0x51) 976 UTRAP(0x52) 977 UTRAP(0x53) 978 UTRAP(0x54) 979 UTRAP(0x55) 980 UTRAP(0x56) 981 UTRAP(0x57) 982 UTRAP(0x58) 983 UTRAP(0x59) 984 UTRAP(0x5a) 985 UTRAP(0x5b) 986 UTRAP(0x5c) 987 UTRAP(0x5d) 988 UTRAP(0x5e) 989 UTRAP(0x5f) 990 UTRAP(0x60) 991 UTRAP(0x61) 992 UTRAP(0x62) 993 UTRAP(0x63) 994 UTRAP(0x64) 995 UTRAP(0x65) 996 UTRAP(0x66) 997 UTRAP(0x67) 998 UTRAP(0x68) 999 UTRAP(0x69) 1000 UTRAP(0x6a) 1001 UTRAP(0x6b) 1002 UTRAP(0x6c) 1003 UTRAP(0x6d) 1004 UTRAP(0x6e) 1005 UTRAP(0x6f) 1006 UTRAP(0x70) 1007 UTRAP(0x71) 1008 UTRAP(0x72) 1009 UTRAP(0x73) 1010 UTRAP(0x74) 1011 UTRAP(0x75) 1012 UTRAP(0x76) 1013 UTRAP(0x77) 1014 UTRAP(0x78) 1015 UTRAP(0x79) 1016 UTRAP(0x7a) 1017 UTRAP(0x7b) 1018 UTRAP(0x7c) 1019 UTRAP(0x7d) 1020 UTRAP(0x7e) 1021 UTRAP(0x7f) 1022 SYSCALL ! 80 = sun syscall 1023 BPT ! 81 = pseudo breakpoint instruction 1024 TRAP(T_DIV0) ! 82 = divide by zero 1025 TRAP(T_FLUSHWIN) ! 83 = flush windows 1026 TRAP(T_CLEANWIN) ! 84 = provide clean windows 1027 TRAP(T_RANGECHECK) ! 85 = ??? 1028 TRAP(T_FIXALIGN) ! 86 = fix up unaligned accesses 1029 TRAP(T_INTOF) ! 87 = integer overflow 1030 SYSCALL ! 88 = svr4 syscall 1031 SYSCALL ! 89 = bsd syscall 1032 BPT_KGDB_EXEC ! 8a = enter kernel gdb on kernel startup 1033 STRAP(0x8b) 1034 STRAP(0x8c) 1035 STRAP(0x8d) 1036 STRAP(0x8e) 1037 STRAP(0x8f) 1038 STRAP(0x90) 1039 STRAP(0x91) 1040 STRAP(0x92) 1041 STRAP(0x93) 1042 STRAP(0x94) 1043 STRAP(0x95) 1044 STRAP(0x96) 1045 STRAP(0x97) 1046 STRAP(0x98) 1047 STRAP(0x99) 1048 STRAP(0x9a) 1049 STRAP(0x9b) 1050 STRAP(0x9c) 1051 STRAP(0x9d) 1052 STRAP(0x9e) 1053 STRAP(0x9f) 1054 STRAP(0xa0) 1055 STRAP(0xa1) 1056 STRAP(0xa2) 1057 STRAP(0xa3) 1058 STRAP(0xa4) 1059 STRAP(0xa5) 1060 STRAP(0xa6) 1061 STRAP(0xa7) 1062 STRAP(0xa8) 1063 STRAP(0xa9) 1064 STRAP(0xaa) 1065 STRAP(0xab) 1066 STRAP(0xac) 1067 STRAP(0xad) 1068 STRAP(0xae) 1069 STRAP(0xaf) 1070 STRAP(0xb0) 1071 STRAP(0xb1) 1072 STRAP(0xb2) 1073 STRAP(0xb3) 1074 STRAP(0xb4) 1075 STRAP(0xb5) 1076 STRAP(0xb6) 1077 STRAP(0xb7) 1078 STRAP(0xb8) 1079 STRAP(0xb9) 1080 STRAP(0xba) 1081 STRAP(0xbb) 1082 STRAP(0xbc) 1083 STRAP(0xbd) 1084 STRAP(0xbe) 1085 STRAP(0xbf) 1086 STRAP(0xc0) 1087 STRAP(0xc1) 1088 STRAP(0xc2) 1089 STRAP(0xc3) 1090 STRAP(0xc4) 1091 STRAP(0xc5) 1092 STRAP(0xc6) 1093 STRAP(0xc7) 1094 STRAP(0xc8) 1095 STRAP(0xc9) 1096 STRAP(0xca) 1097 STRAP(0xcb) 1098 STRAP(0xcc) 1099 STRAP(0xcd) 1100 STRAP(0xce) 1101 STRAP(0xcf) 1102 STRAP(0xd0) 1103 STRAP(0xd1) 1104 STRAP(0xd2) 1105 STRAP(0xd3) 1106 STRAP(0xd4) 1107 STRAP(0xd5) 1108 STRAP(0xd6) 1109 STRAP(0xd7) 1110 STRAP(0xd8) 1111 STRAP(0xd9) 1112 STRAP(0xda) 1113 STRAP(0xdb) 1114 STRAP(0xdc) 1115 STRAP(0xdd) 1116 STRAP(0xde) 1117 STRAP(0xdf) 1118 STRAP(0xe0) 1119 STRAP(0xe1) 1120 STRAP(0xe2) 1121 STRAP(0xe3) 1122 STRAP(0xe4) 1123 STRAP(0xe5) 1124 STRAP(0xe6) 1125 STRAP(0xe7) 1126 STRAP(0xe8) 1127 STRAP(0xe9) 1128 STRAP(0xea) 1129 STRAP(0xeb) 1130 STRAP(0xec) 1131 STRAP(0xed) 1132 STRAP(0xee) 1133 STRAP(0xef) 1134 STRAP(0xf0) 1135 STRAP(0xf1) 1136 STRAP(0xf2) 1137 STRAP(0xf3) 1138 STRAP(0xf4) 1139 STRAP(0xf5) 1140 STRAP(0xf6) 1141 STRAP(0xf7) 1142 STRAP(0xf8) 1143 STRAP(0xf9) 1144 STRAP(0xfa) 1145 STRAP(0xfb) 1146 STRAP(0xfc) 1147 STRAP(0xfd) 1148 STRAP(0xfe) 1149 STRAP(0xff) 1150#endif 1151 1152/* 1153 * Pad the trap table to max page size. 1154 * Trap table size is 0x100 * 4instr * 4byte/instr = 4096 bytes; 1155 * need to .skip 4096 to pad to page size iff. the number of trap tables 1156 * defined above is odd. 1157 */ 1158#if (defined(SUN4) + defined(SUN4C) + defined(SUN4M)) % 2 == 1 1159 .skip 4096 1160#endif 1161 1162#ifdef DEBUG 1163/* 1164 * A hardware red zone is impossible. We simulate one in software by 1165 * keeping a `red zone' pointer; if %sp becomes less than this, we panic. 1166 * This is expensive and is only enabled when debugging. 1167 */ 1168 1169/* `redzone' is located in the per-CPU information structure */ 1170_redzone = CPUINFO_VA + CPUINFO_REDZONE 1171 .data 1172#define REDSTACK 2048 /* size of `panic: stack overflow' region */ 1173_redstack: 1174 .skip REDSTACK 1175 .text 1176Lpanic_red: 1177 .asciz "stack overflow" 1178 _ALIGN 1179 1180 /* set stack pointer redzone to base+minstack; alters base */ 1181#define SET_SP_REDZONE(base, tmp) \ 1182 add base, REDSIZE, base; \ 1183 sethi %hi(_redzone), tmp; \ 1184 st base, [tmp + %lo(_redzone)] 1185 1186 /* variant with a constant */ 1187#define SET_SP_REDZONE_CONST(const, tmp1, tmp2) \ 1188 set (const) + REDSIZE, tmp1; \ 1189 sethi %hi(_redzone), tmp2; \ 1190 st tmp1, [tmp2 + %lo(_redzone)] 1191 1192 /* variant with a variable & offset */ 1193#define SET_SP_REDZONE_VAR(var, offset, tmp1, tmp2) \ 1194 sethi %hi(var), tmp1; \ 1195 ld [tmp1 + %lo(var)], tmp1; \ 1196 sethi %hi(offset), tmp2; \ 1197 add tmp1, tmp2, tmp1; \ 1198 SET_SP_REDZONE(tmp1, tmp2) 1199 1200 /* check stack pointer against redzone (uses two temps) */ 1201#define CHECK_SP_REDZONE(t1, t2) \ 1202 sethi %hi(_redzone), t1; \ 1203 ld [t1 + %lo(_redzone)], t2; \ 1204 cmp %sp, t2; /* if sp >= t2, not in red zone */ \ 1205 bgeu 7f; nop; /* and can continue normally */ \ 1206 /* move to panic stack */ \ 1207 st %g0, [t1 + %lo(_redzone)]; \ 1208 set _redstack + REDSTACK - 96, %sp; \ 1209 /* prevent panic() from lowering ipl */ \ 1210 sethi %hi(_C_LABEL(panicstr)), t2; \ 1211 set Lpanic_red, t2; \ 1212 st t2, [t1 + %lo(_C_LABEL(panicstr))]; \ 1213 rd %psr, t1; /* t1 = splhigh() */ \ 1214 or t1, PSR_PIL, t2; \ 1215 wr t2, 0, %psr; \ 1216 wr t2, PSR_ET, %psr; /* turn on traps */ \ 1217 nop; nop; nop; \ 1218 save %sp, -CCFSZ, %sp; /* preserve current window */ \ 1219 sethi %hi(Lpanic_red), %o0; \ 1220 call _C_LABEL(panic); or %o0, %lo(Lpanic_red), %o0; \ 12217: 1222 1223#else 1224 1225#define SET_SP_REDZONE(base, tmp) 1226#define SET_SP_REDZONE_CONST(const, t1, t2) 1227#define SET_SP_REDZONE_VAR(var, offset, t1, t2) 1228#define CHECK_SP_REDZONE(t1, t2) 1229#endif /* DEBUG */ 1230 1231/* 1232 * The window code must verify user stack addresses before using them. 1233 * A user stack pointer is invalid if: 1234 * - it is not on an 8 byte boundary; 1235 * - its pages (a register window, being 64 bytes, can occupy 1236 * two pages) are not readable or writable. 1237 * We define three separate macros here for testing user stack addresses. 1238 * 1239 * PTE_OF_ADDR locates a PTE, branching to a `bad address' 1240 * handler if the stack pointer points into the hole in the 1241 * address space (i.e., top 3 bits are not either all 1 or all 0); 1242 * CMP_PTE_USER_READ compares the located PTE against `user read' mode; 1243 * CMP_PTE_USER_WRITE compares the located PTE against `user write' mode. 1244 * The compares give `equal' if read or write is OK. 1245 * 1246 * Note that the user stack pointer usually points into high addresses 1247 * (top 3 bits all 1), so that is what we check first. 1248 * 1249 * The code below also assumes that PTE_OF_ADDR is safe in a delay 1250 * slot; it is, at it merely sets its `pte' register to a temporary value. 1251 */ 1252#if defined(SUN4) || defined(SUN4C) 1253 /* input: addr, output: pte; aux: bad address label */ 1254#define PTE_OF_ADDR4_4C(addr, pte, bad, page_offset) \ 1255 sra addr, PG_VSHIFT, pte; \ 1256 cmp pte, -1; \ 1257 be,a 1f; andn addr, page_offset, pte; \ 1258 tst pte; \ 1259 bne bad; EMPTY; \ 1260 andn addr, page_offset, pte; \ 12611: 1262 1263 /* input: pte; output: condition codes */ 1264#define CMP_PTE_USER_READ4_4C(pte) \ 1265 lda [pte] ASI_PTE, pte; \ 1266 srl pte, PG_PROTSHIFT, pte; \ 1267 andn pte, (PG_W >> PG_PROTSHIFT), pte; \ 1268 cmp pte, PG_PROTUREAD 1269 1270 /* input: pte; output: condition codes */ 1271#define CMP_PTE_USER_WRITE4_4C(pte) \ 1272 lda [pte] ASI_PTE, pte; \ 1273 srl pte, PG_PROTSHIFT, pte; \ 1274 cmp pte, PG_PROTUWRITE 1275#endif 1276 1277/* 1278 * The Sun4M does not have the memory hole that the 4C does. Thus all 1279 * we need to do here is clear the page offset from addr. 1280 */ 1281#if defined(SUN4M) 1282#define PTE_OF_ADDR4M(addr, pte, bad, page_offset) \ 1283 andn addr, page_offset, pte 1284 1285/* 1286 * After obtaining the PTE through ASI_SRMMUFP, we read the Sync Fault 1287 * Status register. This is necessary on Hypersparcs which stores and 1288 * locks the fault address and status registers if the translation 1289 * fails (thanks to Chris Torek for finding this quirk). 1290 */ 1291/* note: pmap currently does not use the PPROT_R_R and PPROT_RW_RW cases */ 1292#define CMP_PTE_USER_READ4M(pte, tmp) \ 1293 or pte, ASI_SRMMUFP_L3, pte; \ 1294 lda [pte] ASI_SRMMUFP, pte; \ 1295 set SRMMU_SFSR, tmp; \ 1296 and pte, (SRMMU_TETYPE | SRMMU_PROT_MASK), pte; \ 1297 cmp pte, (SRMMU_TEPTE | PPROT_RWX_RWX); \ 1298 be 8f; \ 1299 lda [tmp] ASI_SRMMU, %g0; \ 1300 cmp pte, (SRMMU_TEPTE | PPROT_RX_RX); \ 13018: 1302 1303 1304/* note: PTE bit 4 set implies no user writes */ 1305#define CMP_PTE_USER_WRITE4M(pte, tmp) \ 1306 or pte, ASI_SRMMUFP_L3, pte; \ 1307 lda [pte] ASI_SRMMUFP, pte; \ 1308 set SRMMU_SFSR, tmp; \ 1309 lda [tmp] ASI_SRMMU, %g0; \ 1310 and pte, (SRMMU_TETYPE | 0x14), pte; \ 1311 cmp pte, (SRMMU_TEPTE | PPROT_WRITE) 1312#endif /* 4m */ 1313 1314#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4)) 1315 1316#define PTE_OF_ADDR(addr, pte, bad, page_offset, label) \ 1317 PTE_OF_ADDR4M(addr, pte, bad, page_offset) 1318#define CMP_PTE_USER_WRITE(pte, tmp, label) CMP_PTE_USER_WRITE4M(pte,tmp) 1319#define CMP_PTE_USER_READ(pte, tmp, label) CMP_PTE_USER_READ4M(pte,tmp) 1320 1321#elif (defined(SUN4C) || defined(SUN4)) && !defined(SUN4M) 1322 1323#define PTE_OF_ADDR(addr, pte, bad, page_offset,label) \ 1324 PTE_OF_ADDR4_4C(addr, pte, bad, page_offset) 1325#define CMP_PTE_USER_WRITE(pte, tmp, label) CMP_PTE_USER_WRITE4_4C(pte) 1326#define CMP_PTE_USER_READ(pte, tmp, label) CMP_PTE_USER_READ4_4C(pte) 1327 1328#else /* both defined, ugh */ 1329 1330#define PTE_OF_ADDR(addr, pte, bad, page_offset, label) \ 1331label: b,a 2f; \ 1332 PTE_OF_ADDR4M(addr, pte, bad, page_offset); \ 1333 b,a 3f; \ 13342: \ 1335 PTE_OF_ADDR4_4C(addr, pte, bad, page_offset); \ 13363: 1337 1338#define CMP_PTE_USER_READ(pte, tmp, label) \ 1339label: b,a 1f; \ 1340 CMP_PTE_USER_READ4M(pte,tmp); \ 1341 b,a 2f; \ 13421: \ 1343 CMP_PTE_USER_READ4_4C(pte); \ 13442: 1345 1346#define CMP_PTE_USER_WRITE(pte, tmp, label) \ 1347label: b,a 1f; \ 1348 CMP_PTE_USER_WRITE4M(pte,tmp); \ 1349 b,a 2f; \ 13501: \ 1351 CMP_PTE_USER_WRITE4_4C(pte); \ 13522: 1353#endif 1354 1355 1356/* 1357 * The calculations in PTE_OF_ADDR and CMP_PTE_USER_* are rather slow: 1358 * in particular, according to Gordon Irlam of the University of Adelaide 1359 * in Australia, these consume at least 18 cycles on an SS1 and 37 on an 1360 * SS2. Hence, we try to avoid them in the common case. 1361 * 1362 * A chunk of 64 bytes is on a single page if and only if: 1363 * 1364 * ((base + 64 - 1) & ~(NBPG-1)) == (base & ~(NBPG-1)) 1365 * 1366 * Equivalently (and faster to test), the low order bits (base & 4095) must 1367 * be small enough so that the sum (base + 63) does not carry out into the 1368 * upper page-address bits, i.e., 1369 * 1370 * (base & (NBPG-1)) < (NBPG - 63) 1371 * 1372 * so we allow testing that here. This macro is also assumed to be safe 1373 * in a delay slot (modulo overwriting its temporary). 1374 */ 1375#define SLT_IF_1PAGE_RW(addr, tmp, page_offset) \ 1376 and addr, page_offset, tmp; \ 1377 sub page_offset, 62, page_offset; \ 1378 cmp tmp, page_offset 1379 1380/* 1381 * Every trap that enables traps must set up stack space. 1382 * If the trap is from user mode, this involves switching to the kernel 1383 * stack for the current process, and we must also set cpcb->pcb_uw 1384 * so that the window overflow handler can tell user windows from kernel 1385 * windows. 1386 * 1387 * The number of user windows is: 1388 * 1389 * cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows 1390 * 1391 * (where pcb_wim = log2(current %wim) and CWP = low 5 bits of %psr). 1392 * We compute this expression by table lookup in uwtab[CWP - pcb_wim], 1393 * which has been set up as: 1394 * 1395 * for i in [-nwin+1 .. nwin-1] 1396 * uwtab[i] = (nwin - 1 - i) % nwin; 1397 * 1398 * (If you do not believe this works, try it for yourself.) 1399 * 1400 * We also keep one or two more tables: 1401 * 1402 * for i in 0..nwin-1 1403 * wmask[i] = 1 << ((i + 1) % nwindows); 1404 * 1405 * wmask[CWP] tells whether a `rett' would return into the invalid window. 1406 */ 1407 .data 1408 .skip 32 ! alignment byte & negative indicies 1409uwtab: .skip 32 ! u_char uwtab[-31..31]; 1410wmask: .skip 32 ! u_char wmask[0..31]; 1411 1412 .text 1413/* 1414 * Things begin to grow uglier.... 1415 * 1416 * Each trap handler may (always) be running in the trap window. 1417 * If this is the case, it cannot enable further traps until it writes 1418 * the register windows into the stack (or, if the stack is no good, 1419 * the current pcb). 1420 * 1421 * ASSUMPTIONS: TRAP_SETUP() is called with: 1422 * %l0 = %psr 1423 * %l1 = return pc 1424 * %l2 = return npc 1425 * %l3 = (some value that must not be altered) 1426 * which means we have 4 registers to work with. 1427 * 1428 * The `stackspace' argument is the number of stack bytes to allocate 1429 * for register-saving, and must be at least -64 (and typically more, 1430 * for global registers and %y). 1431 * 1432 * Trapframes should use -CCFSZ-80. (80 = sizeof(struct trapframe); 1433 * see trap.h. This basically means EVERYONE. Interrupt frames could 1434 * get away with less, but currently do not.) 1435 * 1436 * The basic outline here is: 1437 * 1438 * if (trap came from kernel mode) { 1439 * if (we are in the trap window) 1440 * save it away; 1441 * %sp = %fp - stackspace; 1442 * } else { 1443 * compute the number of user windows; 1444 * if (we are in the trap window) 1445 * save it away; 1446 * %sp = (top of kernel stack) - stackspace; 1447 * } 1448 * 1449 * Again, the number of user windows is: 1450 * 1451 * cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows 1452 * 1453 * (where pcb_wim = log2(current %wim) and CWP is the low 5 bits of %psr), 1454 * and this is computed as `uwtab[CWP - pcb_wim]'. 1455 * 1456 * NOTE: if you change this code, you will have to look carefully 1457 * at the window overflow and underflow handlers and make sure they 1458 * have similar changes made as needed. 1459 */ 1460#define CALL_CLEAN_TRAP_WINDOW \ 1461 sethi %hi(clean_trap_window), %l7; \ 1462 jmpl %l7 + %lo(clean_trap_window), %l4; \ 1463 mov %g7, %l7 /* save %g7 in %l7 for clean_trap_window */ 1464 1465#define TRAP_SETUP(stackspace) \ 1466 rd %wim, %l4; \ 1467 mov 1, %l5; \ 1468 sll %l5, %l0, %l5; \ 1469 btst PSR_PS, %l0; \ 1470 bz 1f; \ 1471 btst %l5, %l4; \ 1472 /* came from kernel mode; cond codes indicate trap window */ \ 1473 bz,a 3f; \ 1474 add %fp, stackspace, %sp; /* want to just set %sp */ \ 1475 CALL_CLEAN_TRAP_WINDOW; /* but maybe need to clean first */ \ 1476 b 3f; \ 1477 add %fp, stackspace, %sp; \ 14781: \ 1479 /* came from user mode: compute pcb_nw */ \ 1480 sethi %hi(cpcb), %l6; \ 1481 ld [%l6 + %lo(cpcb)], %l6; \ 1482 ld [%l6 + PCB_WIM], %l5; \ 1483 and %l0, 31, %l4; \ 1484 sub %l4, %l5, %l5; \ 1485 set uwtab, %l4; \ 1486 ldub [%l4 + %l5], %l5; \ 1487 st %l5, [%l6 + PCB_UW]; \ 1488 /* cond codes still indicate whether in trap window */ \ 1489 bz,a 2f; \ 1490 sethi %hi(USPACE+(stackspace)), %l5; \ 1491 /* yes, in trap window; must clean it */ \ 1492 CALL_CLEAN_TRAP_WINDOW; \ 1493 sethi %hi(cpcb), %l6; \ 1494 ld [%l6 + %lo(cpcb)], %l6; \ 1495 sethi %hi(USPACE+(stackspace)), %l5; \ 14962: \ 1497 /* trap window is (now) clean: set %sp */ \ 1498 or %l5, %lo(USPACE+(stackspace)), %l5; \ 1499 add %l6, %l5, %sp; \ 1500 SET_SP_REDZONE(%l6, %l5); \ 15013: \ 1502 CHECK_SP_REDZONE(%l6, %l5) 1503 1504/* 1505 * Interrupt setup is almost exactly like trap setup, but we need to 1506 * go to the interrupt stack if (a) we came from user mode or (b) we 1507 * came from kernel mode on the kernel stack. 1508 */ 1509#if defined(MULTIPROCESSOR) 1510/* 1511 * SMP kernels: read `eintstack' from cpuinfo structure. Since the 1512 * location of the interrupt stack is not known in advance, we need 1513 * to check the current %fp against both ends of the stack space. 1514 */ 1515#define INTR_SETUP(stackspace) \ 1516 rd %wim, %l4; \ 1517 mov 1, %l5; \ 1518 sll %l5, %l0, %l5; \ 1519 btst PSR_PS, %l0; \ 1520 bz 1f; \ 1521 btst %l5, %l4; \ 1522 /* came from kernel mode; cond codes still indicate trap window */ \ 1523 bz,a 0f; \ 1524 sethi %hi(_EINTSTACKP), %l7; \ 1525 CALL_CLEAN_TRAP_WINDOW; \ 1526 sethi %hi(_EINTSTACKP), %l7; \ 15270: /* now if not intstack > %fp >= eintstack, we were on the kernel stack */ \ 1528 ld [%l7 + %lo(_EINTSTACKP)], %l7; \ 1529 cmp %fp, %l7; \ 1530 bge,a 3f; /* %fp >= eintstack */ \ 1531 add %l7, stackspace, %sp; /* so switch to intstack */ \ 1532 sethi %hi(INT_STACK_SIZE), %l6; \ 1533 sub %l7, %l6, %l6; \ 1534 cmp %fp, %l6; \ 1535 blu,a 3f; /* %fp < intstack */ \ 1536 add %l7, stackspace, %sp; /* so switch to intstack */ \ 1537 b 4f; \ 1538 add %fp, stackspace, %sp; /* else stay on intstack */ \ 15391: \ 1540 /* came from user mode: compute pcb_nw */ \ 1541 sethi %hi(cpcb), %l6; \ 1542 ld [%l6 + %lo(cpcb)], %l6; \ 1543 ld [%l6 + PCB_WIM], %l5; \ 1544 and %l0, 31, %l4; \ 1545 sub %l4, %l5, %l5; \ 1546 set uwtab, %l4; \ 1547 ldub [%l4 + %l5], %l5; \ 1548 st %l5, [%l6 + PCB_UW]; \ 1549 /* cond codes still indicate whether in trap window */ \ 1550 bz,a 2f; \ 1551 sethi %hi(_EINTSTACKP), %l7; \ 1552 /* yes, in trap window; must save regs */ \ 1553 CALL_CLEAN_TRAP_WINDOW; \ 1554 sethi %hi(_EINTSTACKP), %l7; \ 15552: \ 1556 ld [%l7 + %lo(_EINTSTACKP)], %l7; \ 1557 add %l7, stackspace, %sp; \ 15583: \ 1559 SET_SP_REDZONE_VAR(_EINTSTACKP, -INT_STACK_SIZE, %l6, %l5); \ 15604: \ 1561 CHECK_SP_REDZONE(%l6, %l5) 1562 1563#else /* MULTIPROCESSOR */ 1564 1565#define INTR_SETUP(stackspace) \ 1566 rd %wim, %l4; \ 1567 mov 1, %l5; \ 1568 sll %l5, %l0, %l5; \ 1569 btst PSR_PS, %l0; \ 1570 bz 1f; \ 1571 btst %l5, %l4; \ 1572 /* came from kernel mode; cond codes still indicate trap window */ \ 1573 bz,a 0f; \ 1574 sethi %hi(_C_LABEL(eintstack)), %l7; \ 1575 CALL_CLEAN_TRAP_WINDOW; \ 1576 sethi %hi(_C_LABEL(eintstack)), %l7; \ 15770: /* now if %fp >= eintstack, we were on the kernel stack */ \ 1578 cmp %fp, %l7; \ 1579 bge,a 3f; \ 1580 add %l7, stackspace, %sp; /* so switch to intstack */ \ 1581 b 4f; \ 1582 add %fp, stackspace, %sp; /* else stay on intstack */ \ 15831: \ 1584 /* came from user mode: compute pcb_nw */ \ 1585 sethi %hi(cpcb), %l6; \ 1586 ld [%l6 + %lo(cpcb)], %l6; \ 1587 ld [%l6 + PCB_WIM], %l5; \ 1588 and %l0, 31, %l4; \ 1589 sub %l4, %l5, %l5; \ 1590 set uwtab, %l4; \ 1591 ldub [%l4 + %l5], %l5; \ 1592 st %l5, [%l6 + PCB_UW]; \ 1593 /* cond codes still indicate whether in trap window */ \ 1594 bz,a 2f; \ 1595 sethi %hi(_C_LABEL(eintstack)), %l7; \ 1596 /* yes, in trap window; must save regs */ \ 1597 CALL_CLEAN_TRAP_WINDOW; \ 1598 sethi %hi(_C_LABEL(eintstack)), %l7; \ 15992: \ 1600 add %l7, stackspace, %sp; \ 16013: \ 1602 SET_SP_REDZONE_CONST(_C_LABEL(intstack), %l6, %l5); \ 16034: \ 1604 CHECK_SP_REDZONE(%l6, %l5) 1605#endif /* MULTIPROCESSOR */ 1606 1607/* 1608 * Handler for making the trap window shiny clean. 1609 * 1610 * On entry: 1611 * cpcb->pcb_nw = number of user windows 1612 * %l0 = %psr 1613 * %l1 must not be clobbered 1614 * %l2 must not be clobbered 1615 * %l3 must not be clobbered 1616 * %l4 = address for `return' 1617 * %l7 = saved %g7 (we put this in a delay slot above, to save work) 1618 * 1619 * On return: 1620 * %wim has changed, along with cpcb->pcb_wim 1621 * %g7 has been restored 1622 * 1623 * Normally, we push only one window. 1624 */ 1625clean_trap_window: 1626 mov %g5, %l5 ! save %g5 1627 mov %g6, %l6 ! ... and %g6 1628/* mov %g7, %l7 ! ... and %g7 (already done for us) */ 1629 sethi %hi(cpcb), %g6 ! get current pcb 1630 ld [%g6 + %lo(cpcb)], %g6 1631 1632 /* Figure out whether it is a user window (cpcb->pcb_uw > 0). */ 1633 ld [%g6 + PCB_UW], %g7 1634 deccc %g7 1635 bge ctw_user 1636 save %g0, %g0, %g0 ! in any case, enter window to save 1637 1638 /* The window to be pushed is a kernel window. */ 1639 std %l0, [%sp + (0*8)] 1640ctw_merge: 1641 std %l2, [%sp + (1*8)] 1642 std %l4, [%sp + (2*8)] 1643 std %l6, [%sp + (3*8)] 1644 std %i0, [%sp + (4*8)] 1645 std %i2, [%sp + (5*8)] 1646 std %i4, [%sp + (6*8)] 1647 std %i6, [%sp + (7*8)] 1648 1649 /* Set up new window invalid mask, and update cpcb->pcb_wim. */ 1650 rd %psr, %g7 ! g7 = (junk << 5) + new_cwp 1651 mov 1, %g5 ! g5 = 1 << new_cwp; 1652 sll %g5, %g7, %g5 1653 wr %g5, 0, %wim ! setwim(g5); 1654 and %g7, 31, %g7 ! cpcb->pcb_wim = g7 & 31; 1655 sethi %hi(cpcb), %g6 ! re-get current pcb 1656 ld [%g6 + %lo(cpcb)], %g6 1657 st %g7, [%g6 + PCB_WIM] 1658 nop 1659 restore ! back to trap window 1660 1661 mov %l5, %g5 ! restore g5 1662 mov %l6, %g6 ! ... and g6 1663 jmp %l4 + 8 ! return to caller 1664 mov %l7, %g7 ! ... and g7 1665 /* NOTREACHED */ 1666 1667ctw_user: 1668 /* 1669 * The window to be pushed is a user window. 1670 * We must verify the stack pointer (alignment & permissions). 1671 * See comments above definition of PTE_OF_ADDR. 1672 */ 1673 st %g7, [%g6 + PCB_UW] ! cpcb->pcb_uw--; 1674 btst 7, %sp ! if not aligned, 1675 bne ctw_invalid ! choke on it 1676 EMPTY 1677 1678 sethi %hi(_C_LABEL(pgofset)), %g6 ! trash %g6=curpcb 1679 ld [%g6 + %lo(_C_LABEL(pgofset))], %g6 1680 PTE_OF_ADDR(%sp, %g7, ctw_invalid, %g6, NOP_ON_4M_1) 1681 CMP_PTE_USER_WRITE(%g7, %g5, NOP_ON_4M_2) ! likewise if not writable 1682 bne ctw_invalid 1683 EMPTY 1684 /* Note side-effect of SLT_IF_1PAGE_RW: decrements %g6 by 62 */ 1685 SLT_IF_1PAGE_RW(%sp, %g7, %g6) 1686 bl,a ctw_merge ! all ok if only 1 1687 std %l0, [%sp] 1688 add %sp, 7*8, %g5 ! check last addr too 1689 add %g6, 62, %g6 ! restore %g6 to `pgofset' 1690 PTE_OF_ADDR(%g5, %g7, ctw_invalid, %g6, NOP_ON_4M_3) 1691 CMP_PTE_USER_WRITE(%g7, %g6, NOP_ON_4M_4) 1692 be,a ctw_merge ! all ok: store <l0,l1> and merge 1693 std %l0, [%sp] 1694 1695 /* 1696 * The window we wanted to push could not be pushed. 1697 * Instead, save ALL user windows into the pcb. 1698 * We will notice later that we did this, when we 1699 * get ready to return from our trap or syscall. 1700 * 1701 * The code here is run rarely and need not be optimal. 1702 */ 1703ctw_invalid: 1704 /* 1705 * Reread cpcb->pcb_uw. We decremented this earlier, 1706 * so it is off by one. 1707 */ 1708 sethi %hi(cpcb), %g6 ! re-get current pcb 1709 ld [%g6 + %lo(cpcb)], %g6 1710 1711 ld [%g6 + PCB_UW], %g7 ! (number of user windows) - 1 1712 add %g6, PCB_RW, %g5 1713 1714 /* save g7+1 windows, starting with the current one */ 17151: ! do { 1716 std %l0, [%g5 + (0*8)] ! rw->rw_local[0] = l0; 1717 std %l2, [%g5 + (1*8)] ! ... 1718 std %l4, [%g5 + (2*8)] 1719 std %l6, [%g5 + (3*8)] 1720 std %i0, [%g5 + (4*8)] 1721 std %i2, [%g5 + (5*8)] 1722 std %i4, [%g5 + (6*8)] 1723 std %i6, [%g5 + (7*8)] 1724 deccc %g7 ! if (n > 0) save(), rw++; 1725 bge,a 1b ! } while (--n >= 0); 1726 save %g5, 64, %g5 1727 1728 /* stash sp for bottommost window */ 1729 st %sp, [%g5 + 64 + (7*8)] 1730 1731 /* set up new wim */ 1732 rd %psr, %g7 ! g7 = (junk << 5) + new_cwp; 1733 mov 1, %g5 ! g5 = 1 << new_cwp; 1734 sll %g5, %g7, %g5 1735 wr %g5, 0, %wim ! wim = g5; 1736 and %g7, 31, %g7 1737 st %g7, [%g6 + PCB_WIM] ! cpcb->pcb_wim = new_cwp; 1738 1739 /* fix up pcb fields */ 1740 ld [%g6 + PCB_UW], %g7 ! n = cpcb->pcb_uw; 1741 add %g7, 1, %g5 1742 st %g5, [%g6 + PCB_NSAVED] ! cpcb->pcb_nsaved = n + 1; 1743 st %g0, [%g6 + PCB_UW] ! cpcb->pcb_uw = 0; 1744 1745 /* return to trap window */ 17461: deccc %g7 ! do { 1747 bge 1b ! restore(); 1748 restore ! } while (--n >= 0); 1749 1750 mov %l5, %g5 ! restore g5, g6, & g7, and return 1751 mov %l6, %g6 1752 jmp %l4 + 8 1753 mov %l7, %g7 1754 /* NOTREACHED */ 1755 1756 1757/* 1758 * Each memory access (text or data) fault, from user or kernel mode, 1759 * comes here. We read the error register and figure out what has 1760 * happened. 1761 * 1762 * This cannot be done from C code since we must not enable traps (and 1763 * hence may not use the `save' instruction) until we have decided that 1764 * the error is or is not an asynchronous one that showed up after a 1765 * synchronous error, but which must be handled before the sync err. 1766 * 1767 * Most memory faults are user mode text or data faults, which can cause 1768 * signal delivery or ptracing, for which we must build a full trapframe. 1769 * It does not seem worthwhile to work to avoid this in the other cases, 1770 * so we store all the %g registers on the stack immediately. 1771 * 1772 * On entry: 1773 * %l0 = %psr 1774 * %l1 = return pc 1775 * %l2 = return npc 1776 * %l3 = T_TEXTFAULT or T_DATAFAULT 1777 * 1778 * Internal: 1779 * %l4 = %y, until we call mem_access_fault (then onto trapframe) 1780 * %l5 = IE_reg_addr, if async mem error 1781 * 1782 */ 1783 1784#if defined(SUN4) 1785memfault_sun4: 1786 TRAP_SETUP(-CCFSZ-80) 1787 INCR(_C_LABEL(uvmexp)+V_FAULTS) ! cnt.v_faults++ (clobbers %o0,%o1) 1788 1789 st %g1, [%sp + CCFSZ + 20] ! save g1 1790 rd %y, %l4 ! save y 1791 1792 /* 1793 * registers: 1794 * memerr.ctrl = memory error control reg., error if 0x80 set 1795 * memerr.vaddr = address of memory error 1796 * buserr = basically just like sun4c sync error reg but 1797 * no SER_WRITE bit (have to figure out from code). 1798 */ 1799 set _C_LABEL(par_err_reg), %o0 ! memerr ctrl addr -- XXX mapped? 1800 ld [%o0], %o0 ! get it 1801 std %g2, [%sp + CCFSZ + 24] ! save g2, g3 1802 ld [%o0], %o1 ! memerr ctrl register 1803 inc 4, %o0 ! now VA of memerr vaddr register 1804 std %g4, [%sp + CCFSZ + 32] ! (sneak g4,g5 in here) 1805 ld [%o0], %o2 ! memerr virt addr 1806 st %g0, [%o0] ! NOTE: this clears latching!!! 1807 btst ME_REG_IERR, %o1 ! memory error? 1808 ! XXX this value may not be correct 1809 ! as I got some parity errors and the 1810 ! correct bits were not on? 1811 std %g6, [%sp + CCFSZ + 40] 1812 bz,a 0f ! no, just a regular fault 1813 wr %l0, PSR_ET, %psr ! (and reenable traps) 1814 1815 /* memory error = death for now XXX */ 1816 clr %o3 1817 clr %o4 1818 call _C_LABEL(memerr4_4c) ! memerr(0, ser, sva, 0, 0) 1819 clr %o0 1820 call _C_LABEL(prom_halt) 1821 nop 1822 18230: 1824 /* 1825 * have to make SUN4 emulate SUN4C. 4C code expects 1826 * SER in %o1 and the offending VA in %o2, everything else is ok. 1827 * (must figure out if SER_WRITE should be set) 1828 */ 1829 set AC_BUS_ERR, %o0 ! bus error register 1830 cmp %l3, T_TEXTFAULT ! text fault always on PC 1831 be normal_mem_fault ! go 1832 lduba [%o0] ASI_CONTROL, %o1 ! get its value 1833 1834#define STORE_BIT 21 /* bit that indicates a store instruction for sparc */ 1835 ld [%l1], %o3 ! offending instruction in %o3 [l1=pc] 1836 srl %o3, STORE_BIT, %o3 ! get load/store bit (wont fit simm13) 1837 btst 1, %o3 ! test for store operation 1838 1839 bz normal_mem_fault ! if (z) is a load (so branch) 1840 sethi %hi(SER_WRITE), %o5 ! damn SER_WRITE wont fit simm13 1841! or %lo(SER_WRITE), %o5, %o5! not necessary since %lo is zero 1842 or %o5, %o1, %o1 ! set SER_WRITE 1843#if defined(SUN4C) || defined(SUN4M) 1844 ba,a normal_mem_fault 1845 !!nop ! XXX make efficient later 1846#endif /* SUN4C || SUN4M */ 1847#endif /* SUN4 */ 1848 1849memfault_sun4c: 1850#if defined(SUN4C) 1851 TRAP_SETUP(-CCFSZ-80) 1852 INCR(_C_LABEL(uvmexp)+V_FAULTS) ! cnt.v_faults++ (clobbers %o0,%o1) 1853 1854 st %g1, [%sp + CCFSZ + 20] ! save g1 1855 rd %y, %l4 ! save y 1856 1857 /* 1858 * We know about the layout of the error registers here. 1859 * addr reg 1860 * ---- --- 1861 * a AC_SYNC_ERR 1862 * a+4 AC_SYNC_VA 1863 * a+8 AC_ASYNC_ERR 1864 * a+12 AC_ASYNC_VA 1865 */ 1866 1867#if AC_SYNC_ERR + 4 != AC_SYNC_VA || \ 1868 AC_SYNC_ERR + 8 != AC_ASYNC_ERR || AC_SYNC_ERR + 12 != AC_ASYNC_VA 1869 help help help ! I, I, I wanna be a lifeguard 1870#endif 1871 set AC_SYNC_ERR, %o0 1872 std %g2, [%sp + CCFSZ + 24] ! save g2, g3 1873 lda [%o0] ASI_CONTROL, %o1 ! sync err reg 1874 inc 4, %o0 1875 std %g4, [%sp + CCFSZ + 32] ! (sneak g4,g5 in here) 1876 lda [%o0] ASI_CONTROL, %o2 ! sync virt addr 1877 btst SER_MEMERR, %o1 ! memory error? 1878 std %g6, [%sp + CCFSZ + 40] 1879 bz,a normal_mem_fault ! no, just a regular fault 1880 wr %l0, PSR_ET, %psr ! (and reenable traps) 1881 1882 /* 1883 * We got a synchronous memory error. It could be one that 1884 * happened because there were two stores in a row, and the 1885 * first went into the write buffer, and the second caused this 1886 * synchronous trap; so there could now be a pending async error. 1887 * This is in fact the case iff the two va's differ. 1888 */ 1889 inc 4, %o0 1890 lda [%o0] ASI_CONTROL, %o3 ! async err reg 1891 inc 4, %o0 1892 lda [%o0] ASI_CONTROL, %o4 ! async virt addr 1893 cmp %o2, %o4 1894 be,a 1f ! no, not an async err 1895 wr %l0, PSR_ET, %psr ! (and reenable traps) 1896 1897 /* 1898 * Handle the async error; ignore the sync error for now 1899 * (we may end up getting it again, but so what?). 1900 * This code is essentially the same as that at `nmi' below, 1901 * but the register usage is different and we cannot merge. 1902 */ 1903 sethi %hi(INTRREG_VA), %l5 ! ienab_bic(IE_ALLIE); 1904 ldub [%l5 + %lo(INTRREG_VA)], %o0 1905 andn %o0, IE_ALLIE, %o0 1906 stb %o0, [%l5 + %lo(INTRREG_VA)] 1907 1908 /* 1909 * Now reenable traps and call C code. 1910 * %o1 through %o4 still hold the error reg contents. 1911 * If memerr() returns, return from the trap. 1912 */ 1913 wr %l0, PSR_ET, %psr 1914 call _C_LABEL(memerr4_4c) ! memerr(0, ser, sva, aer, ava) 1915 clr %o0 1916 1917 ld [%sp + CCFSZ + 20], %g1 ! restore g1 through g7 1918 wr %l0, 0, %psr ! and disable traps, 3 instr delay 1919 ldd [%sp + CCFSZ + 24], %g2 1920 ldd [%sp + CCFSZ + 32], %g4 1921 ldd [%sp + CCFSZ + 40], %g6 1922 /* now safe to set IE_ALLIE again */ 1923 ldub [%l5 + %lo(INTRREG_VA)], %o1 1924 or %o1, IE_ALLIE, %o1 1925 stb %o1, [%l5 + %lo(INTRREG_VA)] 1926 b return_from_trap 1927 wr %l4, 0, %y ! restore y 1928 1929 /* 1930 * Trap was a synchronous memory error. 1931 * %o1 through %o4 still hold the error reg contents. 1932 */ 19331: 1934 call _C_LABEL(memerr4_4c) ! memerr(1, ser, sva, aer, ava) 1935 mov 1, %o0 1936 1937 ld [%sp + CCFSZ + 20], %g1 ! restore g1 through g7 1938 ldd [%sp + CCFSZ + 24], %g2 1939 ldd [%sp + CCFSZ + 32], %g4 1940 ldd [%sp + CCFSZ + 40], %g6 1941 wr %l4, 0, %y ! restore y 1942 b return_from_trap 1943 wr %l0, 0, %psr 1944 /* NOTREACHED */ 1945#endif /* SUN4C */ 1946 1947#if defined(SUN4M) 1948memfault_sun4m: 1949 ! DANGER: we use the fact that %lo(CPUINFO_VA) is zero 1950.if CPUINFO_VA & 0x1fff 1951BARF 1952.endif 1953 sethi %hi(CPUINFO_VA), %l4 1954 ld [%l4 + %lo(CPUINFO_VA+CPUINFO_GETSYNCFLT)], %l5 1955 jmpl %l5, %l7 1956 or %l4, %lo(CPUINFO_SYNCFLTDUMP), %l4 1957 TRAP_SETUP(-CCFSZ-80) 1958 INCR(_C_LABEL(uvmexp)+V_FAULTS) ! cnt.v_faults++ (clobbers %o0,%o1) 1959 1960 st %g1, [%sp + CCFSZ + 20] ! save g1 1961 rd %y, %l4 ! save y 1962 1963 std %g2, [%sp + CCFSZ + 24] ! save g2, g3 1964 std %g4, [%sp + CCFSZ + 32] ! save g4, g5 1965 std %g6, [%sp + CCFSZ + 40] ! sneak in g6, g7 1966 1967 ! retrieve sync fault status/address 1968 sethi %hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %o0 1969 ld [%o0 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP)], %o1 1970 ld [%o0 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4)], %o2 1971 1972 wr %l0, PSR_ET, %psr ! reenable traps 1973 1974 /* Finish stackframe, call C trap handler */ 1975 std %l0, [%sp + CCFSZ + 0] ! set tf.tf_psr, tf.tf_pc 1976 mov %l3, %o0 ! (argument: type) 1977 st %l2, [%sp + CCFSZ + 8] ! set tf.tf_npc 1978 st %l4, [%sp + CCFSZ + 12] ! set tf.tf_y 1979 std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc 1980 std %i2, [%sp + CCFSZ + 56] 1981 std %i4, [%sp + CCFSZ + 64] 1982 std %i6, [%sp + CCFSZ + 72] 1983 ! mem_access_fault(type,sfsr,sfva,&tf); 1984 call _C_LABEL(mem_access_fault4m) 1985 add %sp, CCFSZ, %o3 ! (argument: &tf) 1986 1987 ldd [%sp + CCFSZ + 0], %l0 ! load new values 1988 ldd [%sp + CCFSZ + 8], %l2 1989 wr %l3, 0, %y 1990 ld [%sp + CCFSZ + 20], %g1 1991 ldd [%sp + CCFSZ + 24], %g2 1992 ldd [%sp + CCFSZ + 32], %g4 1993 ldd [%sp + CCFSZ + 40], %g6 1994 ldd [%sp + CCFSZ + 48], %i0 1995 ldd [%sp + CCFSZ + 56], %i2 1996 ldd [%sp + CCFSZ + 64], %i4 1997 ldd [%sp + CCFSZ + 72], %i6 1998 1999 b return_from_trap ! go return 2000 wr %l0, 0, %psr ! (but first disable traps again) 2001#endif /* SUN4M */ 2002 2003normal_mem_fault: 2004 /* 2005 * Trap was some other error; call C code to deal with it. 2006 * Must finish trap frame (psr,pc,npc,%y,%o0..%o7) in case 2007 * we decide to deliver a signal or ptrace the process. 2008 * %g1..%g7 were already set up above. 2009 */ 2010 std %l0, [%sp + CCFSZ + 0] ! set tf.tf_psr, tf.tf_pc 2011 mov %l3, %o0 ! (argument: type) 2012 st %l2, [%sp + CCFSZ + 8] ! set tf.tf_npc 2013 st %l4, [%sp + CCFSZ + 12] ! set tf.tf_y 2014 mov %l1, %o3 ! (argument: pc) 2015 std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc 2016 std %i2, [%sp + CCFSZ + 56] 2017 mov %l0, %o4 ! (argument: psr) 2018 std %i4, [%sp + CCFSZ + 64] 2019 std %i6, [%sp + CCFSZ + 72] 2020 call _C_LABEL(mem_access_fault)! mem_access_fault(type, ser, sva, 2021 ! pc, psr, &tf); 2022 add %sp, CCFSZ, %o5 ! (argument: &tf) 2023 2024 ldd [%sp + CCFSZ + 0], %l0 ! load new values 2025 ldd [%sp + CCFSZ + 8], %l2 2026 wr %l3, 0, %y 2027 ld [%sp + CCFSZ + 20], %g1 2028 ldd [%sp + CCFSZ + 24], %g2 2029 ldd [%sp + CCFSZ + 32], %g4 2030 ldd [%sp + CCFSZ + 40], %g6 2031 ldd [%sp + CCFSZ + 48], %i0 2032 ldd [%sp + CCFSZ + 56], %i2 2033 ldd [%sp + CCFSZ + 64], %i4 2034 ldd [%sp + CCFSZ + 72], %i6 2035 2036 b return_from_trap ! go return 2037 wr %l0, 0, %psr ! (but first disable traps again) 2038 2039 2040/* 2041 * fp_exception has to check to see if we are trying to save 2042 * the FP state, and if so, continue to save the FP state. 2043 * 2044 * We do not even bother checking to see if we were in kernel mode, 2045 * since users have no access to the special_fp_store instruction. 2046 * 2047 * This whole idea was stolen from Sprite. 2048 */ 2049fp_exception: 2050 set special_fp_store, %l4 ! see if we came from the special one 2051 cmp %l1, %l4 ! pc == special_fp_store? 2052 bne slowtrap ! no, go handle per usual 2053 EMPTY 2054 sethi %hi(savefpcont), %l4 ! yes, "return" to the special code 2055 or %lo(savefpcont), %l4, %l4 2056 jmp %l4 2057 rett %l4 + 4 2058 2059/* 2060 * slowtrap() builds a trap frame and calls trap(). 2061 * This is called `slowtrap' because it *is*.... 2062 * We have to build a full frame for ptrace(), for instance. 2063 * 2064 * Registers: 2065 * %l0 = %psr 2066 * %l1 = return pc 2067 * %l2 = return npc 2068 * %l3 = trap code 2069 */ 2070slowtrap: 2071 TRAP_SETUP(-CCFSZ-80) 2072 /* 2073 * Phew, ready to enable traps and call C code. 2074 */ 2075 mov %l3, %o0 ! put type in %o0 for later 2076Lslowtrap_reenter: 2077 wr %l0, PSR_ET, %psr ! traps on again 2078 std %l0, [%sp + CCFSZ] ! tf.tf_psr = psr; tf.tf_pc = ret_pc; 2079 rd %y, %l3 2080 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc = return_npc; tf.tf_y = %y; 2081 st %g1, [%sp + CCFSZ + 20] 2082 std %g2, [%sp + CCFSZ + 24] 2083 std %g4, [%sp + CCFSZ + 32] 2084 std %g6, [%sp + CCFSZ + 40] 2085 std %i0, [%sp + CCFSZ + 48] 2086 mov %l0, %o1 ! (psr) 2087 std %i2, [%sp + CCFSZ + 56] 2088 mov %l1, %o2 ! (pc) 2089 std %i4, [%sp + CCFSZ + 64] 2090 add %sp, CCFSZ, %o3 ! (&tf) 2091 call _C_LABEL(trap) ! trap(type, psr, pc, &tf) 2092 std %i6, [%sp + CCFSZ + 72] 2093 2094 ldd [%sp + CCFSZ], %l0 ! load new values 2095 ldd [%sp + CCFSZ + 8], %l2 2096 wr %l3, 0, %y 2097 ld [%sp + CCFSZ + 20], %g1 2098 ldd [%sp + CCFSZ + 24], %g2 2099 ldd [%sp + CCFSZ + 32], %g4 2100 ldd [%sp + CCFSZ + 40], %g6 2101 ldd [%sp + CCFSZ + 48], %i0 2102 ldd [%sp + CCFSZ + 56], %i2 2103 ldd [%sp + CCFSZ + 64], %i4 2104 ldd [%sp + CCFSZ + 72], %i6 2105 b return_from_trap 2106 wr %l0, 0, %psr 2107 2108/* 2109 * Do a `software' trap by re-entering the trap code, possibly first 2110 * switching from interrupt stack to kernel stack. This is used for 2111 * scheduling and signal ASTs (which generally occur from softclock or 2112 * tty or net interrupts) and register window saves (which might occur 2113 * from anywhere). 2114 * 2115 * The current window is the trap window, and it is by definition clean. 2116 * We enter with the trap type in %o0. All we have to do is jump to 2117 * Lslowtrap_reenter above, but maybe after switching stacks.... 2118 */ 2119softtrap: 2120#if defined(MULTIPROCESSOR) 2121 /* 2122 * The interrupt stack is not at a fixed location 2123 * and %sp must be checked against both ends. 2124 */ 2125 sethi %hi(_EINTSTACKP), %l7 2126 ld [%l7 + %lo(_EINTSTACKP)], %l7 2127 cmp %sp, %l7 2128 bge Lslowtrap_reenter 2129 EMPTY 2130 set INT_STACK_SIZE, %l6 2131 sub %l7, %l6, %l7 2132 cmp %sp, %l7 2133 blu Lslowtrap_reenter 2134 EMPTY 2135#else 2136 sethi %hi(_C_LABEL(eintstack)), %l7 2137 cmp %sp, %l7 2138 bge Lslowtrap_reenter 2139 EMPTY 2140#endif 2141 sethi %hi(cpcb), %l6 2142 ld [%l6 + %lo(cpcb)], %l6 2143 set USPACE-CCFSZ-80, %l5 2144 add %l6, %l5, %l7 2145 SET_SP_REDZONE(%l6, %l5) 2146 b Lslowtrap_reenter 2147 mov %l7, %sp 2148 2149#ifdef KGDB 2150/* 2151 * bpt is entered on all breakpoint traps. 2152 * If this is a kernel breakpoint, we do not want to call trap(). 2153 * Among other reasons, this way we can set breakpoints in trap(). 2154 */ 2155bpt: 2156 btst PSR_PS, %l0 ! breakpoint from kernel? 2157 bz slowtrap ! no, go do regular trap 2158 nop 2159 2160/* XXXSMP */ 2161 /* 2162 * Build a trap frame for kgdb_trap_glue to copy. 2163 * Enable traps but set ipl high so that we will not 2164 * see interrupts from within breakpoints. 2165 */ 2166 TRAP_SETUP(-CCFSZ-80) 2167 or %l0, PSR_PIL, %l4 ! splhigh() 2168 wr %l4, 0, %psr ! the manual claims that this 2169 wr %l4, PSR_ET, %psr ! song and dance is necessary 2170 std %l0, [%sp + CCFSZ + 0] ! tf.tf_psr, tf.tf_pc 2171 mov %l3, %o0 ! trap type arg for kgdb_trap_glue 2172 rd %y, %l3 2173 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc, tf.tf_y 2174 rd %wim, %l3 2175 st %l3, [%sp + CCFSZ + 16] ! tf.tf_wim (a kgdb-only r/o field) 2176 st %g1, [%sp + CCFSZ + 20] ! tf.tf_global[1] 2177 std %g2, [%sp + CCFSZ + 24] ! etc 2178 std %g4, [%sp + CCFSZ + 32] 2179 std %g6, [%sp + CCFSZ + 40] 2180 std %i0, [%sp + CCFSZ + 48] ! tf.tf_in[0..1] 2181 std %i2, [%sp + CCFSZ + 56] ! etc 2182 std %i4, [%sp + CCFSZ + 64] 2183 std %i6, [%sp + CCFSZ + 72] 2184 2185 /* 2186 * Now call kgdb_trap_glue(); if it returns, call trap(). 2187 */ 2188 mov %o0, %l3 ! gotta save trap type 2189 call _C_LABEL(kgdb_trap_glue)! kgdb_trap_glue(type, &trapframe) 2190 add %sp, CCFSZ, %o1 ! (&trapframe) 2191 2192 /* 2193 * Use slowtrap to call trap---but first erase our tracks 2194 * (put the registers back the way they were). 2195 */ 2196 mov %l3, %o0 ! slowtrap will need trap type 2197 ld [%sp + CCFSZ + 12], %l3 2198 wr %l3, 0, %y 2199 ld [%sp + CCFSZ + 20], %g1 2200 ldd [%sp + CCFSZ + 24], %g2 2201 ldd [%sp + CCFSZ + 32], %g4 2202 b Lslowtrap_reenter 2203 ldd [%sp + CCFSZ + 40], %g6 2204 2205/* 2206 * Enter kernel breakpoint. Write all the windows (not including the 2207 * current window) into the stack, so that backtrace works. Copy the 2208 * supplied trap frame to the kgdb stack and switch stacks. 2209 * 2210 * kgdb_trap_glue(type, tf0) 2211 * int type; 2212 * struct trapframe *tf0; 2213 */ 2214_ENTRY(_C_LABEL(kgdb_trap_glue)) 2215 save %sp, -CCFSZ, %sp 2216 2217 call _C_LABEL(write_all_windows) 2218 mov %sp, %l4 ! %l4 = current %sp 2219 2220 /* copy trapframe to top of kgdb stack */ 2221 set _C_LABEL(kgdb_stack) + KGDB_STACK_SIZE - 80, %l0 2222 ! %l0 = tfcopy -> end_of_kgdb_stack 2223 mov 80, %l1 22241: ldd [%i1], %l2 2225 inc 8, %i1 2226 deccc 8, %l1 2227 std %l2, [%l0] 2228 bg 1b 2229 inc 8, %l0 2230 2231#ifdef DEBUG 2232 /* save old red zone and then turn it off */ 2233 sethi %hi(_redzone), %l7 2234 ld [%l7 + %lo(_redzone)], %l6 2235 st %g0, [%l7 + %lo(_redzone)] 2236#endif 2237 /* switch to kgdb stack */ 2238 add %l0, -CCFSZ-80, %sp 2239 2240 /* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */ 2241 mov %i0, %o0 2242 call _C_LABEL(kgdb_trap) 2243 add %l0, -80, %o1 2244 tst %o0 2245 bnz,a kgdb_rett 2246 add %l0, -80, %g1 2247 2248 /* 2249 * kgdb_trap() did not handle the trap at all so the stack is 2250 * still intact. A simple `restore' will put everything back, 2251 * after we reset the stack pointer. 2252 */ 2253 mov %l4, %sp 2254#ifdef DEBUG 2255 st %l6, [%l7 + %lo(_redzone)] ! restore red zone 2256#endif 2257 ret 2258 restore 2259 2260/* 2261 * Return from kgdb trap. This is sort of special. 2262 * 2263 * We know that kgdb_trap_glue wrote the window above it, so that we will 2264 * be able to (and are sure to have to) load it up. We also know that we 2265 * came from kernel land and can assume that the %fp (%i6) we load here 2266 * is proper. We must also be sure not to lower ipl (it is at splhigh()) 2267 * until we have traps disabled, due to the SPARC taking traps at the 2268 * new ipl before noticing that PSR_ET has been turned off. We are on 2269 * the kgdb stack, so this could be disastrous. 2270 * 2271 * Note that the trapframe argument in %g1 points into the current stack 2272 * frame (current window). We abandon this window when we move %g1->tf_psr 2273 * into %psr, but we will not have loaded the new %sp yet, so again traps 2274 * must be disabled. 2275 */ 2276kgdb_rett: 2277 rd %psr, %g4 ! turn off traps 2278 wr %g4, PSR_ET, %psr 2279 /* use the three-instruction delay to do something useful */ 2280 ld [%g1], %g2 ! pick up new %psr 2281 ld [%g1 + 12], %g3 ! set %y 2282 wr %g3, 0, %y 2283#ifdef DEBUG 2284 st %l6, [%l7 + %lo(_redzone)] ! and restore red zone 2285#endif 2286 wr %g0, 0, %wim ! enable window changes 2287 nop; nop; nop 2288 /* now safe to set the new psr (changes CWP, leaves traps disabled) */ 2289 wr %g2, 0, %psr ! set rett psr (including cond codes) 2290 /* 3 instruction delay before we can use the new window */ 2291/*1*/ ldd [%g1 + 24], %g2 ! set new %g2, %g3 2292/*2*/ ldd [%g1 + 32], %g4 ! set new %g4, %g5 2293/*3*/ ldd [%g1 + 40], %g6 ! set new %g6, %g7 2294 2295 /* now we can use the new window */ 2296 mov %g1, %l4 2297 ld [%l4 + 4], %l1 ! get new pc 2298 ld [%l4 + 8], %l2 ! get new npc 2299 ld [%l4 + 20], %g1 ! set new %g1 2300 2301 /* set up returnee's out registers, including its %sp */ 2302 ldd [%l4 + 48], %i0 2303 ldd [%l4 + 56], %i2 2304 ldd [%l4 + 64], %i4 2305 ldd [%l4 + 72], %i6 2306 2307 /* load returnee's window, making the window above it be invalid */ 2308 restore 2309 restore %g0, 1, %l1 ! move to inval window and set %l1 = 1 2310 rd %psr, %l0 2311 sll %l1, %l0, %l1 2312 wr %l1, 0, %wim ! %wim = 1 << (%psr & 31) 2313 sethi %hi(cpcb), %l1 2314 ld [%l1 + %lo(cpcb)], %l1 2315 and %l0, 31, %l0 ! CWP = %psr & 31; 2316 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = CWP; 2317 save %g0, %g0, %g0 ! back to window to reload 2318 LOADWIN(%sp) 2319 save %g0, %g0, %g0 ! back to trap window 2320 /* note, we have not altered condition codes; safe to just rett */ 2321 RETT 2322#endif 2323 2324/* 2325 * syscall() builds a trap frame and calls syscall(). 2326 * sun_syscall is same but delivers sun system call number 2327 * XXX should not have to save&reload ALL the registers just for 2328 * ptrace... 2329 */ 2330_C_LABEL(_syscall): 2331 TRAP_SETUP(-CCFSZ-80) 2332 wr %l0, PSR_ET, %psr 2333 std %l0, [%sp + CCFSZ + 0] ! tf_psr, tf_pc 2334 rd %y, %l3 2335 std %l2, [%sp + CCFSZ + 8] ! tf_npc, tf_y 2336 st %g1, [%sp + CCFSZ + 20] ! tf_g[1] 2337 std %g2, [%sp + CCFSZ + 24] ! tf_g[2], tf_g[3] 2338 std %g4, [%sp + CCFSZ + 32] ! etc 2339 std %g6, [%sp + CCFSZ + 40] 2340 mov %g1, %o0 ! (code) 2341 std %i0, [%sp + CCFSZ + 48] 2342 add %sp, CCFSZ, %o1 ! (&tf) 2343 std %i2, [%sp + CCFSZ + 56] 2344 mov %l1, %o2 ! (pc) 2345 std %i4, [%sp + CCFSZ + 64] 2346 call _C_LABEL(syscall) ! syscall(code, &tf, pc, suncompat) 2347 std %i6, [%sp + CCFSZ + 72] 2348 ! now load em all up again, sigh 2349 ldd [%sp + CCFSZ + 0], %l0 ! new %psr, new pc 2350 ldd [%sp + CCFSZ + 8], %l2 ! new npc, new %y 2351 wr %l3, 0, %y 2352 /* see `proc_trampoline' for the reason for this label */ 2353return_from_syscall: 2354 ld [%sp + CCFSZ + 20], %g1 2355 ldd [%sp + CCFSZ + 24], %g2 2356 ldd [%sp + CCFSZ + 32], %g4 2357 ldd [%sp + CCFSZ + 40], %g6 2358 ldd [%sp + CCFSZ + 48], %i0 2359 ldd [%sp + CCFSZ + 56], %i2 2360 ldd [%sp + CCFSZ + 64], %i4 2361 ldd [%sp + CCFSZ + 72], %i6 2362 b return_from_trap 2363 wr %l0, 0, %psr 2364 2365/* 2366 * Interrupts. Software interrupts must be cleared from the software 2367 * interrupt enable register. Rather than calling ienab_bic for each, 2368 * we do them in-line before enabling traps. 2369 * 2370 * After preliminary setup work, the interrupt is passed to each 2371 * registered handler in turn. These are expected to return nonzero if 2372 * they took care of the interrupt. If a handler claims the interrupt, 2373 * we exit (hardware interrupts are latched in the requestor so we'll 2374 * just take another interrupt in the unlikely event of simultaneous 2375 * interrupts from two different devices at the same level). If we go 2376 * through all the registered handlers and no one claims it, we report a 2377 * stray interrupt. This is more or less done as: 2378 * 2379 * for (ih = intrhand[intlev]; ih; ih = ih->ih_next) 2380 * if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame)) 2381 * return; 2382 * strayintr(&frame); 2383 * 2384 * Software interrupts are almost the same with three exceptions: 2385 * (1) we clear the interrupt from the software interrupt enable 2386 * register before calling any handler (we have to clear it first 2387 * to avoid an interrupt-losing race), 2388 * (2) we always call all the registered handlers (there is no way 2389 * to tell if the single bit in the software interrupt register 2390 * represents one or many requests) 2391 * (3) we never announce a stray interrupt (because of (1), another 2392 * interrupt request can come in while we're in the handler. If 2393 * the handler deals with everything for both the original & the 2394 * new request, we'll erroneously report a stray interrupt when 2395 * we take the software interrupt for the new request. 2396 * 2397 * Inputs: 2398 * %l0 = %psr 2399 * %l1 = return pc 2400 * %l2 = return npc 2401 * %l3 = interrupt level 2402 * (software interrupt only) %l4 = bits to clear in interrupt register 2403 * 2404 * Internal: 2405 * %l4, %l5: local variables 2406 * %l6 = %y 2407 * %l7 = %g1 2408 * %g2..%g7 go to stack 2409 * 2410 * An interrupt frame is built in the space for a full trapframe; 2411 * this contains the psr, pc, npc, and interrupt level. 2412 */ 2413softintr_sun44c: 2414 sethi %hi(INTRREG_VA), %l6 2415 ldub [%l6 + %lo(INTRREG_VA)], %l5 2416 andn %l5, %l4, %l5 2417 stb %l5, [%l6 + %lo(INTRREG_VA)] 2418 2419softintr_common: 2420 INTR_SETUP(-CCFSZ-80) 2421 std %g2, [%sp + CCFSZ + 24] ! save registers 2422 INCR(_C_LABEL(uvmexp)+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) 2423 mov %g1, %l7 2424 rd %y, %l6 2425 std %g4, [%sp + CCFSZ + 32] 2426 andn %l0, PSR_PIL, %l4 ! %l4 = psr & ~PSR_PIL | 2427 sll %l3, 8, %l5 ! intlev << IPLSHIFT 2428 std %g6, [%sp + CCFSZ + 40] 2429 or %l5, %l4, %l4 ! ; 2430 wr %l4, 0, %psr ! the manual claims this 2431 wr %l4, PSR_ET, %psr ! song and dance is necessary 2432 std %l0, [%sp + CCFSZ + 0] ! set up intrframe/clockframe 2433 sll %l3, 2, %l5 2434 set _C_LABEL(intrcnt), %l4 ! intrcnt[intlev]++; 2435 ld [%l4 + %l5], %o0 2436 std %l2, [%sp + CCFSZ + 8] 2437 inc %o0 2438 st %o0, [%l4 + %l5] 2439 set _C_LABEL(intrhand), %l4 ! %l4 = intrhand[intlev]; 2440 ld [%l4 + %l5], %l4 2441 b 3f 2442 st %fp, [%sp + CCFSZ + 16] 2443 24441: ld [%l4], %o1 2445 ld [%l4 + 4], %o0 2446 tst %o0 2447 bz,a 2f 2448 add %sp, CCFSZ, %o0 24492: jmpl %o1, %o7 ! (void)(*ih->ih_fun)(...) 2450 ld [%l4 + 8], %l4 ! and ih = ih->ih_next 24513: tst %l4 ! while ih != NULL 2452 bnz 1b 2453 nop 2454 mov %l7, %g1 2455 wr %l6, 0, %y 2456 ldd [%sp + CCFSZ + 24], %g2 2457 ldd [%sp + CCFSZ + 32], %g4 2458 ldd [%sp + CCFSZ + 40], %g6 2459 b return_from_trap 2460 wr %l0, 0, %psr 2461 2462 /* 2463 * _sparc_interrupt{44c,4m} is exported for paranoia checking 2464 * (see intr.c). 2465 */ 2466#if defined(SUN4M) 2467_ENTRY(_C_LABEL(sparc_interrupt4m)) 2468#if !defined(MSIIEP) /* "normal" sun4m */ 2469 mov 1, %l4 2470 sethi %hi(CPUINFO_VA+CPUINFO_INTREG), %l6 2471 ld [%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l6 2472 ld [%l6 + ICR_PI_PEND_OFFSET], %l5 ! get pending interrupts 2473 sll %l4, %l3, %l4 ! test SOFTINT bit 2474 andcc %l5, %l4, %g0 2475 bne sparc_interrupt_common 2476 nop 2477 2478 ! a soft interrupt; clear bit in interrupt-pending register 2479 sll %l4, 16, %l5 2480 st %l5, [%l6 + ICR_PI_CLR_OFFSET] 2481 b,a softintr_common 2482#else /* MSIIEP */ 2483 sethi %hi(MSIIEP_PCIC_VA), %l6 2484 mov 1, %l4 2485 ld [%l6 + PCIC_PROC_IPR_REG], %l5 ! get pending interrupts 2486 sll %l4, %l3, %l4 2487 btst %l4, %l5 ! has pending hw intr at this level? 2488 bnz sparc_interrupt_common 2489 nop 2490 2491 ! a soft interrupt; clear its bit in softintr clear register 2492 b softintr_common 2493 sth %l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG] 2494#endif /* MSIIEP */ 2495#endif /* SUN4M */ 2496 2497_ENTRY(_C_LABEL(sparc_interrupt44c)) 2498sparc_interrupt_common: 2499 INTR_SETUP(-CCFSZ-80) 2500 std %g2, [%sp + CCFSZ + 24] ! save registers 2501 INCR(_C_LABEL(uvmexp)+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) 2502 mov %g1, %l7 2503 rd %y, %l6 2504 std %g4, [%sp + CCFSZ + 32] 2505 andn %l0, PSR_PIL, %l4 ! %l4 = psr & ~PSR_PIL | 2506 sll %l3, 8, %l5 ! intlev << IPLSHIFT 2507 std %g6, [%sp + CCFSZ + 40] 2508 or %l5, %l4, %l4 ! ; 2509 wr %l4, 0, %psr ! the manual claims this 2510 wr %l4, PSR_ET, %psr ! song and dance is necessary 2511 std %l0, [%sp + CCFSZ + 0] ! set up intrframe/clockframe 2512 sll %l3, 2, %l5 2513 set _C_LABEL(intrcnt), %l4 ! intrcnt[intlev]++; 2514 ld [%l4 + %l5], %o0 2515 std %l2, [%sp + CCFSZ + 8] ! set up intrframe/clockframe 2516 inc %o0 2517 st %o0, [%l4 + %l5] 2518 set _C_LABEL(intrhand), %l4 ! %l4 = intrhand[intlev]; 2519 ld [%l4 + %l5], %l4 2520 2521#if defined(MULTIPROCESSOR) && defined(SUN4M) /* XXX */ 2522 call _C_LABEL(intr_lock_kernel) 2523 nop 2524#endif 2525 2526 b 3f 2527 st %fp, [%sp + CCFSZ + 16] 2528 25291: ld [%l4], %o1 2530 ld [%l4 + 4], %o0 2531 tst %o0 2532 bz,a 2f 2533 add %sp, CCFSZ, %o0 25342: jmpl %o1, %o7 ! handled = (*ih->ih_fun)(...) 2535 ld [%l4 + 8], %l4 ! and ih = ih->ih_next 2536 tst %o0 2537 bnz 4f ! if (handled) break 2538 nop 25393: tst %l4 2540 bnz 1b ! while (ih) 2541 nop 2542 2543 /* Unhandled interrupts while cold cause IPL to be raised to `high' */ 2544 sethi %hi(_C_LABEL(cold)), %o0 2545 ld [%o0 + %lo(_C_LABEL(cold))], %o0 2546 tst %o0 ! if (cold) { 2547 bnz,a 4f ! splhigh(); 2548 or %l0, 0xf00, %l0 ! } else 2549 2550 call _C_LABEL(strayintr) ! strayintr(&intrframe) 2551 add %sp, CCFSZ, %o0 2552 /* all done: restore registers and go return */ 25534: 2554#if defined(MULTIPROCESSOR) && defined(SUN4M) /* XXX */ 2555 call _C_LABEL(intr_unlock_kernel) 2556 nop 2557#endif 2558 mov %l7, %g1 2559 wr %l6, 0, %y 2560 ldd [%sp + CCFSZ + 24], %g2 2561 ldd [%sp + CCFSZ + 32], %g4 2562 ldd [%sp + CCFSZ + 40], %g6 2563 b return_from_trap 2564 wr %l0, 0, %psr 2565 2566#ifdef notyet 2567/* 2568 * Level 12 (ZS serial) interrupt. Handle it quickly, schedule a 2569 * software interrupt, and get out. Do the software interrupt directly 2570 * if we would just take it on the way out. 2571 * 2572 * Input: 2573 * %l0 = %psr 2574 * %l1 = return pc 2575 * %l2 = return npc 2576 * Internal: 2577 * %l3 = zs device 2578 * %l4, %l5 = temporary 2579 * %l6 = rr3 (or temporary data) + 0x100 => need soft int 2580 * %l7 = zs soft status 2581 */ 2582zshard: 2583#endif /* notyet */ 2584 2585/* 2586 * Level 15 interrupt. An async memory error has occurred; 2587 * take care of it (typically by panicking, but hey...). 2588 * %l0 = %psr 2589 * %l1 = return pc 2590 * %l2 = return npc 2591 * %l3 = 15 * 4 (why? just because!) 2592 * 2593 * Internal: 2594 * %l4 = %y 2595 * %l5 = %g1 2596 * %l6 = %g6 2597 * %l7 = %g7 2598 * g2, g3, g4, g5 go to stack 2599 * 2600 * This code is almost the same as that in mem_access_fault, 2601 * except that we already know the problem is not a `normal' fault, 2602 * and that we must be extra-careful with interrupt enables. 2603 */ 2604 2605#if defined(SUN4) 2606nmi_sun4: 2607 INTR_SETUP(-CCFSZ-80) 2608 INCR(_C_LABEL(uvmexp)+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) 2609 /* 2610 * Level 15 interrupts are nonmaskable, so with traps off, 2611 * disable all interrupts to prevent recursion. 2612 */ 2613 sethi %hi(INTRREG_VA), %o0 2614 ldub [%o0 + %lo(INTRREG_VA)], %o1 2615 andn %o0, IE_ALLIE, %o1 2616 stb %o1, [%o0 + %lo(INTRREG_VA)] 2617 wr %l0, PSR_ET, %psr ! okay, turn traps on again 2618 2619 std %g2, [%sp + CCFSZ + 0] ! save g2, g3 2620 rd %y, %l4 ! save y 2621 2622 std %g4, [%sp + CCFSZ + 8] ! save g4, g5 2623 mov %g1, %l5 ! save g1, g6, g7 2624 mov %g6, %l6 2625 mov %g7, %l7 2626#if defined(SUN4C) || defined(SUN4M) 2627 b,a nmi_common 2628#endif /* SUN4C || SUN4M */ 2629#endif 2630 2631#if defined(SUN4C) 2632nmi_sun4c: 2633 INTR_SETUP(-CCFSZ-80) 2634 INCR(_C_LABEL(uvmexp)+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) 2635 /* 2636 * Level 15 interrupts are nonmaskable, so with traps off, 2637 * disable all interrupts to prevent recursion. 2638 */ 2639 sethi %hi(INTRREG_VA), %o0 2640 ldub [%o0 + %lo(INTRREG_VA)], %o1 2641 andn %o0, IE_ALLIE, %o1 2642 stb %o1, [%o0 + %lo(INTRREG_VA)] 2643 wr %l0, PSR_ET, %psr ! okay, turn traps on again 2644 2645 std %g2, [%sp + CCFSZ + 0] ! save g2, g3 2646 rd %y, %l4 ! save y 2647 2648 ! must read the sync error register too. 2649 set AC_SYNC_ERR, %o0 2650 lda [%o0] ASI_CONTROL, %o1 ! sync err reg 2651 inc 4, %o0 2652 lda [%o0] ASI_CONTROL, %o2 ! sync virt addr 2653 std %g4, [%sp + CCFSZ + 8] ! save g4,g5 2654 mov %g1, %l5 ! save g1,g6,g7 2655 mov %g6, %l6 2656 mov %g7, %l7 2657 inc 4, %o0 2658 lda [%o0] ASI_CONTROL, %o3 ! async err reg 2659 inc 4, %o0 2660 lda [%o0] ASI_CONTROL, %o4 ! async virt addr 2661#if defined(SUN4M) 2662 !!b,a nmi_common 2663#endif /* SUN4M */ 2664#endif /* SUN4C */ 2665 2666nmi_common: 2667 ! and call C code 2668 call _C_LABEL(memerr4_4c) ! memerr(0, ser, sva, aer, ava) 2669 clr %o0 2670 2671 mov %l5, %g1 ! restore g1 through g7 2672 ldd [%sp + CCFSZ + 0], %g2 2673 ldd [%sp + CCFSZ + 8], %g4 2674 wr %l0, 0, %psr ! re-disable traps 2675 mov %l6, %g6 2676 mov %l7, %g7 2677 2678 ! set IE_ALLIE again (safe, we disabled traps again above) 2679 sethi %hi(INTRREG_VA), %o0 2680 ldub [%o0 + %lo(INTRREG_VA)], %o1 2681 or %o1, IE_ALLIE, %o1 2682 stb %o1, [%o0 + %lo(INTRREG_VA)] 2683 b return_from_trap 2684 wr %l4, 0, %y ! restore y 2685 2686#if defined(SUN4M) 2687nmi_sun4m: 2688 INTR_SETUP(-CCFSZ-80) 2689 INCR(_C_LABEL(uvmexp)+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) 2690 2691 /* Read the Pending Interrupts register */ 2692 sethi %hi(CPUINFO_VA+CPUINFO_INTREG), %l6 2693 ld [%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l6 2694 ld [%l6 + ICR_PI_PEND_OFFSET], %l5 ! get pending interrupts 2695 2696 set _C_LABEL(nmi_soft), %o3 ! assume a softint 2697 set PINTR_IC, %o1 ! hard lvl 15 bit 2698 sethi %hi(PINTR_SINTRLEV(15)), %o0 ! soft lvl 15 bit 2699 btst %o0, %l5 ! soft level 15? 2700 bnz,a 1f ! 2701 mov %o0, %o1 ! shift int clear bit to SOFTINT 15 2702 2703 set _C_LABEL(nmi_hard), %o3 ! it's a hardint; switch handler 2704 2705 /* 2706 * Level 15 interrupts are nonmaskable, so with traps off, 2707 * disable all interrupts to prevent recursion. 2708 */ 2709 sethi %hi(ICR_SI_SET), %o0 2710 set SINTR_MA, %o2 2711 st %o2, [%o0 + %lo(ICR_SI_SET)] 2712#if defined(MULTIPROCESSOR) && defined(DDB) 2713 b 2f 2714 clr %o0 2715#endif 2716 27171: 2718#if defined(MULTIPROCESSOR) && defined(DDB) 2719 /* 2720 * Setup a trapframe for nmi_soft; this might be an IPI telling 2721 * us to pause, so lets save some state for DDB to get at. 2722 */ 2723 std %l0, [%sp + CCFSZ] ! tf.tf_psr = psr; tf.tf_pc = ret_pc; 2724 rd %y, %l3 2725 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc = return_npc; tf.tf_y = %y; 2726 st %g1, [%sp + CCFSZ + 20] 2727 std %g2, [%sp + CCFSZ + 24] 2728 std %g4, [%sp + CCFSZ + 32] 2729 std %g6, [%sp + CCFSZ + 40] 2730 std %i0, [%sp + CCFSZ + 48] 2731 std %i2, [%sp + CCFSZ + 56] 2732 std %i4, [%sp + CCFSZ + 64] 2733 std %i6, [%sp + CCFSZ + 72] 2734 add %sp, CCFSZ, %o0 27352: 2736#else 2737 clr %o0 2738#endif 2739 /* 2740 * Now clear the NMI. Apparently, we must allow some time 2741 * to let the bits sink in.. 2742 */ 2743 st %o1, [%l6 + ICR_PI_CLR_OFFSET] 2744 nop; nop; nop; 2745 ld [%l6 + ICR_PI_PEND_OFFSET], %g0 ! drain register!? 2746 nop; nop; nop; 2747 2748 wr %l0, PSR_ET, %psr ! okay, turn traps on again 2749 2750 std %g2, [%sp + CCFSZ + 80] ! save g2, g3 2751 rd %y, %l4 ! save y 2752 std %g4, [%sp + CCFSZ + 88] ! save g4,g5 2753 2754 /* Finish stackframe, call C trap handler */ 2755 mov %g1, %l5 ! save g1,g6,g7 2756 mov %g6, %l6 2757 2758 jmpl %o3, %o7 ! nmi_hard(0) or nmi_soft(&tf) 2759 mov %g7, %l7 2760 2761 mov %l5, %g1 ! restore g1 through g7 2762 ldd [%sp + CCFSZ + 80], %g2 2763 ldd [%sp + CCFSZ + 88], %g4 2764 wr %l0, 0, %psr ! re-disable traps 2765 mov %l6, %g6 2766 mov %l7, %g7 2767 2768 !cmp %o0, 0 ! was this a soft nmi 2769 !be 4f 2770 !XXX - we need to unblock `mask all ints' only on a hard nmi 2771 2772 ! enable interrupts again (safe, we disabled traps again above) 2773 sethi %hi(ICR_SI_CLR), %o0 2774 set SINTR_MA, %o1 2775 st %o1, [%o0 + %lo(ICR_SI_CLR)] 2776 27774: 2778 b return_from_trap 2779 wr %l4, 0, %y ! restore y 2780#endif /* SUN4M */ 2781 2782#ifdef GPROF 2783 .globl window_of, winof_user 2784 .globl window_uf, winuf_user, winuf_ok, winuf_invalid 2785 .globl return_from_trap, rft_kernel, rft_user, rft_invalid 2786 .globl softtrap, slowtrap 2787 .globl clean_trap_window, _C_LABEL(_syscall) 2788#endif 2789 2790/* 2791 * Window overflow trap handler. 2792 * %l0 = %psr 2793 * %l1 = return pc 2794 * %l2 = return npc 2795 */ 2796window_of: 2797#ifdef TRIVIAL_WINDOW_OVERFLOW_HANDLER 2798 /* a trivial version that assumes %sp is ok */ 2799 /* (for testing only!) */ 2800 save %g0, %g0, %g0 2801 std %l0, [%sp + (0*8)] 2802 rd %psr, %l0 2803 mov 1, %l1 2804 sll %l1, %l0, %l0 2805 wr %l0, 0, %wim 2806 std %l2, [%sp + (1*8)] 2807 std %l4, [%sp + (2*8)] 2808 std %l6, [%sp + (3*8)] 2809 std %i0, [%sp + (4*8)] 2810 std %i2, [%sp + (5*8)] 2811 std %i4, [%sp + (6*8)] 2812 std %i6, [%sp + (7*8)] 2813 restore 2814 RETT 2815#else 2816 /* 2817 * This is similar to TRAP_SETUP, but we do not want to spend 2818 * a lot of time, so we have separate paths for kernel and user. 2819 * We also know for sure that the window has overflowed. 2820 */ 2821 btst PSR_PS, %l0 2822 bz winof_user 2823 sethi %hi(clean_trap_window), %l7 2824 2825 /* 2826 * Overflow from kernel mode. Call clean_trap_window to 2827 * do the dirty work, then just return, since we know prev 2828 * window is valid. clean_trap_windows might dump all *user* 2829 * windows into the pcb, but we do not care: there is at 2830 * least one kernel window (a trap or interrupt frame!) 2831 * above us. 2832 */ 2833 jmpl %l7 + %lo(clean_trap_window), %l4 2834 mov %g7, %l7 ! for clean_trap_window 2835 2836 wr %l0, 0, %psr ! put back the @%*! cond. codes 2837 nop ! (let them settle in) 2838 RETT 2839 2840winof_user: 2841 /* 2842 * Overflow from user mode. 2843 * If clean_trap_window dumps the registers into the pcb, 2844 * rft_user will need to call trap(), so we need space for 2845 * a trap frame. We also have to compute pcb_nw. 2846 * 2847 * SHOULD EXPAND IN LINE TO AVOID BUILDING TRAP FRAME ON 2848 * `EASY' SAVES 2849 */ 2850 sethi %hi(cpcb), %l6 2851 ld [%l6 + %lo(cpcb)], %l6 2852 ld [%l6 + PCB_WIM], %l5 2853 and %l0, 31, %l3 2854 sub %l3, %l5, %l5 /* l5 = CWP - pcb_wim */ 2855 set uwtab, %l4 2856 ldub [%l4 + %l5], %l5 /* l5 = uwtab[l5] */ 2857 st %l5, [%l6 + PCB_UW] 2858 jmpl %l7 + %lo(clean_trap_window), %l4 2859 mov %g7, %l7 ! for clean_trap_window 2860 sethi %hi(cpcb), %l6 2861 ld [%l6 + %lo(cpcb)], %l6 2862 set USPACE-CCFSZ-80, %l5 2863 add %l6, %l5, %sp /* over to kernel stack */ 2864 CHECK_SP_REDZONE(%l6, %l5) 2865 2866 /* 2867 * Copy return_from_trap far enough to allow us 2868 * to jump directly to rft_user_or_recover_pcb_windows 2869 * (since we know that is where we are headed). 2870 */ 2871! and %l0, 31, %l3 ! still set (clean_trap_window 2872 ! leaves this register alone) 2873 set wmask, %l6 2874 ldub [%l6 + %l3], %l5 ! %l5 = 1 << ((CWP + 1) % nwindows) 2875 b rft_user_or_recover_pcb_windows 2876 rd %wim, %l4 ! (read %wim first) 2877#endif /* end `real' version of window overflow trap handler */ 2878 2879/* 2880 * Window underflow trap handler. 2881 * %l0 = %psr 2882 * %l1 = return pc 2883 * %l2 = return npc 2884 * 2885 * A picture: 2886 * 2887 * T R I X 2888 * 0 0 0 1 0 0 0 (%wim) 2889 * [bit numbers increase towards the right; 2890 * `restore' moves right & `save' moves left] 2891 * 2892 * T is the current (Trap) window, R is the window that attempted 2893 * a `Restore' instruction, I is the Invalid window, and X is the 2894 * window we want to make invalid before we return. 2895 * 2896 * Since window R is valid, we cannot use rft_user to restore stuff 2897 * for us. We have to duplicate its logic. YUCK. 2898 * 2899 * Incidentally, TRIX are for kids. Silly rabbit! 2900 */ 2901window_uf: 2902#ifdef TRIVIAL_WINDOW_UNDERFLOW_HANDLER 2903 wr %g0, 0, %wim ! allow us to enter I 2904 restore ! to R 2905 nop 2906 nop 2907 restore ! to I 2908 restore %g0, 1, %l1 ! to X 2909 rd %psr, %l0 2910 sll %l1, %l0, %l0 2911 wr %l0, 0, %wim 2912 save %g0, %g0, %g0 ! back to I 2913 LOADWIN(%sp) 2914 save %g0, %g0, %g0 ! back to R 2915 save %g0, %g0, %g0 ! back to T 2916 RETT 2917#else 2918 wr %g0, 0, %wim ! allow us to enter I 2919 btst PSR_PS, %l0 2920 restore ! enter window R 2921 bz winuf_user 2922 restore ! enter window I 2923 2924 /* 2925 * Underflow from kernel mode. Just recover the 2926 * registers and go (except that we have to update 2927 * the blasted user pcb fields). 2928 */ 2929 restore %g0, 1, %l1 ! enter window X, then set %l1 to 1 2930 rd %psr, %l0 ! cwp = %psr & 31; 2931 and %l0, 31, %l0 2932 sll %l1, %l0, %l1 ! wim = 1 << cwp; 2933 wr %l1, 0, %wim ! setwim(wim); 2934 sethi %hi(cpcb), %l1 2935 ld [%l1 + %lo(cpcb)], %l1 2936 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = cwp; 2937 save %g0, %g0, %g0 ! back to window I 2938 LOADWIN(%sp) 2939 save %g0, %g0, %g0 ! back to R 2940 save %g0, %g0, %g0 ! and then to T 2941 wr %l0, 0, %psr ! fix those cond codes.... 2942 nop ! (let them settle in) 2943 RETT 2944 2945winuf_user: 2946 /* 2947 * Underflow from user mode. 2948 * 2949 * We cannot use rft_user (as noted above) because 2950 * we must re-execute the `restore' instruction. 2951 * Since it could be, e.g., `restore %l0,0,%l0', 2952 * it is not okay to touch R's registers either. 2953 * 2954 * We are now in window I. 2955 */ 2956 btst 7, %sp ! if unaligned, it is invalid 2957 bne winuf_invalid 2958 EMPTY 2959 2960 sethi %hi(_C_LABEL(pgofset)), %l4 2961 ld [%l4 + %lo(_C_LABEL(pgofset))], %l4 2962 PTE_OF_ADDR(%sp, %l7, winuf_invalid, %l4, NOP_ON_4M_5) 2963 CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_6) ! if first page not readable, 2964 bne winuf_invalid ! it is invalid 2965 EMPTY 2966 SLT_IF_1PAGE_RW(%sp, %l7, %l4) ! first page is readable 2967 bl,a winuf_ok ! if only one page, enter window X 2968 restore %g0, 1, %l1 ! and goto ok, & set %l1 to 1 2969 add %sp, 7*8, %l5 2970 add %l4, 62, %l4 2971 PTE_OF_ADDR(%l5, %l7, winuf_invalid, %l4, NOP_ON_4M_7) 2972 CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_8) ! check second page too 2973 be,a winuf_ok ! enter window X and goto ok 2974 restore %g0, 1, %l1 ! (and then set %l1 to 1) 2975 2976winuf_invalid: 2977 /* 2978 * We were unable to restore the window because %sp 2979 * is invalid or paged out. Return to the trap window 2980 * and call trap(T_WINUF). This will save R to the user 2981 * stack, then load both R and I into the pcb rw[] area, 2982 * and return with pcb_nsaved set to -1 for success, 0 for 2983 * failure. `Failure' indicates that someone goofed with the 2984 * trap registers (e.g., signals), so that we need to return 2985 * from the trap as from a syscall (probably to a signal handler) 2986 * and let it retry the restore instruction later. Note that 2987 * window R will have been pushed out to user space, and thus 2988 * be the invalid window, by the time we get back here. (We 2989 * continue to label it R anyway.) We must also set %wim again, 2990 * and set pcb_uw to 1, before enabling traps. (Window R is the 2991 * only window, and it is a user window). 2992 */ 2993 save %g0, %g0, %g0 ! back to R 2994 save %g0, 1, %l4 ! back to T, then %l4 = 1 2995 sethi %hi(cpcb), %l6 2996 ld [%l6 + %lo(cpcb)], %l6 2997 st %l4, [%l6 + PCB_UW] ! pcb_uw = 1 2998 ld [%l6 + PCB_WIM], %l5 ! get log2(%wim) 2999 sll %l4, %l5, %l4 ! %l4 = old %wim 3000 wr %l4, 0, %wim ! window I is now invalid again 3001 set USPACE-CCFSZ-80, %l5 3002 add %l6, %l5, %sp ! get onto kernel stack 3003 CHECK_SP_REDZONE(%l6, %l5) 3004 3005 /* 3006 * Okay, call trap(T_WINUF, psr, pc, &tf). 3007 * See `slowtrap' above for operation. 3008 */ 3009 wr %l0, PSR_ET, %psr 3010 std %l0, [%sp + CCFSZ + 0] ! tf.tf_psr, tf.tf_pc 3011 rd %y, %l3 3012 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc, tf.tf_y 3013 mov T_WINUF, %o0 3014 st %g1, [%sp + CCFSZ + 20] ! tf.tf_global[1] 3015 mov %l0, %o1 3016 std %g2, [%sp + CCFSZ + 24] ! etc 3017 mov %l1, %o2 3018 std %g4, [%sp + CCFSZ + 32] 3019 add %sp, CCFSZ, %o3 3020 std %g6, [%sp + CCFSZ + 40] 3021 std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc 3022 std %i2, [%sp + CCFSZ + 56] 3023 std %i4, [%sp + CCFSZ + 64] 3024 call _C_LABEL(trap) ! trap(T_WINUF, pc, psr, &tf) 3025 std %i6, [%sp + CCFSZ + 72] ! tf.tf_out[6] 3026 3027 ldd [%sp + CCFSZ + 0], %l0 ! new psr, pc 3028 ldd [%sp + CCFSZ + 8], %l2 ! new npc, %y 3029 wr %l3, 0, %y 3030 ld [%sp + CCFSZ + 20], %g1 3031 ldd [%sp + CCFSZ + 24], %g2 3032 ldd [%sp + CCFSZ + 32], %g4 3033 ldd [%sp + CCFSZ + 40], %g6 3034 ldd [%sp + CCFSZ + 48], %i0 ! %o0 for window R, etc 3035 ldd [%sp + CCFSZ + 56], %i2 3036 ldd [%sp + CCFSZ + 64], %i4 3037 wr %l0, 0, %psr ! disable traps: test must be atomic 3038 ldd [%sp + CCFSZ + 72], %i6 3039 sethi %hi(cpcb), %l6 3040 ld [%l6 + %lo(cpcb)], %l6 3041 ld [%l6 + PCB_NSAVED], %l7 ! if nsaved is -1, we have our regs 3042 tst %l7 3043 bl,a 1f ! got them 3044 wr %g0, 0, %wim ! allow us to enter windows R, I 3045 b,a return_from_trap 3046 3047 /* 3048 * Got 'em. Load 'em up. 3049 */ 30501: 3051 mov %g6, %l3 ! save %g6; set %g6 = cpcb 3052 mov %l6, %g6 3053 st %g0, [%g6 + PCB_NSAVED] ! and clear magic flag 3054 restore ! from T to R 3055 restore ! from R to I 3056 restore %g0, 1, %l1 ! from I to X, then %l1 = 1 3057 rd %psr, %l0 ! cwp = %psr; 3058 sll %l1, %l0, %l1 3059 wr %l1, 0, %wim ! make window X invalid 3060 and %l0, 31, %l0 3061 st %l0, [%g6 + PCB_WIM] ! cpcb->pcb_wim = cwp; 3062 nop ! unnecessary? old wim was 0... 3063 save %g0, %g0, %g0 ! back to I 3064 LOADWIN(%g6 + PCB_RW + 64) ! load from rw[1] 3065 save %g0, %g0, %g0 ! back to R 3066 LOADWIN(%g6 + PCB_RW) ! load from rw[0] 3067 save %g0, %g0, %g0 ! back to T 3068 wr %l0, 0, %psr ! restore condition codes 3069 mov %l3, %g6 ! fix %g6 3070 RETT 3071 3072 /* 3073 * Restoring from user stack, but everything has checked out 3074 * as good. We are now in window X, and %l1 = 1. Window R 3075 * is still valid and holds user values. 3076 */ 3077winuf_ok: 3078 rd %psr, %l0 3079 sll %l1, %l0, %l1 3080 wr %l1, 0, %wim ! make this one invalid 3081 sethi %hi(cpcb), %l2 3082 ld [%l2 + %lo(cpcb)], %l2 3083 and %l0, 31, %l0 3084 st %l0, [%l2 + PCB_WIM] ! cpcb->pcb_wim = cwp; 3085 save %g0, %g0, %g0 ! back to I 3086 LOADWIN(%sp) 3087 save %g0, %g0, %g0 ! back to R 3088 save %g0, %g0, %g0 ! back to T 3089 wr %l0, 0, %psr ! restore condition codes 3090 nop ! it takes three to tangle 3091 RETT 3092#endif /* end `real' version of window underflow trap handler */ 3093 3094/* 3095 * Various return-from-trap routines (see return_from_trap). 3096 */ 3097 3098/* 3099 * Return from trap, to kernel. 3100 * %l0 = %psr 3101 * %l1 = return pc 3102 * %l2 = return npc 3103 * %l4 = %wim 3104 * %l5 = bit for previous window 3105 */ 3106rft_kernel: 3107 btst %l5, %l4 ! if (wim & l5) 3108 bnz 1f ! goto reload; 3109 wr %l0, 0, %psr ! but first put !@#*% cond codes back 3110 3111 /* previous window is valid; just rett */ 3112 nop ! wait for cond codes to settle in 3113 RETT 3114 3115 /* 3116 * Previous window is invalid. 3117 * Update %wim and then reload l0..i7 from frame. 3118 * 3119 * T I X 3120 * 0 0 1 0 0 (%wim) 3121 * [see picture in window_uf handler] 3122 * 3123 * T is the current (Trap) window, I is the Invalid window, 3124 * and X is the window we want to make invalid. Window X 3125 * currently has no useful values. 3126 */ 31271: 3128 wr %g0, 0, %wim ! allow us to enter window I 3129 nop; nop; nop ! (it takes a while) 3130 restore ! enter window I 3131 restore %g0, 1, %l1 ! enter window X, then %l1 = 1 3132 rd %psr, %l0 ! CWP = %psr & 31; 3133 and %l0, 31, %l0 3134 sll %l1, %l0, %l1 ! wim = 1 << CWP; 3135 wr %l1, 0, %wim ! setwim(wim); 3136 sethi %hi(cpcb), %l1 3137 ld [%l1 + %lo(cpcb)], %l1 3138 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = l0 & 31; 3139 save %g0, %g0, %g0 ! back to window I 3140 LOADWIN(%sp) 3141 save %g0, %g0, %g0 ! back to window T 3142 /* 3143 * Note that the condition codes are still set from 3144 * the code at rft_kernel; we can simply return. 3145 */ 3146 RETT 3147 3148/* 3149 * Return from trap, to user. Checks for scheduling trap (`ast') first; 3150 * will re-enter trap() if set. Note that we may have to switch from 3151 * the interrupt stack to the kernel stack in this case. 3152 * %l0 = %psr 3153 * %l1 = return pc 3154 * %l2 = return npc 3155 * %l4 = %wim 3156 * %l5 = bit for previous window 3157 * %l6 = cpcb 3158 * If returning to a valid window, just set psr and return. 3159 */ 3160rft_user: 3161! sethi %hi(_C_LABEL(want_ast)), %l7 ! (done below) 3162 ld [%l7 + %lo(_C_LABEL(want_ast))], %l7 3163 tst %l7 ! want AST trap? 3164 bne,a softtrap ! yes, re-enter trap with type T_AST 3165 mov T_AST, %o0 3166 3167 btst %l5, %l4 ! if (wim & l5) 3168 bnz 1f ! goto reload; 3169 wr %l0, 0, %psr ! restore cond codes 3170 nop ! (three instruction delay) 3171 RETT 3172 3173 /* 3174 * Previous window is invalid. 3175 * Before we try to load it, we must verify its stack pointer. 3176 * This is much like the underflow handler, but a bit easier 3177 * since we can use our own local registers. 3178 */ 31791: 3180 btst 7, %fp ! if unaligned, address is invalid 3181 bne rft_invalid 3182 EMPTY 3183 3184 sethi %hi(_C_LABEL(pgofset)), %l3 3185 ld [%l3 + %lo(_C_LABEL(pgofset))], %l3 3186 PTE_OF_ADDR(%fp, %l7, rft_invalid, %l3, NOP_ON_4M_9) 3187 CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_10) ! try first page 3188 bne rft_invalid ! no good 3189 EMPTY 3190 SLT_IF_1PAGE_RW(%fp, %l7, %l3) 3191 bl,a rft_user_ok ! only 1 page: ok 3192 wr %g0, 0, %wim 3193 add %fp, 7*8, %l5 3194 add %l3, 62, %l3 3195 PTE_OF_ADDR(%l5, %l7, rft_invalid, %l3, NOP_ON_4M_11) 3196 CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_12) ! check 2nd page too 3197 be,a rft_user_ok 3198 wr %g0, 0, %wim 3199 3200 /* 3201 * The window we wanted to pull could not be pulled. Instead, 3202 * re-enter trap with type T_RWRET. This will pull the window 3203 * into cpcb->pcb_rw[0] and set cpcb->pcb_nsaved to -1, which we 3204 * will detect when we try to return again. 3205 */ 3206rft_invalid: 3207 b softtrap 3208 mov T_RWRET, %o0 3209 3210 /* 3211 * The window we want to pull can be pulled directly. 3212 */ 3213rft_user_ok: 3214! wr %g0, 0, %wim ! allow us to get into it 3215 wr %l0, 0, %psr ! fix up the cond codes now 3216 nop; nop; nop 3217 restore ! enter window I 3218 restore %g0, 1, %l1 ! enter window X, then %l1 = 1 3219 rd %psr, %l0 ! l0 = (junk << 5) + CWP; 3220 sll %l1, %l0, %l1 ! %wim = 1 << CWP; 3221 wr %l1, 0, %wim 3222 sethi %hi(cpcb), %l1 3223 ld [%l1 + %lo(cpcb)], %l1 3224 and %l0, 31, %l0 3225 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = l0 & 31; 3226 save %g0, %g0, %g0 ! back to window I 3227 LOADWIN(%sp) ! suck hard 3228 save %g0, %g0, %g0 ! back to window T 3229 RETT 3230 3231/* 3232 * Return from trap. Entered after a 3233 * wr %l0, 0, %psr 3234 * which disables traps so that we can rett; registers are: 3235 * 3236 * %l0 = %psr 3237 * %l1 = return pc 3238 * %l2 = return npc 3239 * 3240 * (%l3..%l7 anything). 3241 * 3242 * If we are returning to user code, we must: 3243 * 1. Check for register windows in the pcb that belong on the stack. 3244 * If there are any, reenter trap with type T_WINOF. 3245 * 2. Make sure the register windows will not underflow. This is 3246 * much easier in kernel mode.... 3247 */ 3248return_from_trap: 3249! wr %l0, 0, %psr ! disable traps so we can rett 3250! (someone else did this already) 3251 and %l0, 31, %l5 3252 set wmask, %l6 3253 ldub [%l6 + %l5], %l5 ! %l5 = 1 << ((CWP + 1) % nwindows) 3254 btst PSR_PS, %l0 ! returning to userland? 3255 bnz rft_kernel ! no, go return to kernel 3256 rd %wim, %l4 ! (read %wim in any case) 3257 3258rft_user_or_recover_pcb_windows: 3259 /* 3260 * (entered with %l4=%wim, %l5=wmask[cwp]; %l0..%l2 as usual) 3261 * 3262 * check cpcb->pcb_nsaved: 3263 * if 0, do a `normal' return to user (see rft_user); 3264 * if > 0, cpcb->pcb_rw[] holds registers to be copied to stack; 3265 * if -1, cpcb->pcb_rw[0] holds user registers for rett window 3266 * from an earlier T_RWRET pseudo-trap. 3267 */ 3268 sethi %hi(cpcb), %l6 3269 ld [%l6 + %lo(cpcb)], %l6 3270 ld [%l6 + PCB_NSAVED], %l7 3271 tst %l7 3272 bz,a rft_user 3273 sethi %hi(_C_LABEL(want_ast)), %l7 ! first instr of rft_user 3274 3275 bg,a softtrap ! if (pcb_nsaved > 0) 3276 mov T_WINOF, %o0 ! trap(T_WINOF); 3277 3278 /* 3279 * To get here, we must have tried to return from a previous 3280 * trap and discovered that it would cause a window underflow. 3281 * We then must have tried to pull the registers out of the 3282 * user stack (from the address in %fp==%i6) and discovered 3283 * that it was either unaligned or not loaded in memory, and 3284 * therefore we ran a trap(T_RWRET), which loaded one set of 3285 * registers into cpcb->pcb_pcb_rw[0] (if it had killed the 3286 * process due to a bad stack, we would not be here). 3287 * 3288 * We want to load pcb_rw[0] into the previous window, which 3289 * we know is currently invalid. In other words, we want 3290 * %wim to be 1 << ((cwp + 2) % nwindows). 3291 */ 3292 wr %g0, 0, %wim ! enable restores 3293 mov %g6, %l3 ! save g6 in l3 3294 mov %l6, %g6 ! set g6 = &u 3295 st %g0, [%g6 + PCB_NSAVED] ! clear cpcb->pcb_nsaved 3296 restore ! enter window I 3297 restore %g0, 1, %l1 ! enter window X, then %l1 = 1 3298 rd %psr, %l0 3299 sll %l1, %l0, %l1 ! %wim = 1 << CWP; 3300 wr %l1, 0, %wim 3301 and %l0, 31, %l0 3302 st %l0, [%g6 + PCB_WIM] ! cpcb->pcb_wim = CWP; 3303 nop ! unnecessary? old wim was 0... 3304 save %g0, %g0, %g0 ! back to window I 3305 LOADWIN(%g6 + PCB_RW) 3306 save %g0, %g0, %g0 ! back to window T (trap window) 3307 wr %l0, 0, %psr ! cond codes, cond codes everywhere 3308 mov %l3, %g6 ! restore g6 3309 RETT 3310 3311! exported end marker for kernel gdb 3312 .globl _C_LABEL(endtrapcode) 3313_C_LABEL(endtrapcode): 3314 3315/* 3316 * init_tables(nwin) int nwin; 3317 * 3318 * Set up the uwtab and wmask tables. 3319 * We know nwin > 1. 3320 */ 3321init_tables: 3322 /* 3323 * for (i = -nwin, j = nwin - 2; ++i < 0; j--) 3324 * uwtab[i] = j; 3325 * (loop runs at least once) 3326 */ 3327 set uwtab, %o3 3328 sub %g0, %o0, %o1 ! i = -nwin + 1 3329 inc %o1 3330 add %o0, -2, %o2 ! j = nwin - 2; 33310: 3332 stb %o2, [%o3 + %o1] ! uwtab[i] = j; 33331: 3334 inccc %o1 ! ++i < 0? 3335 bl 0b ! yes, continue loop 3336 dec %o2 ! in any case, j-- 3337 3338 /* 3339 * (i now equals 0) 3340 * for (j = nwin - 1; i < nwin; i++, j--) 3341 * uwtab[i] = j; 3342 * (loop runs at least twice) 3343 */ 3344 sub %o0, 1, %o2 ! j = nwin - 1 33450: 3346 stb %o2, [%o3 + %o1] ! uwtab[i] = j 3347 inc %o1 ! i++ 33481: 3349 cmp %o1, %o0 ! i < nwin? 3350 bl 0b ! yes, continue 3351 dec %o2 ! in any case, j-- 3352 3353 /* 3354 * We observe that, for i in 0..nwin-2, (i+1)%nwin == i+1; 3355 * for i==nwin-1, (i+1)%nwin == 0. 3356 * To avoid adding 1, we run i from 1 to nwin and set 3357 * wmask[i-1]. 3358 * 3359 * for (i = j = 1; i < nwin; i++) { 3360 * j <<= 1; (j now == 1 << i) 3361 * wmask[i - 1] = j; 3362 * } 3363 * (loop runs at least once) 3364 */ 3365 set wmask - 1, %o3 3366 mov 1, %o1 ! i = 1; 3367 mov 2, %o2 ! j = 2; 33680: 3369 stb %o2, [%o3 + %o1] ! (wmask - 1)[i] = j; 3370 inc %o1 ! i++ 3371 cmp %o1, %o0 ! i < nwin? 3372 bl,a 0b ! yes, continue 3373 sll %o2, 1, %o2 ! (and j <<= 1) 3374 3375 /* 3376 * Now i==nwin, so we want wmask[i-1] = 1. 3377 */ 3378 mov 1, %o2 ! j = 1; 3379 retl 3380 stb %o2, [%o3 + %o1] ! (wmask - 1)[i] = j; 3381 3382#ifdef SUN4 3383/* 3384 * getidprom(struct idprom *, sizeof(struct idprom)) 3385 */ 3386_ENTRY(_C_LABEL(getidprom)) 3387 set AC_IDPROM, %o2 33881: lduba [%o2] ASI_CONTROL, %o3 3389 stb %o3, [%o0] 3390 inc %o0 3391 inc %o2 3392 dec %o1 3393 cmp %o1, 0 3394 bne 1b 3395 nop 3396 retl 3397 nop 3398#endif 3399 3400dostart: 3401 /* 3402 * Startup. 3403 * 3404 * We have been loaded in low RAM, at some address which 3405 * is page aligned (PROM_LOADADDR actually) rather than where we 3406 * want to run (KERNBASE+PROM_LOADADDR). Until we get everything set, 3407 * we have to be sure to use only pc-relative addressing. 3408 */ 3409 3410 /* 3411 * We now use the bootinfo method to pass arguments, and the new 3412 * magic number indicates that. A pointer to the kernel top, i.e. 3413 * the first address after the load kernel image (including DDB 3414 * symbols, if any) is passed in %o4[0] and the bootinfo structure 3415 * is passed in %o4[1]. 3416 * 3417 * A magic number is passed in %o5 to allow for bootloaders 3418 * that know nothing about the bootinfo structure or previous 3419 * DDB symbol loading conventions. 3420 * 3421 * For compatibility with older versions, we check for DDB arguments 3422 * if the older magic number is there. The loader passes `kernel_top' 3423 * (previously known as `esym') in %o4. 3424 * 3425 * Note: we don't touch %o1-%o3; SunOS bootloaders seem to use them 3426 * for their own mirky business. 3427 * 3428 * Pre-NetBSD 1.3 bootblocks had KERNBASE compiled in, and used it 3429 * to compute the value of `kernel_top' (previously known as `esym'). 3430 * In order to successfully boot a kernel built with a different value 3431 * for KERNBASE using old bootblocks, we fixup `kernel_top' here by 3432 * the difference between KERNBASE and the old value (known to be 3433 * 0xf8000000) compiled into pre-1.3 bootblocks. 3434 */ 3435 set KERNBASE, %l4 3436 3437 set 0x44444232, %l3 ! bootinfo magic 3438 cmp %o5, %l3 3439 bne 1f 3440 nop 3441 3442 /* The loader has passed to us a `bootinfo' structure */ 3443 ld [%o4], %l3 ! 1st word is kernel_top 3444 add %l3, %l4, %o5 ! relocate: + KERNBASE 3445 sethi %hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! and store it 3446 st %o5, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)] 3447 3448 ld [%o4 + 4], %l3 ! 2nd word is bootinfo 3449 add %l3, %l4, %o5 ! relocate 3450 sethi %hi(_C_LABEL(bootinfo) - KERNBASE), %l3 ! store bootinfo 3451 st %o5, [%l3 + %lo(_C_LABEL(bootinfo) - KERNBASE)] 3452 b,a 4f 3453 34541: 3455#ifdef DDB 3456 /* Check for old-style DDB loader magic */ 3457 set 0x44444231, %l3 ! Is it DDB_MAGIC1? 3458 cmp %o5, %l3 3459 be,a 2f 3460 clr %l4 ! if DDB_MAGIC1, clear %l4 3461 3462 set 0x44444230, %l3 ! Is it DDB_MAGIC0? 3463 cmp %o5, %l3 ! if so, need to relocate %o4 3464 bne 3f ! if not, there's no bootloader info 3465 3466 ! note: %l4 set to KERNBASE above. 3467 set 0xf8000000, %l5 ! compute correction term: 3468 sub %l5, %l4, %l4 ! old KERNBASE (0xf8000000 ) - KERNBASE 3469 34702: 3471 tst %o4 ! do we have the symbols? 3472 bz 3f 3473 sub %o4, %l4, %o4 ! apply compat correction 3474 sethi %hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! and store it 3475 st %o4, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)] 3476 b,a 4f 34773: 3478#endif 3479 /* 3480 * The boot loader did not pass in a value for `kernel_top'; 3481 * let it default to `end'. 3482 */ 3483 set end, %o4 3484 sethi %hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! store kernel_top 3485 st %o4, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)] 3486 34874: 3488 3489 /* 3490 * Sun4 passes in the `load address'. Although possible, its highly 3491 * unlikely that OpenBoot would place the prom vector there. 3492 */ 3493 set PROM_LOADADDR, %g7 3494 cmp %o0, %g7 3495 be is_sun4 3496 nop 3497 3498#if defined(SUN4C) || defined(SUN4M) 3499 /* 3500 * Be prepared to get OF client entry in either %o0 or %o3. 3501 */ 3502 cmp %o0, 0 3503 be is_openfirm 3504 nop 3505 3506 mov %o0, %g7 ! save romp passed by boot code 3507 3508 /* First, check `romp->pv_magic' */ 3509 ld [%g7 + PV_MAGIC], %o0 ! v = pv->pv_magic 3510 set OBP_MAGIC, %o1 3511 cmp %o0, %o1 ! if ( v != OBP_MAGIC) { 3512 bne is_sun4m ! assume this is an OPENFIRM machine 3513 nop ! } 3514 3515 /* 3516 * are we on a sun4c or a sun4m? 3517 */ 3518 ld [%g7 + PV_NODEOPS], %o4 ! node = pv->pv_nodeops->no_nextnode(0) 3519 ld [%o4 + NO_NEXTNODE], %o4 3520 call %o4 3521 mov 0, %o0 ! node 3522 3523 mov %o0, %l0 3524 set cputypvar-KERNBASE, %o1 ! name = "compatible" 3525 set cputypval-KERNBASE, %o2 ! buffer ptr (assume buffer long enough) 3526 ld [%g7 + PV_NODEOPS], %o4 ! (void)pv->pv_nodeops->no_getprop(...) 3527 ld [%o4 + NO_GETPROP], %o4 3528 call %o4 3529 nop 3530 set cputypval-KERNBASE, %o2 ! buffer ptr 3531 ldub [%o2 + 4], %o0 ! which is it... "sun4c", "sun4m", "sun4d"? 3532 cmp %o0, 'c' 3533 be is_sun4c 3534 nop 3535 cmp %o0, 'm' 3536 be is_sun4m 3537 nop 3538#endif /* SUN4C || SUN4M */ 3539 3540 ! ``on a sun4d?! hell no!'' 3541 ld [%g7 + PV_HALT], %o1 ! by this kernel, then halt 3542 call %o1 3543 nop 3544 3545is_openfirm: 3546 ! OF client entry in %o3 (kernel booted directly by PROM?) 3547 mov %o3, %g7 3548 /* FALLTHROUGH to sun4m case */ 3549 3550is_sun4m: 3551#if defined(SUN4M) 3552 set trapbase_sun4m, %g6 3553 mov SUN4CM_PGSHIFT, %g5 3554 b start_havetype 3555 mov CPU_SUN4M, %g4 3556#else 3557 set sun4m_notsup-KERNBASE, %o0 3558 ld [%g7 + PV_EVAL], %o1 3559 call %o1 ! print a message saying that the 3560 nop ! sun4m architecture is not supported 3561 ld [%g7 + PV_HALT], %o1 ! by this kernel, then halt 3562 call %o1 3563 nop 3564 /*NOTREACHED*/ 3565#endif 3566is_sun4c: 3567#if defined(SUN4C) 3568 set trapbase_sun4c, %g6 3569 mov SUN4CM_PGSHIFT, %g5 3570 3571 set AC_CONTEXT, %g1 ! paranoia: set context to kernel 3572 stba %g0, [%g1] ASI_CONTROL 3573 3574 b start_havetype 3575 mov CPU_SUN4C, %g4 ! XXX CPU_SUN4 3576#else 3577 set sun4c_notsup-KERNBASE, %o0 3578 3579 ld [%g7 + PV_ROMVEC_VERS], %o1 3580 cmp %o1, 0 3581 bne 1f 3582 nop 3583 3584 ! stupid version 0 rom interface is pv_eval(int length, char *string) 3585 mov %o0, %o1 35862: ldub [%o0], %o4 3587 bne 2b 3588 inc %o0 3589 dec %o0 3590 sub %o0, %o1, %o0 3591 35921: ld [%g7 + PV_EVAL], %o2 3593 call %o2 ! print a message saying that the 3594 nop ! sun4c architecture is not supported 3595 ld [%g7 + PV_HALT], %o1 ! by this kernel, then halt 3596 call %o1 3597 nop 3598 /*NOTREACHED*/ 3599#endif 3600is_sun4: 3601#if defined(SUN4) 3602 set trapbase_sun4, %g6 3603 mov SUN4_PGSHIFT, %g5 3604 3605 set AC_CONTEXT, %g1 ! paranoia: set context to kernel 3606 stba %g0, [%g1] ASI_CONTROL 3607 3608 b start_havetype 3609 mov CPU_SUN4, %g4 3610#else 3611 set PROM_BASE, %g7 3612 3613 set sun4_notsup-KERNBASE, %o0 3614 ld [%g7 + OLDMON_PRINTF], %o1 3615 call %o1 ! print a message saying that the 3616 nop ! sun4 architecture is not supported 3617 ld [%g7 + OLDMON_HALT], %o1 ! by this kernel, then halt 3618 call %o1 3619 nop 3620 /*NOTREACHED*/ 3621#endif 3622 3623start_havetype: 3624 /* 3625 * Step 1: double map low RAM (addresses [0.._end-start-1]) 3626 * to KERNBASE (addresses [KERNBASE.._end-1]). None of these 3627 * are `bad' aliases (since they are all on segment boundaries) 3628 * so we do not have to worry about cache aliasing. 3629 * 3630 * We map in another couple of segments just to have some 3631 * more memory (512K, actually) guaranteed available for 3632 * bootstrap code (pmap_bootstrap needs memory to hold MMU 3633 * and context data structures). Note: this is only relevant 3634 * for 2-level MMU sun4/sun4c machines. 3635 */ 3636 clr %l0 ! lowva 3637 set KERNBASE, %l1 ! highva 3638 3639 sethi %hi(_C_LABEL(kernel_top) - KERNBASE), %o0 3640 ld [%o0 + %lo(_C_LABEL(kernel_top) - KERNBASE)], %o1 3641 set (2 << 18), %o2 ! add slack for sun4c MMU 3642 add %o1, %o2, %l2 ! last va that must be remapped 3643 3644 /* 3645 * Need different initial mapping functions for different 3646 * types of machines. 3647 */ 3648#if defined(SUN4C) 3649 cmp %g4, CPU_SUN4C 3650 bne 1f 3651 set 1 << 18, %l3 ! segment size in bytes 36520: 3653 lduba [%l0] ASI_SEGMAP, %l4 ! segmap[highva] = segmap[lowva]; 3654 stba %l4, [%l1] ASI_SEGMAP 3655 add %l3, %l1, %l1 ! highva += segsiz; 3656 cmp %l1, %l2 ! done? 3657 blu 0b ! no, loop 3658 add %l3, %l0, %l0 ! (and lowva += segsz) 3659 b,a startmap_done 36601: 3661#endif /* SUN4C */ 3662 3663#if defined(SUN4) 3664 cmp %g4, CPU_SUN4 3665 bne 2f 3666#if defined(SUN4_MMU3L) 3667 set AC_IDPROM+1, %l3 3668 lduba [%l3] ASI_CONTROL, %l3 3669 cmp %l3, 0x24 ! XXX - SUN4_400 3670 bne no_3mmu 3671 nop 3672 3673 /* 3674 * Three-level sun4 MMU. 3675 * Double-map by duplicating a single region entry (which covers 3676 * 16MB) corresponding to the kernel's virtual load address. 3677 */ 3678 add %l0, 2, %l0 ! get to proper half-word in RG space 3679 add %l1, 2, %l1 3680 lduha [%l0] ASI_REGMAP, %l4 ! regmap[highva] = regmap[lowva]; 3681 stha %l4, [%l1] ASI_REGMAP 3682 b,a startmap_done 3683no_3mmu: 3684#endif 3685 3686 /* 3687 * Three-level sun4 MMU. 3688 * Double-map by duplicating the required number of segment 3689 * entries corresponding to the kernel's virtual load address. 3690 */ 3691 set 1 << 18, %l3 ! segment size in bytes 36920: 3693 lduha [%l0] ASI_SEGMAP, %l4 ! segmap[highva] = segmap[lowva]; 3694 stha %l4, [%l1] ASI_SEGMAP 3695 add %l3, %l1, %l1 ! highva += segsiz; 3696 cmp %l1, %l2 ! done? 3697 blu 0b ! no, loop 3698 add %l3, %l0, %l0 ! (and lowva += segsz) 3699 b,a startmap_done 37002: 3701#endif /* SUN4 */ 3702 3703#if defined(SUN4M) 3704 cmp %g4, CPU_SUN4M ! skip for sun4m! 3705 bne 3f 3706 3707 /* 3708 * The OBP guarantees us a 16MB mapping using a level 1 PTE at 3709 * the start of the memory bank in which we were loaded. All we 3710 * have to do is copy the entry. 3711 * Also, we must check to see if we have a TI Viking in non-mbus mode, 3712 * and if so do appropriate flipping and turning off traps before 3713 * we dork with MMU passthrough. -grrr 3714 */ 3715 3716 sethi %hi(0x40000000), %o1 ! TI version bit 3717 rd %psr, %o0 3718 andcc %o0, %o1, %g0 3719 be remap_notvik ! is non-TI normal MBUS module 3720 lda [%g0] ASI_SRMMU, %o0 ! load MMU 3721 andcc %o0, 0x800, %g0 3722 bne remap_notvik ! It is a viking MBUS module 3723 nop 3724 3725 /* 3726 * Ok, we have a non-Mbus TI Viking, a MicroSparc. 3727 * In this scenerio, in order to play with the MMU 3728 * passthrough safely, we need turn off traps, flip 3729 * the AC bit on in the mmu status register, do our 3730 * passthroughs, then restore the mmu reg and %psr 3731 */ 3732 rd %psr, %o4 ! saved here till done 3733 andn %o4, 0x20, %o5 3734 wr %o5, 0x0, %psr 3735 nop; nop; nop; 3736 set SRMMU_CXTPTR, %o0 3737 lda [%o0] ASI_SRMMU, %o0 ! get context table ptr 3738 sll %o0, 4, %o0 ! make physical 3739 lda [%g0] ASI_SRMMU, %o3 ! hold mmu-sreg here 3740 /* 0x8000 is AC bit in Viking mmu-ctl reg */ 3741 set 0x8000, %o2 3742 or %o3, %o2, %o2 3743 sta %o2, [%g0] ASI_SRMMU ! AC bit on 3744 3745 lda [%o0] ASI_BYPASS, %o1 3746 srl %o1, 4, %o1 3747 sll %o1, 8, %o1 ! get phys addr of l1 entry 3748 lda [%o1] ASI_BYPASS, %l4 3749 srl %l1, 22, %o2 ! note: 22 == RGSHIFT - 2 3750 add %o1, %o2, %o1 3751 sta %l4, [%o1] ASI_BYPASS 3752 3753 sta %o3, [%g0] ASI_SRMMU ! restore mmu-sreg 3754 wr %o4, 0x0, %psr ! restore psr 3755 b,a startmap_done 3756 3757 /* 3758 * The following is generic and should work on all 3759 * Mbus based SRMMU's. 3760 */ 3761remap_notvik: 3762 set SRMMU_CXTPTR, %o0 3763 lda [%o0] ASI_SRMMU, %o0 ! get context table ptr 3764 sll %o0, 4, %o0 ! make physical 3765 lda [%o0] ASI_BYPASS, %o1 3766 srl %o1, 4, %o1 3767 sll %o1, 8, %o1 ! get phys addr of l1 entry 3768 lda [%o1] ASI_BYPASS, %l4 3769 srl %l1, 22, %o2 ! note: 22 == RGSHIFT - 2 3770 add %o1, %o2, %o1 3771 sta %l4, [%o1] ASI_BYPASS 3772 !b,a startmap_done 3773 37743: 3775#endif /* SUN4M */ 3776 ! botch! We should blow up. 3777 3778startmap_done: 3779 /* 3780 * All set, fix pc and npc. Once we are where we should be, 3781 * we can give ourselves a stack and enable traps. 3782 */ 3783 set 1f, %g1 3784 jmp %g1 3785 nop 37861: 3787 sethi %hi(_C_LABEL(cputyp)), %o0 ! what type of cpu we are on 3788 st %g4, [%o0 + %lo(_C_LABEL(cputyp))] 3789 3790 sethi %hi(_C_LABEL(pgshift)), %o0 ! pgshift = log2(nbpg) 3791 st %g5, [%o0 + %lo(_C_LABEL(pgshift))] 3792 3793 mov 1, %o0 ! nbpg = 1 << pgshift 3794 sll %o0, %g5, %g5 3795 sethi %hi(_C_LABEL(nbpg)), %o0 ! nbpg = bytes in a page 3796 st %g5, [%o0 + %lo(_C_LABEL(nbpg))] 3797 3798 sub %g5, 1, %g5 3799 sethi %hi(_C_LABEL(pgofset)), %o0 ! page offset = bytes in a page - 1 3800 st %g5, [%o0 + %lo(_C_LABEL(pgofset))] 3801 3802 rd %psr, %g3 ! paranoia: make sure ... 3803 andn %g3, PSR_ET, %g3 ! we have traps off 3804 wr %g3, 0, %psr ! so that we can fiddle safely 3805 nop; nop; nop 3806 3807 wr %g0, 0, %wim ! make sure we can set psr 3808 nop; nop; nop 3809 wr %g0, PSR_S|PSR_PS|PSR_PIL, %psr ! set initial psr 3810 nop; nop; nop 3811 3812 wr %g0, 2, %wim ! set initial %wim (w1 invalid) 3813 mov 1, %g1 ! set pcb_wim (log2(%wim) = 1) 3814 sethi %hi(_C_LABEL(u0) + PCB_WIM), %g2 3815 st %g1, [%g2 + %lo(_C_LABEL(u0) + PCB_WIM)] 3816 3817 set USRSTACK - CCFSZ, %fp ! as if called from user code 3818 set estack0 - CCFSZ - 80, %sp ! via syscall(boot_me_up) or somesuch 3819 rd %psr, %l0 3820 wr %l0, PSR_ET, %psr 3821 nop; nop; nop 3822 3823 /* Export actual trapbase */ 3824 sethi %hi(_C_LABEL(trapbase)), %o0 3825 st %g6, [%o0+%lo(_C_LABEL(trapbase))] 3826 3827#ifdef notdef 3828 /* 3829 * Step 2: clear BSS. This may just be paranoia; the boot 3830 * loader might already do it for us; but what the hell. 3831 */ 3832 set _edata, %o0 ! bzero(edata, end - edata) 3833 set _end, %o1 3834 call _C_LABEL(bzero) 3835 sub %o1, %o0, %o1 3836#endif 3837 3838 /* 3839 * Stash prom vectors now, after bzero, as it lives in bss 3840 * (which we just zeroed). 3841 * This depends on the fact that bzero does not use %g7. 3842 */ 3843 sethi %hi(_C_LABEL(romp)), %l0 3844 st %g7, [%l0 + %lo(_C_LABEL(romp))] 3845 3846 /* 3847 * Step 3: compute number of windows and set up tables. 3848 * We could do some of this later. 3849 */ 3850 save %sp, -64, %sp 3851 rd %psr, %g1 3852 restore 3853 and %g1, 31, %g1 ! want just the CWP bits 3854 add %g1, 1, %o0 ! compute nwindows 3855 sethi %hi(_C_LABEL(nwindows)), %o1 ! may as well tell everyone 3856 call init_tables 3857 st %o0, [%o1 + %lo(_C_LABEL(nwindows))] 3858 3859#if defined(SUN4) || defined(SUN4C) 3860 /* 3861 * Some sun4/sun4c models have fewer than 8 windows. For extra 3862 * speed, we do not need to save/restore those windows 3863 * The save/restore code has 7 "save"'s followed by 7 3864 * "restore"'s -- we "nop" out the last "save" and first 3865 * "restore" 3866 */ 3867 cmp %o0, 8 3868 be 1f 3869noplab: nop 3870 sethi %hi(noplab), %l0 3871 ld [%l0 + %lo(noplab)], %l1 3872 set wb1, %l0 3873 st %l1, [%l0 + 6*4] 3874 st %l1, [%l0 + 7*4] 38751: 3876#endif 3877 3878#if ((defined(SUN4) || defined(SUN4C)) && defined(SUN4M)) 3879 3880 /* 3881 * Patch instructions at specified labels that start 3882 * per-architecture code-paths. 3883 */ 3884Lgandul: nop 3885 3886#define MUNGE(label) \ 3887 sethi %hi(label), %o0; \ 3888 st %l0, [%o0 + %lo(label)] 3889 3890 sethi %hi(Lgandul), %o0 3891 ld [%o0 + %lo(Lgandul)], %l0 ! %l0 = NOP 3892 3893 cmp %g4, CPU_SUN4M 3894 bne,a 1f 3895 nop 3896 3897 ! this should be automated! 3898 MUNGE(NOP_ON_4M_1) 3899 MUNGE(NOP_ON_4M_2) 3900 MUNGE(NOP_ON_4M_3) 3901 MUNGE(NOP_ON_4M_4) 3902 MUNGE(NOP_ON_4M_5) 3903 MUNGE(NOP_ON_4M_6) 3904 MUNGE(NOP_ON_4M_7) 3905 MUNGE(NOP_ON_4M_8) 3906 MUNGE(NOP_ON_4M_9) 3907 MUNGE(NOP_ON_4M_10) 3908 MUNGE(NOP_ON_4M_11) 3909 MUNGE(NOP_ON_4M_12) 3910 MUNGE(NOP_ON_4M_13) 3911 MUNGE(NOP_ON_4M_14) 3912 MUNGE(NOP_ON_4M_15) 3913 b,a 2f 3914 39151: 3916 MUNGE(NOP_ON_4_4C_1) 3917 39182: 3919 3920#undef MUNGE 3921#endif 3922 3923 /* 3924 * Step 4: change the trap base register, now that our trap handlers 3925 * will function (they need the tables we just set up). 3926 * This depends on the fact that bzero does not use %g6. 3927 */ 3928 wr %g6, 0, %tbr 3929 nop; nop; nop ! paranoia 3930 3931 3932 /* Clear `cpuinfo' */ 3933 sethi %hi(CPUINFO_VA), %o0 ! bzero(&cpuinfo, NBPG) 3934 sethi %hi(CPUINFO_STRUCTSIZE), %o1 3935 call _C_LABEL(bzero) 3936 add %o1, %lo(CPUINFO_STRUCTSIZE), %o1 3937 3938 /* 3939 * Initialize `cpuinfo' fields which are needed early. Note 3940 * we make the cpuinfo self-reference at the local VA for now. 3941 * It may be changed to reference a global VA later. 3942 */ 3943 set _C_LABEL(u0), %o0 ! cpuinfo.curpcb = u0; 3944 sethi %hi(cpcb), %l0 3945 st %o0, [%l0 + %lo(cpcb)] 3946 3947 sethi %hi(CPUINFO_VA), %o0 ! cpuinfo.ci_self = &cpuinfo; 3948 sethi %hi(_CISELFP), %l0 3949 st %o0, [%l0 + %lo(_CISELFP)] 3950 3951 set _C_LABEL(eintstack), %o0 ! cpuinfo.eintstack= _eintstack; 3952 sethi %hi(_EINTSTACKP), %l0 3953 st %o0, [%l0 + %lo(_EINTSTACKP)] 3954 3955 /* 3956 * Ready to run C code; finish bootstrap. 3957 */ 3958 call _C_LABEL(bootstrap) 3959 nop 3960 3961 /* 3962 * Call main. This returns to us after loading /sbin/init into 3963 * user space. (If the exec fails, main() does not return.) 3964 */ 3965 call _C_LABEL(main) 3966 clr %o0 ! our frame arg is ignored 3967 /*NOTREACHED*/ 3968 3969#if defined(MULTIPROCESSOR) 3970 /* 3971 * Entry point for non-boot CPUs in MP systems. 3972 */ 3973 .globl _C_LABEL(cpu_hatch) 3974_C_LABEL(cpu_hatch): 3975 rd %psr, %g3 ! paranoia: make sure ... 3976 andn %g3, PSR_ET, %g3 ! we have traps off 3977 wr %g3, 0, %psr ! so that we can fiddle safely 3978 nop; nop; nop 3979 3980 wr %g0, 0, %wim ! make sure we can set psr 3981 nop; nop; nop 3982 wr %g0, PSR_S|PSR_PS|PSR_PIL, %psr ! set initial psr 3983 nop; nop; nop 3984 3985 wr %g0, 2, %wim ! set initial %wim (w1 invalid) 3986 3987 /* Initialize Trap Base register */ 3988 sethi %hi(_C_LABEL(trapbase)), %o0 3989 ld [%o0+%lo(_C_LABEL(trapbase))], %g6 3990 wr %g6, 0, %tbr 3991 nop; nop; nop ! paranoia 3992 3993 /* Set up a stack */ 3994 set USRSTACK - CCFSZ, %fp ! as if called from user code 3995 sethi %hi(_C_LABEL(cpu_hatchstack)), %o0 3996 ld [%o0+%lo(_C_LABEL(cpu_hatchstack))], %o0 3997 set USPACE - CCFSZ - 80, %sp 3998 add %sp, %o0, %sp 3999 4000 /* Enable traps */ 4001 rd %psr, %l0 4002 wr %l0, PSR_ET, %psr 4003 nop; nop; nop 4004 4005 /* Call C code */ 4006 sethi %hi(_C_LABEL(cpu_hatch_sc)), %o0 4007 call _C_LABEL(cpu_setup) 4008 ld [%o0+%lo(_C_LABEL(cpu_hatch_sc))], %o0 4009 4010 /* Wait for go_smp_cpus to go */ 4011 set _C_LABEL(go_smp_cpus), %l1 4012 ld [%l1], %l0 40131: 4014 cmp %l0, %g0 4015 be 1b 4016 ld [%l1], %l0 4017 4018#if 0 /* doesn't quite work yet */ 4019 4020 set _C_LABEL(proc0), %g3 ! p = proc0 4021 sethi %hi(_C_LABEL(sched_whichqs)), %g2 4022 sethi %hi(cpcb), %g6 4023 sethi %hi(curproc), %g7 4024 st %g0, [%g7 + %lo(curproc)] ! curproc = NULL; 4025 4026 mov PSR_S|PSR_ET, %g1 ! oldpsr = PSR_S | PSR_ET; 4027 sethi %hi(IDLE_UP), %g5 4028 ld [%g5 + %lo(IDLE_UP)], %g5 4029 st %g5, [%g6 + %lo(cpcb)] ! cpcb = &idle_u 4030 set USPACE-CCFSZ, %o1 4031 add %g5, %o1, %sp ! set new %sp 4032 4033#ifdef DEBUG 4034 mov %g5, %o2 ! %o2 = _idle_u 4035 SET_SP_REDZONE(%o2, %o1) 4036#endif /* DEBUG */ 4037 4038 b idle_enter_no_schedlock 4039 clr %g4 ! lastproc = NULL; 4040#else 4041 /* Idle here .. */ 4042 rd %psr, %l0 4043 andn %l0, PSR_PIL, %l0 ! psr &= ~PSR_PIL; 4044 wr %l0, 0, %psr ! (void) spl0(); 4045 nop; nop; nop 40469: ba 9b 4047 nop 4048 /*NOTREACHED*/ 4049#endif 4050 4051#endif /* MULTIPROCESSOR */ 4052 4053#include "sigcode_state.s" 4054 4055 .globl _C_LABEL(sigcode) 4056 .globl _C_LABEL(esigcode) 4057_C_LABEL(sigcode): 4058 4059 SAVE_STATE 4060 4061 ldd [%fp + 64], %o0 ! sig, code 4062 ld [%fp + 76], %o3 ! arg3 4063 call %g1 ! (*sa->sa_handler)(sig,code,scp,arg3) 4064 add %fp, 64 + 16, %o2 ! scp 4065 4066 RESTORE_STATE 4067 4068 ! get registers back & set syscall # 4069 restore %g0, SYS___sigreturn14, %g1 4070 add %sp, 64 + 16, %o0 ! compute scp 4071 t ST_SYSCALL ! sigreturn(scp) 4072 ! sigreturn does not return unless it fails 4073 mov SYS_exit, %g1 ! exit(errno) 4074 t ST_SYSCALL 4075_C_LABEL(esigcode): 4076 4077/* 4078 * Primitives 4079 */ 4080 4081/* 4082 * General-purpose NULL routine. 4083 */ 4084ENTRY(sparc_noop) 4085 retl 4086 nop 4087 4088/* 4089 * getfp() - get stack frame pointer 4090 */ 4091ENTRY(getfp) 4092 retl 4093 mov %fp, %o0 4094 4095/* 4096 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 4097 * 4098 * Copy a null terminated string from the user address space into 4099 * the kernel address space. 4100 */ 4101ENTRY(copyinstr) 4102 ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied 4103 mov %o1, %o5 ! save = toaddr; 4104 tst %o2 ! maxlen == 0? 4105 beq,a Lcstoolong ! yes, return ENAMETOOLONG 4106 sethi %hi(cpcb), %o4 4107 4108 set KERNBASE, %o4 4109 cmp %o0, %o4 ! fromaddr < KERNBASE? 4110 blu Lcsdocopy ! yes, go do it 4111 sethi %hi(cpcb), %o4 ! (first instr of copy) 4112 4113 b Lcsdone ! no, return EFAULT 4114 mov EFAULT, %o0 4115 4116/* 4117 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 4118 * 4119 * Copy a null terminated string from the kernel 4120 * address space to the user address space. 4121 */ 4122ENTRY(copyoutstr) 4123 ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied 4124 mov %o1, %o5 ! save = toaddr; 4125 tst %o2 ! maxlen == 0? 4126 beq,a Lcstoolong ! yes, return ENAMETOOLONG 4127 sethi %hi(cpcb), %o4 4128 4129 set KERNBASE, %o4 4130 cmp %o1, %o4 ! toaddr < KERNBASE? 4131 blu Lcsdocopy ! yes, go do it 4132 sethi %hi(cpcb), %o4 ! (first instr of copy) 4133 4134 b Lcsdone ! no, return EFAULT 4135 mov EFAULT, %o0 4136 4137Lcsdocopy: 4138! sethi %hi(cpcb), %o4 ! (done earlier) 4139 ld [%o4 + %lo(cpcb)], %o4 ! catch faults 4140 set Lcsdone, %g1 4141 st %g1, [%o4 + PCB_ONFAULT] 4142 4143! XXX should do this in bigger chunks when possible 41440: ! loop: 4145 ldsb [%o0], %g1 ! c = *fromaddr; 4146 tst %g1 4147 stb %g1, [%o1] ! *toaddr++ = c; 4148 be 1f ! if (c == NULL) 4149 inc %o1 ! goto ok; 4150 deccc %o2 ! if (--len > 0) { 4151 bgu 0b ! fromaddr++; 4152 inc %o0 ! goto loop; 4153 ! } 4154Lcstoolong: ! 4155 b Lcsdone ! error = ENAMETOOLONG; 4156 mov ENAMETOOLONG, %o0 ! goto done; 41571: ! ok: 4158 clr %o0 ! error = 0; 4159Lcsdone: ! done: 4160 sub %o1, %o5, %o1 ! len = to - save; 4161 tst %o3 ! if (lencopied) 4162 bnz,a 3f 4163 st %o1, [%o3] ! *lencopied = len; 41643: 4165 retl ! cpcb->pcb_onfault = 0; 4166 st %g0, [%o4 + PCB_ONFAULT]! return (error); 4167 4168/* 4169 * copystr(fromaddr, toaddr, maxlength, &lencopied) 4170 * 4171 * Copy a null terminated string from one point to another in 4172 * the kernel address space. (This is a leaf procedure, but 4173 * it does not seem that way to the C compiler.) 4174 */ 4175ENTRY(copystr) 4176 mov %o1, %o5 ! to0 = to; 4177 tst %o2 ! if (maxlength == 0) 4178 beq,a 2f ! 4179 mov ENAMETOOLONG, %o0 ! ret = ENAMETOOLONG; goto done; 4180 41810: ! loop: 4182 ldsb [%o0], %o4 ! c = *from; 4183 tst %o4 4184 stb %o4, [%o1] ! *to++ = c; 4185 be 1f ! if (c == 0) 4186 inc %o1 ! goto ok; 4187 deccc %o2 ! if (--len > 0) { 4188 bgu,a 0b ! from++; 4189 inc %o0 ! goto loop; 4190 b 2f ! } 4191 mov ENAMETOOLONG, %o0 ! ret = ENAMETOOLONG; goto done; 41921: ! ok: 4193 clr %o0 ! ret = 0; 41942: 4195 sub %o1, %o5, %o1 ! len = to - to0; 4196 tst %o3 ! if (lencopied) 4197 bnz,a 3f 4198 st %o1, [%o3] ! *lencopied = len; 41993: 4200 retl 4201 nop 4202 4203/* 4204 * Copyin(src, dst, len) 4205 * 4206 * Copy specified amount of data from user space into the kernel. 4207 */ 4208ENTRY(copyin) 4209 set KERNBASE, %o3 4210 cmp %o0, %o3 ! src < KERNBASE? 4211 blu,a Ldocopy ! yes, can try it 4212 sethi %hi(cpcb), %o3 4213 4214 /* source address points into kernel space: return EFAULT */ 4215 retl 4216 mov EFAULT, %o0 4217 4218/* 4219 * Copyout(src, dst, len) 4220 * 4221 * Copy specified amount of data from kernel to user space. 4222 * Just like copyin, except that the `dst' addresses are user space 4223 * rather than the `src' addresses. 4224 */ 4225ENTRY(copyout) 4226 set KERNBASE, %o3 4227 cmp %o1, %o3 ! dst < KERBASE? 4228 blu,a Ldocopy 4229 sethi %hi(cpcb), %o3 4230 4231 /* destination address points into kernel space: return EFAULT */ 4232 retl 4233 mov EFAULT, %o0 4234 4235 /* 4236 * ******NOTE****** this depends on bcopy() not using %g7 4237 */ 4238Ldocopy: 4239! sethi %hi(cpcb), %o3 4240 ld [%o3 + %lo(cpcb)], %o3 4241 set Lcopyfault, %o4 4242 mov %o7, %g7 ! save return address 4243 call _C_LABEL(bcopy) ! bcopy(src, dst, len) 4244 st %o4, [%o3 + PCB_ONFAULT] 4245 4246 sethi %hi(cpcb), %o3 4247 ld [%o3 + %lo(cpcb)], %o3 4248 st %g0, [%o3 + PCB_ONFAULT] 4249 jmp %g7 + 8 4250 clr %o0 ! return 0 4251 4252! Copyin or copyout fault. Clear cpcb->pcb_onfault and return EFAULT. 4253! Note that although we were in bcopy, there is no state to clean up; 4254! the only special thing is that we have to return to [g7 + 8] rather than 4255! [o7 + 8]. 4256Lcopyfault: 4257 sethi %hi(cpcb), %o3 4258 ld [%o3 + %lo(cpcb)], %o3 4259 jmp %g7 + 8 4260 st %g0, [%o3 + PCB_ONFAULT] 4261 4262 4263/* 4264 * Write all user windows presently in the CPU back to the user's stack. 4265 * We just do `save' instructions until pcb_uw == 0. 4266 * 4267 * p = cpcb; 4268 * nsaves = 0; 4269 * while (p->pcb_uw > 0) 4270 * save(), nsaves++; 4271 * while (--nsaves >= 0) 4272 * restore(); 4273 */ 4274ENTRY(write_user_windows) 4275 sethi %hi(cpcb), %g6 4276 ld [%g6 + %lo(cpcb)], %g6 4277 b 2f 4278 clr %g5 42791: 4280 save %sp, -64, %sp 42812: 4282 ld [%g6 + PCB_UW], %g7 4283 tst %g7 4284 bg,a 1b 4285 inc %g5 42863: 4287 deccc %g5 4288 bge,a 3b 4289 restore 4290 retl 4291 nop 4292 4293 4294 .comm _C_LABEL(want_resched),4 4295 .comm _C_LABEL(want_ast),4 4296/* 4297 * Masterpaddr is the p->p_addr of the last process on the processor. 4298 * XXX masterpaddr is almost the same as cpcb 4299 * XXX should delete this entirely 4300 */ 4301 .comm _C_LABEL(masterpaddr), 4 4302 4303/* 4304 * Switch statistics (for later tweaking): 4305 * nswitchdiff = p1 => p2 (i.e., chose different process) 4306 * nswitchexit = number of calls to switchexit() 4307 * cnt.v_swtch = total calls to swtch+swtchexit 4308 */ 4309 .comm _C_LABEL(nswitchdiff), 4 4310 .comm _C_LABEL(nswitchexit), 4 4311 4312/* 4313 * REGISTER USAGE IN cpu_switch AND switchexit: 4314 * This is split into two phases, more or less 4315 * `before we locate a new proc' and `after'. 4316 * Some values are the same in both phases. 4317 * Note that the %o0-registers are not preserved across 4318 * the psr change when entering a new process, since this 4319 * usually changes the CWP field (hence heavy usage of %g's). 4320 * 4321 * %g1 = oldpsr (excluding ipl bits) 4322 * %g2 = %hi(whichqs); newpsr 4323 * %g3 = p 4324 * %g4 = lastproc 4325 * %g5 = <free>; newpcb 4326 * %g6 = %hi(cpcb) 4327 * %g7 = %hi(curproc) 4328 * %o0 = tmp 1 4329 * %o1 = tmp 2 4330 * %o2 = tmp 3 4331 * %o3 = tmp 4; whichqs; vm 4332 * %o4 = tmp 4; which; sswap 4333 * %o5 = tmp 5; q; <free> 4334 */ 4335 4336/* 4337 * When calling external functions from cpu_switch() and idle(), we must 4338 * preserve the global registers mentioned above across the call. We also 4339 * set up a stack frame since we will be running in our caller's frame 4340 * in cpu_switch(). 4341 */ 4342#define SAVE_GLOBALS_AND_CALL(name) \ 4343 save %sp, -CCFSZ, %sp; \ 4344 mov %g1, %i0; \ 4345 mov %g2, %i1; \ 4346 mov %g3, %i2; \ 4347 mov %g4, %i3; \ 4348 mov %g6, %i4; \ 4349 call _C_LABEL(name); \ 4350 mov %g7, %i5; \ 4351 mov %i5, %g7; \ 4352 mov %i4, %g6; \ 4353 mov %i3, %g4; \ 4354 mov %i2, %g3; \ 4355 mov %i1, %g2; \ 4356 mov %i0, %g1; \ 4357 restore 4358 4359 4360/* 4361 * switchexit is called only from cpu_exit() before the current process 4362 * has freed its vmspace and kernel stack; we must schedule them to be 4363 * freed. (curproc is already NULL.) 4364 * 4365 * We lay the process to rest by changing to the `idle' kernel stack, 4366 * and note that the `last loaded process' is nonexistent. 4367 */ 4368ENTRY(switchexit) 4369 mov %o0, %g2 ! save proc for exit2() call 4370 4371 /* 4372 * Change pcb to idle u. area, i.e., set %sp to top of stack 4373 * and %psr to PSR_S|PSR_ET, and set cpcb to point to idle_u. 4374 * Once we have left the old stack, we can call exit2() to 4375 * destroy it. Call it any sooner and the register windows 4376 * go bye-bye. 4377 */ 4378#if defined(MULTIPROCESSOR) 4379 sethi %hi(IDLE_UP), %g5 4380 ld [%g5 + %lo(IDLE_UP)], %g5 4381#else 4382 set _C_LABEL(idle_u), %g5 4383#endif 4384 sethi %hi(cpcb), %g6 4385 mov 1, %g7 4386 wr %g0, PSR_S, %psr ! change to window 0, traps off 4387 wr %g0, 2, %wim ! and make window 1 the trap window 4388 st %g5, [%g6 + %lo(cpcb)] ! cpcb = &idle_u 4389 st %g7, [%g5 + PCB_WIM] ! idle_u.pcb_wim = log2(2) = 1 4390#if defined(MULTIPROCESSOR) 4391 set USPACE-CCFSZ, %o1 ! 4392 add %g5, %o1, %sp ! set new %sp 4393#else 4394 set _C_LABEL(idle_u) + USPACE-CCFSZ, %sp ! set new %sp 4395#endif 4396 4397#ifdef DEBUG 4398 mov %g5, %l6 ! %l6 = _idle_u 4399 SET_SP_REDZONE(%l6, %l5) 4400#endif 4401 4402 wr %g0, PSR_S|PSR_ET, %psr ! and then enable traps 4403 call _C_LABEL(exit2) ! exit2(p) 4404 mov %g2, %o0 4405 4406 /* 4407 * Now fall through to `the last switch'. %g6 was set to 4408 * %hi(cpcb), but may have been clobbered in exit2(), 4409 * so all the registers described below will be set here. 4410 * 4411 * REGISTER USAGE AT THIS POINT: 4412 * %g1 = oldpsr (excluding ipl bits) 4413 * %g2 = %hi(whichqs) 4414 * %g4 = lastproc 4415 * %g6 = %hi(cpcb) 4416 * %g7 = %hi(curproc) 4417 * %o0 = tmp 1 4418 * %o1 = tmp 2 4419 * %o3 = whichqs 4420 */ 4421 4422 INCR(_C_LABEL(nswitchexit)) ! nswitchexit++; 4423 INCR(_C_LABEL(uvmexp)+V_SWTCH) ! cnt.v_switch++; 4424 4425 mov PSR_S|PSR_ET, %g1 ! oldpsr = PSR_S | PSR_ET; 4426 sethi %hi(_C_LABEL(sched_whichqs)), %g2 4427 clr %g4 ! lastproc = NULL; 4428 sethi %hi(cpcb), %g6 4429 sethi %hi(curproc), %g7 4430 st %g0, [%g7 + %lo(curproc)] ! curproc = NULL; 4431 b,a idle_enter_no_schedlock 4432 /* FALLTHROUGH */ 4433 4434 4435/* Macro used for register window flushing in the context switch code */ 4436#define SAVE save %sp, -64, %sp 4437 4438/* 4439 * When no processes are on the runq, switch 4440 * idles here waiting for something to come ready. 4441 * The registers are set up as noted above. 4442 */ 4443idle: 4444#if defined(MULTIPROCESSOR) 4445 /* 4446 * Change pcb to idle u. area, i.e., set %sp to top of stack 4447 * and %psr to PSR_S, and set cpcb to point to idle_u. 4448 */ 4449 /* XXX: FIXME 4450 * 7 of each: 4451 */ 4452 SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE 4453 restore; restore; restore; restore; restore; restore; restore 4454 4455 sethi %hi(IDLE_UP), %g5 4456 ld [%g5 + %lo(IDLE_UP)], %g5 4457 rd %psr, %g1 ! oldpsr = %psr; 4458 andn %g1, PSR_PIL|PSR_PS, %g1! oldpsr &= ~(PSR_PIL|PSR_PS); 4459 and %g1, PSR_S|PSR_ET, %g1 ! oldpsr |= PSR_S|PSR_ET; 4460 st %g5, [%g6 + %lo(cpcb)] ! cpcb = &idle_u 4461 set USPACE-CCFSZ, %o1 4462 add %g5, %o1, %sp ! set new %sp 4463 clr %g4 ! lastproc = NULL; 4464 4465#ifdef DEBUG 4466 mov %g5, %o2 ! %o2 = _idle_u 4467 SET_SP_REDZONE(%o2, %o1) 4468#endif /* DEBUG */ 4469#endif /* MULTIPROCESSOR */ 4470 4471#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 4472 /* Release the scheduler lock */ 4473 SAVE_GLOBALS_AND_CALL(sched_unlock_idle) 4474#endif 4475 4476idle_enter_no_schedlock: 4477 wr %g1, 0, %psr ! spl0(); 44781: ! spin reading whichqs until nonzero 4479 ld [%g2 + %lo(_C_LABEL(sched_whichqs))], %o3 4480 tst %o3 4481#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 4482 bnz,a idle_leave 4483#else 4484 bnz,a Lsw_scan 4485#endif 4486 ! NB: annulled delay slot (executed when we leave the idle loop) 4487 wr %g1, PSR_PIL, %psr ! (void) splhigh(); 4488 4489 ! Check uvm.page_idle_zero 4490 sethi %hi(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO), %o3 4491 ld [%o3 + %lo(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO)], %o3 4492 tst %o3 4493 bz 1b 4494 nop 4495 4496 SAVE_GLOBALS_AND_CALL(uvm_pageidlezero) 4497 b,a 1b 4498 4499#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 4500idle_leave: 4501 /* Before we leave the idle loop, detain the scheduler lock */ 4502 nop;nop;nop; ! just wrote to %psr; delay before doing a `save' 4503 SAVE_GLOBALS_AND_CALL(sched_lock_idle) 4504 b,a Lsw_scan 4505#endif 4506 4507Lsw_panic_rq: 4508 sethi %hi(1f), %o0 4509 call _C_LABEL(panic) 4510 or %lo(1f), %o0, %o0 4511Lsw_panic_wchan: 4512 sethi %hi(2f), %o0 4513 call _C_LABEL(panic) 4514 or %lo(2f), %o0, %o0 4515Lsw_panic_srun: 4516 sethi %hi(3f), %o0 4517 call _C_LABEL(panic) 4518 or %lo(3f), %o0, %o0 45191: .asciz "switch rq" 45202: .asciz "switch wchan" 45213: .asciz "switch SRUN" 4522 _ALIGN 4523 4524/* 4525 * cpu_switch() picks a process to run and runs it, saving the current 4526 * one away. On the assumption that (since most workstations are 4527 * single user machines) the chances are quite good that the new 4528 * process will turn out to be the current process, we defer saving 4529 * it here until we have found someone to load. If that someone 4530 * is the current process we avoid both store and load. 4531 * 4532 * cpu_switch() is always entered at splstatclock or splhigh. 4533 * 4534 * IT MIGHT BE WORTH SAVING BEFORE ENTERING idle TO AVOID HAVING TO 4535 * SAVE LATER WHEN SOMEONE ELSE IS READY ... MUST MEASURE! 4536 */ 4537 .globl _C_LABEL(__ffstab) 4538ENTRY(cpu_switch) 4539 /* 4540 * REGISTER USAGE AT THIS POINT: 4541 * %g1 = oldpsr (excluding ipl bits) 4542 * %g2 = %hi(whichqs) 4543 * %g3 = p 4544 * %g4 = lastproc 4545 * %g5 = tmp 0 4546 * %g6 = %hi(cpcb) 4547 * %g7 = %hi(curproc) 4548 * %o0 = tmp 1 4549 * %o1 = tmp 2 4550 * %o2 = tmp 3 4551 * %o3 = tmp 4, then at Lsw_scan, whichqs 4552 * %o4 = tmp 5, then at Lsw_scan, which 4553 * %o5 = tmp 6, then at Lsw_scan, q 4554 */ 4555 mov %o0, %g4 ! lastproc = p; 4556 sethi %hi(_C_LABEL(sched_whichqs)), %g2 ! set up addr regs 4557 sethi %hi(cpcb), %g6 4558 ld [%g6 + %lo(cpcb)], %o0 4559 std %o6, [%o0 + PCB_SP] ! cpcb->pcb_<sp,pc> = <sp,pc>; 4560 rd %psr, %g1 ! oldpsr = %psr; 4561 st %g1, [%o0 + PCB_PSR] ! cpcb->pcb_psr = oldpsr; 4562 andn %g1, PSR_PIL, %g1 ! oldpsr &= ~PSR_PIL; 4563 sethi %hi(curproc), %g7 4564 st %g0, [%g7 + %lo(curproc)] ! curproc = NULL; 4565 4566Lsw_scan: 4567 nop; nop; nop ! paranoia 4568 ld [%g2 + %lo(_C_LABEL(sched_whichqs))], %o3 4569 4570 /* 4571 * Optimized inline expansion of `which = ffs(whichqs) - 1'; 4572 * branches to idle if ffs(whichqs) was 0. 4573 */ 4574 set _C_LABEL(__ffstab), %o2 4575 andcc %o3, 0xff, %o1 ! byte 0 zero? 4576 bz,a 1f ! yes, try byte 1 4577 srl %o3, 8, %o0 4578 b 2f ! ffs = ffstab[byte0]; which = ffs - 1; 4579 ldsb [%o2 + %o1], %o0 45801: andcc %o0, 0xff, %o1 ! byte 1 zero? 4581 bz,a 1f ! yes, try byte 2 4582 srl %o0, 8, %o0 4583 ldsb [%o2 + %o1], %o0 ! which = ffstab[byte1] + 7; 4584 b 3f 4585 add %o0, 7, %o4 45861: andcc %o0, 0xff, %o1 ! byte 2 zero? 4587 bz,a 1f ! yes, try byte 3 4588 srl %o0, 8, %o0 4589 ldsb [%o2 + %o1], %o0 ! which = ffstab[byte2] + 15; 4590 b 3f 4591 add %o0, 15, %o4 45921: ldsb [%o2 + %o0], %o0 ! ffs = ffstab[byte3] + 24 4593 addcc %o0, 24, %o0 ! (note that ffstab[0] == -24) 4594 bz idle ! if answer was 0, go idle 4595 EMPTY 45962: sub %o0, 1, %o4 ! which = ffs(whichqs) - 1 45973: /* end optimized inline expansion */ 4598 4599 /* 4600 * We found a nonempty run queue. Take its first process. 4601 */ 4602 set _C_LABEL(sched_qs), %o5 ! q = &qs[which]; 4603 sll %o4, 3, %o0 4604 add %o0, %o5, %o5 4605 ld [%o5], %g3 ! p = q->ph_link; 4606 cmp %g3, %o5 ! if (p == q) 4607 be Lsw_panic_rq ! panic("switch rq"); 4608 EMPTY 4609 ld [%g3], %o0 ! tmp0 = p->p_forw; 4610 st %o0, [%o5] ! q->ph_link = tmp0; 4611 st %o5, [%o0 + 4] ! tmp0->p_back = q; 4612 cmp %o0, %o5 ! if (tmp0 == q) 4613 bne 1f 4614 EMPTY 4615 mov 1, %o1 ! whichqs &= ~(1 << which); 4616 sll %o1, %o4, %o1 4617 andn %o3, %o1, %o3 4618 st %o3, [%g2 + %lo(_C_LABEL(sched_whichqs))] 46191: 4620 /* 4621 * PHASE TWO: NEW REGISTER USAGE: 4622 * %g1 = oldpsr (excluding ipl bits) 4623 * %g2 = newpsr 4624 * %g3 = p 4625 * %g4 = lastproc 4626 * %g5 = newpcb 4627 * %g6 = %hi(cpcb) 4628 * %g7 = %hi(curproc) 4629 * %o0 = tmp 1 4630 * %o1 = tmp 2 4631 * %o2 = tmp 3 4632 * %o3 = vm 4633 */ 4634 4635 /* firewalls */ 4636 ld [%g3 + P_WCHAN], %o0 ! if (p->p_wchan) 4637 tst %o0 4638 bne Lsw_panic_wchan ! panic("switch wchan"); 4639 EMPTY 4640 ldsb [%g3 + P_STAT], %o0 ! if (p->p_stat != SRUN) 4641 cmp %o0, SRUN 4642 bne Lsw_panic_srun ! panic("switch SRUN"); 4643 EMPTY 4644 4645 /* 4646 * Committed to running process p. 4647 * It may be the same as the one we were running before. 4648 */ 4649 mov SONPROC, %o0 ! p->p_stat = SONPROC; 4650 stb %o0, [%g3 + P_STAT] 4651 4652 /* p->p_cpu initialized in fork1() for single-processor */ 4653#if defined(MULTIPROCESSOR) 4654 sethi %hi(_CISELFP), %o0 ! p->p_cpu = cpuinfo.ci_self; 4655 ld [%o0 + %lo(_CISELFP)], %o0 4656 st %o0, [%g3 + P_CPU] 4657#endif 4658 4659 sethi %hi(_C_LABEL(want_resched)), %o0 ! want_resched = 0; 4660 st %g0, [%o0 + %lo(_C_LABEL(want_resched))] 4661#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 4662 /* Done with the run queues; release the scheduler lock */ 4663 SAVE_GLOBALS_AND_CALL(sched_unlock_idle) 4664#endif 4665 ld [%g3 + P_ADDR], %g5 ! newpcb = p->p_addr; 4666 st %g0, [%g3 + 4] ! p->p_back = NULL; 4667 ld [%g5 + PCB_PSR], %g2 ! newpsr = newpcb->pcb_psr; 4668 st %g3, [%g7 + %lo(curproc)] ! curproc = p; 4669 4670 cmp %g3, %g4 ! p == lastproc? 4671 be,a Lsw_sameproc ! yes, go return 0 4672 wr %g2, 0, %psr ! (after restoring ipl) 4673 4674 /* 4675 * Not the old process. Save the old process, if any; 4676 * then load p. 4677 */ 4678 tst %g4 4679 be,a Lsw_load ! if no old process, go load 4680 wr %g1, (PIL_CLOCK << 8) | PSR_ET, %psr 4681 4682 INCR(_C_LABEL(nswitchdiff)) ! clobbers %o0,%o1 4683 /* 4684 * save: write back all windows (including the current one). 4685 * XXX crude; knows nwindows <= 8 4686 */ 4687wb1: /* 7 of each: */ 4688 SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE 4689 restore; restore; restore; restore; restore; restore; restore 4690 4691 /* 4692 * Load the new process. To load, we must change stacks and 4693 * alter cpcb and %wim, hence we must disable traps. %psr is 4694 * currently equal to oldpsr (%g1) ^ (PIL_CLOCK << 8); 4695 * this means that PSR_ET is on. Likewise, PSR_ET is on 4696 * in newpsr (%g2), although we do not know newpsr's ipl. 4697 * 4698 * We also must load up the `in' and `local' registers. 4699 */ 4700 wr %g1, (PIL_CLOCK << 8) | PSR_ET, %psr 4701Lsw_load: 4702! wr %g1, (PIL_CLOCK << 8) | PSR_ET, %psr ! done above 4703 /* compute new wim */ 4704 ld [%g5 + PCB_WIM], %o0 4705 mov 1, %o1 4706 sll %o1, %o0, %o0 4707 wr %o0, 0, %wim ! %wim = 1 << newpcb->pcb_wim; 4708 /* Clear FP & CP enable bits, as well as the PIL field */ 4709 /* now must not change %psr for 3 more instrs */ 4710/*1*/ set PSR_EF|PSR_EC|PSR_PIL, %o0 4711/*2*/ andn %g2, %o0, %g2 ! newpsr &= ~(PSR_EF|PSR_EC|PSR_PIL); 4712/*3*/ nop 4713 /* set new psr, but with traps disabled */ 4714 wr %g2, PSR_ET, %psr ! %psr = newpsr ^ PSR_ET; 4715 /* set new cpcb */ 4716 st %g5, [%g6 + %lo(cpcb)] ! cpcb = newpcb; 4717 ldd [%g5 + PCB_SP], %o6 ! <sp,pc> = newpcb->pcb_<sp,pc> 4718 /* load window */ 4719 ldd [%sp + (0*8)], %l0 4720 ldd [%sp + (1*8)], %l2 4721 ldd [%sp + (2*8)], %l4 4722 ldd [%sp + (3*8)], %l6 4723 ldd [%sp + (4*8)], %i0 4724 ldd [%sp + (5*8)], %i2 4725 ldd [%sp + (6*8)], %i4 4726 ldd [%sp + (7*8)], %i6 4727#ifdef DEBUG 4728 mov %g5, %o0 4729 SET_SP_REDZONE(%o0, %o1) 4730 CHECK_SP_REDZONE(%o0, %o1) 4731#endif 4732 /* finally, enable traps and continue at splclock() */ 4733 wr %g2, PIL_CLOCK << 8 , %psr ! psr = newpsr; 4734 4735 /* 4736 * Now running p. Make sure it has a context so that it 4737 * can talk about user space stuff. (Its pcb_uw is currently 4738 * zero so it is safe to have interrupts going here.) 4739 */ 4740 ld [%g3 + P_VMSPACE], %o3 ! vm = p->p_vmspace; 4741 ld [%o3 + VM_PMAP], %o3 ! pm = vm->vm_map.vm_pmap; 4742 ld [%o3 + PMAP_CTX], %o0 ! if (pm->pm_ctx != NULL) 4743 tst %o0 4744 bnz,a Lsw_havectx ! goto havecontext; 4745 ld [%o3 + PMAP_CTXNUM], %o0 ! load context number 4746 4747 /* p does not have a context: call ctx_alloc to get one */ 4748 save %sp, -CCFSZ, %sp 4749 call _C_LABEL(ctx_alloc) ! ctx_alloc(pm); 4750 mov %i3, %o0 4751 4752 ret 4753 restore 4754 4755 /* p does have a context: just switch to it */ 4756Lsw_havectx: 4757 ! context is in %o0 4758 ! pmap is in %o3 4759#if (defined(SUN4) || defined(SUN4C)) && defined(SUN4M) 4760NOP_ON_4M_15: 4761 b,a 1f 4762 b,a 2f 4763#endif 47641: 4765#if defined(SUN4) || defined(SUN4C) 4766 set AC_CONTEXT, %o1 4767 retl 4768 stba %o0, [%o1] ASI_CONTROL ! setcontext(vm->vm_pmap.pm_ctxnum); 4769#endif 47702: 4771#if defined(SUN4M) 4772 /* 4773 * Flush caches that need to be flushed on context switch. 4774 * We know this is currently only necessary on the sun4m hypersparc. 4775 */ 4776 set CPUINFO_VA+CPUINFO_PURE_VCACHE_FLS, %o2 4777 ld [%o2], %o2 4778 mov %o7, %g7 ! save return address 4779 jmpl %o2, %o7 ! this function must not clobber %o0 and %g7 4780 nop 4781 4782 set SRMMU_CXR, %o1 4783 jmp %g7 + 8 4784 sta %o0, [%o1] ASI_SRMMU ! setcontext(vm->vm_pmap.pm_ctxnum); 4785#endif 4786 4787Lsw_sameproc: 4788 /* 4789 * We are resuming the process that was running at the 4790 * call to switch(). Just set psr ipl and return. 4791 */ 4792! wr %g2, 0 %psr ! %psr = newpsr; (done earlier) 4793 nop 4794 retl 4795 nop 4796 4797 4798/* 4799 * Snapshot the current process so that stack frames are up to date. 4800 * Only used just before a crash dump. 4801 */ 4802ENTRY(snapshot) 4803 std %o6, [%o0 + PCB_SP] ! save sp 4804 rd %psr, %o1 ! save psr 4805 st %o1, [%o0 + PCB_PSR] 4806 4807 /* 4808 * Just like switch(); same XXX comments apply. 4809 * 7 of each. Minor tweak: the 7th restore is 4810 * done after a ret. 4811 */ 4812 SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE 4813 restore; restore; restore; restore; restore; restore; ret; restore 4814 4815 4816/* 4817 * cpu_fork() arrange for proc_trampoline() to run after a process gets 4818 * chosen in switch(). The stack frame will contain a function pointer 4819 * in %l0, and an argument to pass to it in %l2. 4820 * 4821 * If the function *(%l0) returns, we arrange for an immediate return 4822 * to user mode. This happens in two known cases: after execve(2) of init, 4823 * and when returning a child to user mode after a fork(2). 4824 * 4825 * If were setting up a kernel thread, the function *(%l0) will not return. 4826 */ 4827ENTRY(proc_trampoline) 4828 /* 4829 * Note: cpu_fork() has set up a stack frame for us to run in, 4830 * so we can call other functions from here without using 4831 * `save ... restore'. 4832 */ 4833#if defined(MULTIPROCESSOR) 4834 /* Finish setup in SMP environment: acquire locks etc. */ 4835 call _C_LABEL(proc_trampoline_mp) 4836 nop 4837#endif 4838 4839 /* Reset interrupt level */ 4840 rd %psr, %o0 4841 andn %o0, PSR_PIL, %o0 ! psr &= ~PSR_PIL; 4842 wr %o0, 0, %psr ! (void) spl0(); 4843 nop ! psr delay; the next 2 instructions 4844 ! can safely be made part of the 4845 ! required 3 instructions psr delay 4846 call %l0 4847 mov %l1, %o0 4848 4849 /* 4850 * Here we finish up as in syscall, but simplified. 4851 * cpu_fork() or sendsig() (if we took a pending signal 4852 * in child_return()) will have set the user-space return 4853 * address in tf_pc. In both cases, %npc should be %pc + 4. 4854 */ 4855 mov PSR_S, %l0 ! user psr (no need to load it) 4856 !?wr %g0, 2, %wim ! %wim = 2 4857 ld [%sp + CCFSZ + 4], %l1 ! pc = tf->tf_pc from cpu_fork() 4858 b return_from_syscall 4859 add %l1, 4, %l2 ! npc = pc+4 4860 4861/* 4862 * {fu,su}{,i}{byte,word} 4863 */ 4864_ENTRY(fuiword) 4865ENTRY(fuword) 4866 set KERNBASE, %o2 4867 cmp %o0, %o2 ! if addr >= KERNBASE... 4868 bgeu Lfsbadaddr 4869 EMPTY 4870 btst 3, %o0 ! or has low bits set... 4871 bnz Lfsbadaddr ! go return -1 4872 EMPTY 4873 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfserr; 4874 ld [%o2 + %lo(cpcb)], %o2 4875 set Lfserr, %o3 4876 st %o3, [%o2 + PCB_ONFAULT] 4877 ld [%o0], %o0 ! fetch the word 4878 retl ! phew, made it, return the word 4879 st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault 4880 4881Lfserr: 4882 st %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault 4883Lfsbadaddr: 4884 retl ! and return error indicator 4885 mov -1, %o0 4886 4887 /* 4888 * This is just like Lfserr, but it's a global label that allows 4889 * mem_access_fault() to check to see that we don't want to try to 4890 * page in the fault. It's used by fuswintr() etc. 4891 */ 4892 .globl _C_LABEL(Lfsbail) 4893_C_LABEL(Lfsbail): 4894 st %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault 4895 retl ! and return error indicator 4896 mov -1, %o0 4897 4898 /* 4899 * Like fusword but callable from interrupt context. 4900 * Fails if data isn't resident. 4901 */ 4902ENTRY(fuswintr) 4903 set KERNBASE, %o2 4904 cmp %o0, %o2 ! if addr >= KERNBASE 4905 bgeu Lfsbadaddr ! return error 4906 EMPTY 4907 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfsbail; 4908 ld [%o2 + %lo(cpcb)], %o2 4909 set _C_LABEL(Lfsbail), %o3 4910 st %o3, [%o2 + PCB_ONFAULT] 4911 lduh [%o0], %o0 ! fetch the halfword 4912 retl ! made it 4913 st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault 4914 4915ENTRY(fusword) 4916 set KERNBASE, %o2 4917 cmp %o0, %o2 ! if addr >= KERNBASE 4918 bgeu Lfsbadaddr ! return error 4919 EMPTY 4920 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfserr; 4921 ld [%o2 + %lo(cpcb)], %o2 4922 set Lfserr, %o3 4923 st %o3, [%o2 + PCB_ONFAULT] 4924 lduh [%o0], %o0 ! fetch the halfword 4925 retl ! made it 4926 st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault 4927 4928_ENTRY(fuibyte) 4929ENTRY(fubyte) 4930 set KERNBASE, %o2 4931 cmp %o0, %o2 ! if addr >= KERNBASE 4932 bgeu Lfsbadaddr ! return error 4933 EMPTY 4934 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfserr; 4935 ld [%o2 + %lo(cpcb)], %o2 4936 set Lfserr, %o3 4937 st %o3, [%o2 + PCB_ONFAULT] 4938 ldub [%o0], %o0 ! fetch the byte 4939 retl ! made it 4940 st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault 4941 4942_ENTRY(suiword) 4943ENTRY(suword) 4944 set KERNBASE, %o2 4945 cmp %o0, %o2 ! if addr >= KERNBASE ... 4946 bgeu Lfsbadaddr 4947 EMPTY 4948 btst 3, %o0 ! or has low bits set ... 4949 bnz Lfsbadaddr ! go return error 4950 EMPTY 4951 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfserr; 4952 ld [%o2 + %lo(cpcb)], %o2 4953 set Lfserr, %o3 4954 st %o3, [%o2 + PCB_ONFAULT] 4955 st %o1, [%o0] ! store the word 4956 st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault 4957 retl ! and return 0 4958 clr %o0 4959 4960ENTRY(suswintr) 4961 set KERNBASE, %o2 4962 cmp %o0, %o2 ! if addr >= KERNBASE 4963 bgeu Lfsbadaddr ! go return error 4964 EMPTY 4965 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfsbail; 4966 ld [%o2 + %lo(cpcb)], %o2 4967 set _C_LABEL(Lfsbail), %o3 4968 st %o3, [%o2 + PCB_ONFAULT] 4969 sth %o1, [%o0] ! store the halfword 4970 st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault 4971 retl ! and return 0 4972 clr %o0 4973 4974ENTRY(susword) 4975 set KERNBASE, %o2 4976 cmp %o0, %o2 ! if addr >= KERNBASE 4977 bgeu Lfsbadaddr ! go return error 4978 EMPTY 4979 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfserr; 4980 ld [%o2 + %lo(cpcb)], %o2 4981 set Lfserr, %o3 4982 st %o3, [%o2 + PCB_ONFAULT] 4983 sth %o1, [%o0] ! store the halfword 4984 st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault 4985 retl ! and return 0 4986 clr %o0 4987 4988_ENTRY(suibyte) 4989ENTRY(subyte) 4990 set KERNBASE, %o2 4991 cmp %o0, %o2 ! if addr >= KERNBASE 4992 bgeu Lfsbadaddr ! go return error 4993 EMPTY 4994 sethi %hi(cpcb), %o2 ! cpcb->pcb_onfault = Lfserr; 4995 ld [%o2 + %lo(cpcb)], %o2 4996 set Lfserr, %o3 4997 st %o3, [%o2 + PCB_ONFAULT] 4998 stb %o1, [%o0] ! store the byte 4999 st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault 5000 retl ! and return 0 5001 clr %o0 5002 5003/* probeget and probeset are meant to be used during autoconfiguration */ 5004 5005/* 5006 * probeget(addr, size) caddr_t addr; int size; 5007 * 5008 * Read or write a (byte,word,longword) from the given address. 5009 * Like {fu,su}{byte,halfword,word} but our caller is supposed 5010 * to know what he is doing... the address can be anywhere. 5011 * 5012 * We optimize for space, rather than time, here. 5013 */ 5014ENTRY(probeget) 5015 ! %o0 = addr, %o1 = (1,2,4) 5016 sethi %hi(cpcb), %o2 5017 ld [%o2 + %lo(cpcb)], %o2 ! cpcb->pcb_onfault = Lfserr; 5018 set Lfserr, %o5 5019 st %o5, [%o2 + PCB_ONFAULT] 5020 btst 1, %o1 5021 bnz,a 0f ! if (len & 1) 5022 ldub [%o0], %o0 ! value = *(char *)addr; 50230: btst 2, %o1 5024 bnz,a 0f ! if (len & 2) 5025 lduh [%o0], %o0 ! value = *(short *)addr; 50260: btst 4, %o1 5027 bnz,a 0f ! if (len & 4) 5028 ld [%o0], %o0 ! value = *(int *)addr; 50290: retl ! made it, clear onfault and return 5030 st %g0, [%o2 + PCB_ONFAULT] 5031 5032/* 5033 * probeset(addr, size, val) caddr_t addr; int size, val; 5034 * 5035 * As above, but we return 0 on success. 5036 */ 5037ENTRY(probeset) 5038 ! %o0 = addr, %o1 = (1,2,4), %o2 = val 5039 sethi %hi(cpcb), %o3 5040 ld [%o3 + %lo(cpcb)], %o3 ! cpcb->pcb_onfault = Lfserr; 5041 set Lfserr, %o5 5042 st %o5, [%o3 + PCB_ONFAULT] 5043 btst 1, %o1 5044 bnz,a 0f ! if (len & 1) 5045 stb %o2, [%o0] ! *(char *)addr = value; 50460: btst 2, %o1 5047 bnz,a 0f ! if (len & 2) 5048 sth %o2, [%o0] ! *(short *)addr = value; 50490: btst 4, %o1 5050 bnz,a 0f ! if (len & 4) 5051 st %o2, [%o0] ! *(int *)addr = value; 50520: clr %o0 ! made it, clear onfault and return 0 5053 retl 5054 st %g0, [%o3 + PCB_ONFAULT] 5055 5056/* 5057 * int xldcontrolb(caddr_t, pcb) 5058 * %o0 %o1 5059 * 5060 * read a byte from the specified address in ASI_CONTROL space. 5061 */ 5062ENTRY(xldcontrolb) 5063 !sethi %hi(cpcb), %o2 5064 !ld [%o2 + %lo(cpcb)], %o2 ! cpcb->pcb_onfault = Lfsbail; 5065 or %o1, %g0, %o2 ! %o2 = %o1 5066 set _C_LABEL(Lfsbail), %o5 5067 st %o5, [%o2 + PCB_ONFAULT] 5068 lduba [%o0] ASI_CONTROL, %o0 ! read 50690: retl 5070 st %g0, [%o2 + PCB_ONFAULT] 5071 5072/* 5073 * int fkbyte(caddr_t, pcb) 5074 * %o0 %o1 5075 * 5076 * Just like fubyte(), but for kernel space. 5077 * (currently used to work around unexplained transient bus errors 5078 * when reading the VME interrupt vector) 5079 */ 5080ENTRY(fkbyte) 5081 or %o1, %g0, %o2 ! %o2 = %o1 5082 set _C_LABEL(Lfsbail), %o5 5083 st %o5, [%o2 + PCB_ONFAULT] 5084 ldub [%o0], %o0 ! fetch the byte 5085 retl ! made it 5086 st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault 5087 5088 5089/* 5090 * copywords(src, dst, nbytes) 5091 * 5092 * Copy `nbytes' bytes from src to dst, both of which are word-aligned; 5093 * nbytes is a multiple of four. It may, however, be zero, in which case 5094 * nothing is to be copied. 5095 */ 5096ENTRY(copywords) 5097 ! %o0 = src, %o1 = dst, %o2 = nbytes 5098 b 1f 5099 deccc 4, %o2 51000: 5101 st %o3, [%o1 + %o2] 5102 deccc 4, %o2 ! while ((n -= 4) >= 0) 51031: 5104 bge,a 0b ! *(int *)(dst+n) = *(int *)(src+n); 5105 ld [%o0 + %o2], %o3 5106 retl 5107 nop 5108 5109/* 5110 * qcopy(src, dst, nbytes) 5111 * 5112 * (q for `quad' or `quick', as opposed to b for byte/block copy) 5113 * 5114 * Just like copywords, but everything is multiples of 8. 5115 */ 5116ENTRY(qcopy) 5117 b 1f 5118 deccc 8, %o2 51190: 5120 std %o4, [%o1 + %o2] 5121 deccc 8, %o2 51221: 5123 bge,a 0b 5124 ldd [%o0 + %o2], %o4 5125 retl 5126 nop 5127 5128/* 5129 * qzero(addr, nbytes) 5130 * 5131 * Zeroes `nbytes' bytes of a quad-aligned virtual address, 5132 * where nbytes is itself a multiple of 8. 5133 */ 5134ENTRY(qzero) 5135 ! %o0 = addr, %o1 = len (in bytes) 5136 clr %g1 51370: 5138 deccc 8, %o1 ! while ((n =- 8) >= 0) 5139 bge,a 0b 5140 std %g0, [%o0 + %o1] ! *(quad *)(addr + n) = 0; 5141 retl 5142 nop 5143 5144/* 5145 * kernel bcopy 5146 * Assumes regions do not overlap; has no useful return value. 5147 * 5148 * Must not use %g7 (see copyin/copyout above). 5149 */ 5150 5151#define BCOPY_SMALL 32 /* if < 32, copy by bytes */ 5152 5153ENTRY(bcopy) 5154 cmp %o2, BCOPY_SMALL 5155Lbcopy_start: 5156 bge,a Lbcopy_fancy ! if >= this many, go be fancy. 5157 btst 7, %o0 ! (part of being fancy) 5158 5159 /* 5160 * Not much to copy, just do it a byte at a time. 5161 */ 5162 deccc %o2 ! while (--len >= 0) 5163 bl 1f 5164 EMPTY 51650: 5166 inc %o0 5167 ldsb [%o0 - 1], %o4 ! (++dst)[-1] = *src++; 5168 stb %o4, [%o1] 5169 deccc %o2 5170 bge 0b 5171 inc %o1 51721: 5173 retl 5174 nop 5175 /* NOTREACHED */ 5176 5177 /* 5178 * Plenty of data to copy, so try to do it optimally. 5179 */ 5180Lbcopy_fancy: 5181 ! check for common case first: everything lines up. 5182! btst 7, %o0 ! done already 5183 bne 1f 5184 EMPTY 5185 btst 7, %o1 5186 be,a Lbcopy_doubles 5187 dec 8, %o2 ! if all lined up, len -= 8, goto bcopy_doubes 5188 5189 ! If the low bits match, we can make these line up. 51901: 5191 xor %o0, %o1, %o3 ! t = src ^ dst; 5192 btst 1, %o3 ! if (t & 1) { 5193 be,a 1f 5194 btst 1, %o0 ! [delay slot: if (src & 1)] 5195 5196 ! low bits do not match, must copy by bytes. 51970: 5198 ldsb [%o0], %o4 ! do { 5199 inc %o0 ! (++dst)[-1] = *src++; 5200 inc %o1 5201 deccc %o2 5202 bnz 0b ! } while (--len != 0); 5203 stb %o4, [%o1 - 1] 5204 retl 5205 nop 5206 /* NOTREACHED */ 5207 5208 ! lowest bit matches, so we can copy by words, if nothing else 52091: 5210 be,a 1f ! if (src & 1) { 5211 btst 2, %o3 ! [delay slot: if (t & 2)] 5212 5213 ! although low bits match, both are 1: must copy 1 byte to align 5214 ldsb [%o0], %o4 ! *dst++ = *src++; 5215 stb %o4, [%o1] 5216 inc %o0 5217 inc %o1 5218 dec %o2 ! len--; 5219 btst 2, %o3 ! } [if (t & 2)] 52201: 5221 be,a 1f ! if (t & 2) { 5222 btst 2, %o0 ! [delay slot: if (src & 2)] 5223 dec 2, %o2 ! len -= 2; 52240: 5225 ldsh [%o0], %o4 ! do { 5226 sth %o4, [%o1] ! *(short *)dst = *(short *)src; 5227 inc 2, %o0 ! dst += 2, src += 2; 5228 deccc 2, %o2 ! } while ((len -= 2) >= 0); 5229 bge 0b 5230 inc 2, %o1 5231 b Lbcopy_mopb ! goto mop_up_byte; 5232 btst 1, %o2 ! } [delay slot: if (len & 1)] 5233 /* NOTREACHED */ 5234 5235 ! low two bits match, so we can copy by longwords 52361: 5237 be,a 1f ! if (src & 2) { 5238 btst 4, %o3 ! [delay slot: if (t & 4)] 5239 5240 ! although low 2 bits match, they are 10: must copy one short to align 5241 ldsh [%o0], %o4 ! (*short *)dst = *(short *)src; 5242 sth %o4, [%o1] 5243 inc 2, %o0 ! dst += 2; 5244 inc 2, %o1 ! src += 2; 5245 dec 2, %o2 ! len -= 2; 5246 btst 4, %o3 ! } [if (t & 4)] 52471: 5248 be,a 1f ! if (t & 4) { 5249 btst 4, %o0 ! [delay slot: if (src & 4)] 5250 dec 4, %o2 ! len -= 4; 52510: 5252 ld [%o0], %o4 ! do { 5253 st %o4, [%o1] ! *(int *)dst = *(int *)src; 5254 inc 4, %o0 ! dst += 4, src += 4; 5255 deccc 4, %o2 ! } while ((len -= 4) >= 0); 5256 bge 0b 5257 inc 4, %o1 5258 b Lbcopy_mopw ! goto mop_up_word_and_byte; 5259 btst 2, %o2 ! } [delay slot: if (len & 2)] 5260 /* NOTREACHED */ 5261 5262 ! low three bits match, so we can copy by doublewords 52631: 5264 be 1f ! if (src & 4) { 5265 dec 8, %o2 ! [delay slot: len -= 8] 5266 ld [%o0], %o4 ! *(int *)dst = *(int *)src; 5267 st %o4, [%o1] 5268 inc 4, %o0 ! dst += 4, src += 4, len -= 4; 5269 inc 4, %o1 5270 dec 4, %o2 ! } 52711: 5272Lbcopy_doubles: 5273 ldd [%o0], %o4 ! do { 5274 std %o4, [%o1] ! *(double *)dst = *(double *)src; 5275 inc 8, %o0 ! dst += 8, src += 8; 5276 deccc 8, %o2 ! } while ((len -= 8) >= 0); 5277 bge Lbcopy_doubles 5278 inc 8, %o1 5279 5280 ! check for a usual case again (save work) 5281 btst 7, %o2 ! if ((len & 7) == 0) 5282 be Lbcopy_done ! goto bcopy_done; 5283 5284 btst 4, %o2 ! if ((len & 4)) == 0) 5285 be,a Lbcopy_mopw ! goto mop_up_word_and_byte; 5286 btst 2, %o2 ! [delay slot: if (len & 2)] 5287 ld [%o0], %o4 ! *(int *)dst = *(int *)src; 5288 st %o4, [%o1] 5289 inc 4, %o0 ! dst += 4; 5290 inc 4, %o1 ! src += 4; 5291 btst 2, %o2 ! } [if (len & 2)] 5292 52931: 5294 ! mop up trailing word (if present) and byte (if present). 5295Lbcopy_mopw: 5296 be Lbcopy_mopb ! no word, go mop up byte 5297 btst 1, %o2 ! [delay slot: if (len & 1)] 5298 ldsh [%o0], %o4 ! *(short *)dst = *(short *)src; 5299 be Lbcopy_done ! if ((len & 1) == 0) goto done; 5300 sth %o4, [%o1] 5301 ldsb [%o0 + 2], %o4 ! dst[2] = src[2]; 5302 retl 5303 stb %o4, [%o1 + 2] 5304 /* NOTREACHED */ 5305 5306 ! mop up trailing byte (if present). 5307Lbcopy_mopb: 5308 bne,a 1f 5309 ldsb [%o0], %o4 5310 5311Lbcopy_done: 5312 retl 5313 nop 5314 53151: 5316 retl 5317 stb %o4,[%o1] 5318/* 5319 * ovbcopy(src, dst, len): like bcopy, but regions may overlap. 5320 */ 5321ENTRY(ovbcopy) 5322 cmp %o0, %o1 ! src < dst? 5323 bgeu Lbcopy_start ! no, go copy forwards as via bcopy 5324 cmp %o2, BCOPY_SMALL! (check length for doublecopy first) 5325 5326 /* 5327 * Since src comes before dst, and the regions might overlap, 5328 * we have to do the copy starting at the end and working backwards. 5329 */ 5330 add %o2, %o0, %o0 ! src += len 5331 add %o2, %o1, %o1 ! dst += len 5332 bge,a Lback_fancy ! if len >= BCOPY_SMALL, go be fancy 5333 btst 3, %o0 5334 5335 /* 5336 * Not much to copy, just do it a byte at a time. 5337 */ 5338 deccc %o2 ! while (--len >= 0) 5339 bl 1f 5340 EMPTY 53410: 5342 dec %o0 ! *--dst = *--src; 5343 ldsb [%o0], %o4 5344 dec %o1 5345 deccc %o2 5346 bge 0b 5347 stb %o4, [%o1] 53481: 5349 retl 5350 nop 5351 5352 /* 5353 * Plenty to copy, try to be optimal. 5354 * We only bother with word/halfword/byte copies here. 5355 */ 5356Lback_fancy: 5357! btst 3, %o0 ! done already 5358 bnz 1f ! if ((src & 3) == 0 && 5359 btst 3, %o1 ! (dst & 3) == 0) 5360 bz,a Lback_words ! goto words; 5361 dec 4, %o2 ! (done early for word copy) 5362 53631: 5364 /* 5365 * See if the low bits match. 5366 */ 5367 xor %o0, %o1, %o3 ! t = src ^ dst; 5368 btst 1, %o3 5369 bz,a 3f ! if (t & 1) == 0, can do better 5370 btst 1, %o0 5371 5372 /* 5373 * Nope; gotta do byte copy. 5374 */ 53752: 5376 dec %o0 ! do { 5377 ldsb [%o0], %o4 ! *--dst = *--src; 5378 dec %o1 5379 deccc %o2 ! } while (--len != 0); 5380 bnz 2b 5381 stb %o4, [%o1] 5382 retl 5383 nop 5384 53853: 5386 /* 5387 * Can do halfword or word copy, but might have to copy 1 byte first. 5388 */ 5389! btst 1, %o0 ! done earlier 5390 bz,a 4f ! if (src & 1) { /* copy 1 byte */ 5391 btst 2, %o3 ! (done early) 5392 dec %o0 ! *--dst = *--src; 5393 ldsb [%o0], %o4 5394 dec %o1 5395 stb %o4, [%o1] 5396 dec %o2 ! len--; 5397 btst 2, %o3 ! } 5398 53994: 5400 /* 5401 * See if we can do a word copy ((t&2) == 0). 5402 */ 5403! btst 2, %o3 ! done earlier 5404 bz,a 6f ! if (t & 2) == 0, can do word copy 5405 btst 2, %o0 ! (src&2, done early) 5406 5407 /* 5408 * Gotta do halfword copy. 5409 */ 5410 dec 2, %o2 ! len -= 2; 54115: 5412 dec 2, %o0 ! do { 5413 ldsh [%o0], %o4 ! src -= 2; 5414 dec 2, %o1 ! dst -= 2; 5415 deccc 2, %o0 ! *(short *)dst = *(short *)src; 5416 bge 5b ! } while ((len -= 2) >= 0); 5417 sth %o4, [%o1] 5418 b Lback_mopb ! goto mop_up_byte; 5419 btst 1, %o2 ! (len&1, done early) 5420 54216: 5422 /* 5423 * We can do word copies, but we might have to copy 5424 * one halfword first. 5425 */ 5426! btst 2, %o0 ! done already 5427 bz 7f ! if (src & 2) { 5428 dec 4, %o2 ! (len -= 4, done early) 5429 dec 2, %o0 ! src -= 2, dst -= 2; 5430 ldsh [%o0], %o4 ! *(short *)dst = *(short *)src; 5431 dec 2, %o1 5432 sth %o4, [%o1] 5433 dec 2, %o2 ! len -= 2; 5434 ! } 5435 54367: 5437Lback_words: 5438 /* 5439 * Do word copies (backwards), then mop up trailing halfword 5440 * and byte if any. 5441 */ 5442! dec 4, %o2 ! len -= 4, done already 54430: ! do { 5444 dec 4, %o0 ! src -= 4; 5445 dec 4, %o1 ! src -= 4; 5446 ld [%o0], %o4 ! *(int *)dst = *(int *)src; 5447 deccc 4, %o2 ! } while ((len -= 4) >= 0); 5448 bge 0b 5449 st %o4, [%o1] 5450 5451 /* 5452 * Check for trailing shortword. 5453 */ 5454 btst 2, %o2 ! if (len & 2) { 5455 bz,a 1f 5456 btst 1, %o2 ! (len&1, done early) 5457 dec 2, %o0 ! src -= 2, dst -= 2; 5458 ldsh [%o0], %o4 ! *(short *)dst = *(short *)src; 5459 dec 2, %o1 5460 sth %o4, [%o1] ! } 5461 btst 1, %o2 5462 5463 /* 5464 * Check for trailing byte. 5465 */ 54661: 5467Lback_mopb: 5468! btst 1, %o2 ! (done already) 5469 bnz,a 1f ! if (len & 1) { 5470 ldsb [%o0 - 1], %o4 ! b = src[-1]; 5471 retl 5472 nop 54731: 5474 retl ! dst[-1] = b; 5475 stb %o4, [%o1 - 1] ! } 5476 5477/* 5478 * kcopy() is exactly like bcopy except that it set pcb_onfault such that 5479 * when a fault occurs, it is able to return -1 to indicate this to the 5480 * caller. 5481 */ 5482ENTRY(kcopy) 5483 sethi %hi(cpcb), %o5 ! cpcb->pcb_onfault = Lkcerr; 5484 ld [%o5 + %lo(cpcb)], %o5 5485 set Lkcerr, %o3 5486 ld [%o5 + PCB_ONFAULT], %g1! save current onfault handler 5487 st %o3, [%o5 + PCB_ONFAULT] 5488 5489 cmp %o2, BCOPY_SMALL 5490Lkcopy_start: 5491 bge,a Lkcopy_fancy ! if >= this many, go be fancy. 5492 btst 7, %o0 ! (part of being fancy) 5493 5494 /* 5495 * Not much to copy, just do it a byte at a time. 5496 */ 5497 deccc %o2 ! while (--len >= 0) 5498 bl 1f 5499 EMPTY 55000: 5501 ldsb [%o0], %o4 ! *dst++ = *src++; 5502 inc %o0 5503 stb %o4, [%o1] 5504 deccc %o2 5505 bge 0b 5506 inc %o1 55071: 5508 st %g1, [%o5 + PCB_ONFAULT] ! restore onfault 5509 retl 5510 mov 0, %o0 ! delay slot: return success 5511 /* NOTREACHED */ 5512 5513 /* 5514 * Plenty of data to copy, so try to do it optimally. 5515 */ 5516Lkcopy_fancy: 5517 ! check for common case first: everything lines up. 5518! btst 7, %o0 ! done already 5519 bne 1f 5520 EMPTY 5521 btst 7, %o1 5522 be,a Lkcopy_doubles 5523 dec 8, %o2 ! if all lined up, len -= 8, goto bcopy_doubes 5524 5525 ! If the low bits match, we can make these line up. 55261: 5527 xor %o0, %o1, %o3 ! t = src ^ dst; 5528 btst 1, %o3 ! if (t & 1) { 5529 be,a 1f 5530 btst 1, %o0 ! [delay slot: if (src & 1)] 5531 5532 ! low bits do not match, must copy by bytes. 55330: 5534 ldsb [%o0], %o4 ! do { 5535 inc %o0 ! *dst++ = *src++; 5536 stb %o4, [%o1] 5537 deccc %o2 5538 bnz 0b ! } while (--len != 0); 5539 inc %o1 5540 st %g1, [%o5 + PCB_ONFAULT] ! restore onfault 5541 retl 5542 mov 0, %o0 ! delay slot: return success 5543 /* NOTREACHED */ 5544 5545 ! lowest bit matches, so we can copy by words, if nothing else 55461: 5547 be,a 1f ! if (src & 1) { 5548 btst 2, %o3 ! [delay slot: if (t & 2)] 5549 5550 ! although low bits match, both are 1: must copy 1 byte to align 5551 ldsb [%o0], %o4 ! *dst++ = *src++; 5552 inc %o0 5553 stb %o4, [%o1] 5554 dec %o2 ! len--; 5555 inc %o1 5556 btst 2, %o3 ! } [if (t & 2)] 55571: 5558 be,a 1f ! if (t & 2) { 5559 btst 2, %o0 ! [delay slot: if (src & 2)] 5560 dec 2, %o2 ! len -= 2; 55610: 5562 ldsh [%o0], %o4 ! do { 5563 inc 2, %o0 ! dst += 2, src += 2; 5564 sth %o4, [%o1] ! *(short *)dst = *(short *)src; 5565 deccc 2, %o2 ! } while ((len -= 2) >= 0); 5566 bge 0b 5567 inc 2, %o1 5568 b Lkcopy_mopb ! goto mop_up_byte; 5569 btst 1, %o2 ! } [delay slot: if (len & 1)] 5570 /* NOTREACHED */ 5571 5572 ! low two bits match, so we can copy by longwords 55731: 5574 be,a 1f ! if (src & 2) { 5575 btst 4, %o3 ! [delay slot: if (t & 4)] 5576 5577 ! although low 2 bits match, they are 10: must copy one short to align 5578 ldsh [%o0], %o4 ! (*short *)dst = *(short *)src; 5579 inc 2, %o0 ! dst += 2; 5580 sth %o4, [%o1] 5581 dec 2, %o2 ! len -= 2; 5582 inc 2, %o1 ! src += 2; 5583 btst 4, %o3 ! } [if (t & 4)] 55841: 5585 be,a 1f ! if (t & 4) { 5586 btst 4, %o0 ! [delay slot: if (src & 4)] 5587 dec 4, %o2 ! len -= 4; 55880: 5589 ld [%o0], %o4 ! do { 5590 inc 4, %o0 ! dst += 4, src += 4; 5591 st %o4, [%o1] ! *(int *)dst = *(int *)src; 5592 deccc 4, %o2 ! } while ((len -= 4) >= 0); 5593 bge 0b 5594 inc 4, %o1 5595 b Lkcopy_mopw ! goto mop_up_word_and_byte; 5596 btst 2, %o2 ! } [delay slot: if (len & 2)] 5597 /* NOTREACHED */ 5598 5599 ! low three bits match, so we can copy by doublewords 56001: 5601 be 1f ! if (src & 4) { 5602 dec 8, %o2 ! [delay slot: len -= 8] 5603 ld [%o0], %o4 ! *(int *)dst = *(int *)src; 5604 inc 4, %o0 ! dst += 4, src += 4, len -= 4; 5605 st %o4, [%o1] 5606 dec 4, %o2 ! } 5607 inc 4, %o1 56081: 5609Lkcopy_doubles: 5610 ! swap %o4 with %o2 during doubles copy, since %o5 is verboten 5611 mov %o2, %o4 5612Lkcopy_doubles2: 5613 ldd [%o0], %o2 ! do { 5614 inc 8, %o0 ! dst += 8, src += 8; 5615 std %o2, [%o1] ! *(double *)dst = *(double *)src; 5616 deccc 8, %o4 ! } while ((len -= 8) >= 0); 5617 bge Lkcopy_doubles2 5618 inc 8, %o1 5619 mov %o4, %o2 ! restore len 5620 5621 ! check for a usual case again (save work) 5622 btst 7, %o2 ! if ((len & 7) == 0) 5623 be Lkcopy_done ! goto bcopy_done; 5624 5625 btst 4, %o2 ! if ((len & 4)) == 0) 5626 be,a Lkcopy_mopw ! goto mop_up_word_and_byte; 5627 btst 2, %o2 ! [delay slot: if (len & 2)] 5628 ld [%o0], %o4 ! *(int *)dst = *(int *)src; 5629 inc 4, %o0 ! dst += 4; 5630 st %o4, [%o1] 5631 inc 4, %o1 ! src += 4; 5632 btst 2, %o2 ! } [if (len & 2)] 5633 56341: 5635 ! mop up trailing word (if present) and byte (if present). 5636Lkcopy_mopw: 5637 be Lkcopy_mopb ! no word, go mop up byte 5638 btst 1, %o2 ! [delay slot: if (len & 1)] 5639 ldsh [%o0], %o4 ! *(short *)dst = *(short *)src; 5640 be Lkcopy_done ! if ((len & 1) == 0) goto done; 5641 sth %o4, [%o1] 5642 ldsb [%o0 + 2], %o4 ! dst[2] = src[2]; 5643 stb %o4, [%o1 + 2] 5644 st %g1, [%o5 + PCB_ONFAULT]! restore onfault 5645 retl 5646 mov 0, %o0 ! delay slot: return success 5647 /* NOTREACHED */ 5648 5649 ! mop up trailing byte (if present). 5650Lkcopy_mopb: 5651 bne,a 1f 5652 ldsb [%o0], %o4 5653 5654Lkcopy_done: 5655 st %g1, [%o5 + PCB_ONFAULT] ! restore onfault 5656 retl 5657 mov 0, %o0 ! delay slot: return success 5658 /* NOTREACHED */ 5659 56601: 5661 stb %o4, [%o1] 5662 st %g1, [%o5 + PCB_ONFAULT] ! restore onfault 5663 retl 5664 mov 0, %o0 ! delay slot: return success 5665 /* NOTREACHED */ 5666 5667Lkcerr: 5668 retl 5669 st %g1, [%o5 + PCB_ONFAULT] ! restore onfault 5670 /* NOTREACHED */ 5671 5672/* 5673 * savefpstate(f) struct fpstate *f; 5674 * 5675 * Store the current FPU state. The first `st %fsr' may cause a trap; 5676 * our trap handler knows how to recover (by `returning' to savefpcont). 5677 */ 5678ENTRY(savefpstate) 5679 rd %psr, %o1 ! enable FP before we begin 5680 set PSR_EF, %o2 5681 or %o1, %o2, %o1 5682 wr %o1, 0, %psr 5683 /* do some setup work while we wait for PSR_EF to turn on */ 5684 set FSR_QNE, %o5 ! QNE = 0x2000, too big for immediate 5685 clr %o3 ! qsize = 0; 5686 nop ! (still waiting for PSR_EF) 5687special_fp_store: 5688 st %fsr, [%o0 + FS_FSR] ! f->fs_fsr = getfsr(); 5689 /* 5690 * Even if the preceding instruction did not trap, the queue 5691 * is not necessarily empty: this state save might be happening 5692 * because user code tried to store %fsr and took the FPU 5693 * from `exception pending' mode to `exception' mode. 5694 * So we still have to check the blasted QNE bit. 5695 * With any luck it will usually not be set. 5696 */ 5697 ld [%o0 + FS_FSR], %o4 ! if (f->fs_fsr & QNE) 5698 btst %o5, %o4 5699 bnz Lfp_storeq ! goto storeq; 5700 std %f0, [%o0 + FS_REGS + (4*0)] ! f->fs_f0 = etc; 5701Lfp_finish: 5702 st %o3, [%o0 + FS_QSIZE] ! f->fs_qsize = qsize; 5703 std %f2, [%o0 + FS_REGS + (4*2)] 5704 std %f4, [%o0 + FS_REGS + (4*4)] 5705 std %f6, [%o0 + FS_REGS + (4*6)] 5706 std %f8, [%o0 + FS_REGS + (4*8)] 5707 std %f10, [%o0 + FS_REGS + (4*10)] 5708 std %f12, [%o0 + FS_REGS + (4*12)] 5709 std %f14, [%o0 + FS_REGS + (4*14)] 5710 std %f16, [%o0 + FS_REGS + (4*16)] 5711 std %f18, [%o0 + FS_REGS + (4*18)] 5712 std %f20, [%o0 + FS_REGS + (4*20)] 5713 std %f22, [%o0 + FS_REGS + (4*22)] 5714 std %f24, [%o0 + FS_REGS + (4*24)] 5715 std %f26, [%o0 + FS_REGS + (4*26)] 5716 std %f28, [%o0 + FS_REGS + (4*28)] 5717 retl 5718 std %f30, [%o0 + FS_REGS + (4*30)] 5719 5720/* 5721 * Store the (now known nonempty) FP queue. 5722 * We have to reread the fsr each time in order to get the new QNE bit. 5723 */ 5724Lfp_storeq: 5725 add %o0, FS_QUEUE, %o1 ! q = &f->fs_queue[0]; 57261: 5727 std %fq, [%o1 + %o3] ! q[qsize++] = fsr_qfront(); 5728 st %fsr, [%o0 + FS_FSR] ! reread fsr 5729 ld [%o0 + FS_FSR], %o4 ! if fsr & QNE, loop 5730 btst %o5, %o4 5731 bnz 1b 5732 inc 8, %o3 5733 b Lfp_finish ! set qsize and finish storing fregs 5734 srl %o3, 3, %o3 ! (but first fix qsize) 5735 5736/* 5737 * The fsr store trapped. Do it again; this time it will not trap. 5738 * We could just have the trap handler return to the `st %fsr', but 5739 * if for some reason it *does* trap, that would lock us into a tight 5740 * loop. This way we panic instead. Whoopee. 5741 */ 5742savefpcont: 5743 b special_fp_store + 4 ! continue 5744 st %fsr, [%o0 + FS_FSR] ! but first finish the %fsr store 5745 5746/* 5747 * Load FPU state. 5748 */ 5749ENTRY(loadfpstate) 5750 rd %psr, %o1 ! enable FP before we begin 5751 set PSR_EF, %o2 5752 or %o1, %o2, %o1 5753 wr %o1, 0, %psr 5754 nop; nop; nop ! paranoia 5755 ldd [%o0 + FS_REGS + (4*0)], %f0 5756 ldd [%o0 + FS_REGS + (4*2)], %f2 5757 ldd [%o0 + FS_REGS + (4*4)], %f4 5758 ldd [%o0 + FS_REGS + (4*6)], %f6 5759 ldd [%o0 + FS_REGS + (4*8)], %f8 5760 ldd [%o0 + FS_REGS + (4*10)], %f10 5761 ldd [%o0 + FS_REGS + (4*12)], %f12 5762 ldd [%o0 + FS_REGS + (4*14)], %f14 5763 ldd [%o0 + FS_REGS + (4*16)], %f16 5764 ldd [%o0 + FS_REGS + (4*18)], %f18 5765 ldd [%o0 + FS_REGS + (4*20)], %f20 5766 ldd [%o0 + FS_REGS + (4*22)], %f22 5767 ldd [%o0 + FS_REGS + (4*24)], %f24 5768 ldd [%o0 + FS_REGS + (4*26)], %f26 5769 ldd [%o0 + FS_REGS + (4*28)], %f28 5770 ldd [%o0 + FS_REGS + (4*30)], %f30 5771 retl 5772 ld [%o0 + FS_FSR], %fsr ! setfsr(f->fs_fsr); 5773 5774/* 5775 * ienab_bis(bis) int bis; 5776 * ienab_bic(bic) int bic; 5777 * 5778 * Set and clear bits in the interrupt register. 5779 */ 5780 5781#if defined(SUN4M) && (defined(SUN4) || defined(SUN4C)) 5782ENTRY(ienab_bis) 5783NOP_ON_4M_13: 5784 b,a _C_LABEL(ienab_bis_4_4c) 5785 b,a _C_LABEL(ienab_bis_4m) 5786 5787ENTRY(ienab_bic) 5788NOP_ON_4M_14: 5789 b,a _C_LABEL(ienab_bic_4_4c) 5790 b,a _C_LABEL(ienab_bic_4m) 5791#endif 5792 5793#if defined(SUN4) || defined(SUN4C) 5794/* 5795 * Since there are no read-modify-write instructions for this, 5796 * and one of the interrupts is nonmaskable, we must disable traps. 5797 */ 5798#if defined(SUN4M) 5799ENTRY(ienab_bis_4_4c) 5800#else 5801ENTRY(ienab_bis) 5802#endif 5803 ! %o0 = bits to set 5804 rd %psr, %o2 5805 wr %o2, PSR_ET, %psr ! disable traps 5806 nop; nop ! 3-instr delay until ET turns off 5807 sethi %hi(INTRREG_VA), %o3 5808 ldub [%o3 + %lo(INTRREG_VA)], %o4 5809 or %o4, %o0, %o4 ! *INTRREG_VA |= bis; 5810 stb %o4, [%o3 + %lo(INTRREG_VA)] 5811 wr %o2, 0, %psr ! reenable traps 5812 nop 5813 retl 5814 nop 5815 5816#if defined(SUN4M) 5817ENTRY(ienab_bic_4_4c) 5818#else 5819ENTRY(ienab_bic) 5820#endif 5821 ! %o0 = bits to clear 5822 rd %psr, %o2 5823 wr %o2, PSR_ET, %psr ! disable traps 5824 nop; nop 5825 sethi %hi(INTRREG_VA), %o3 5826 ldub [%o3 + %lo(INTRREG_VA)], %o4 5827 andn %o4, %o0, %o4 ! *INTRREG_VA &=~ bic; 5828 stb %o4, [%o3 + %lo(INTRREG_VA)] 5829 wr %o2, 0, %psr ! reenable traps 5830 nop 5831 retl 5832 nop 5833#endif 5834 5835#if defined(SUN4M) 5836/* 5837 * sun4m has separate registers for clearing/setting the interrupt mask. 5838 */ 5839#if defined(SUN4) || defined(SUN4C) 5840ENTRY(ienab_bis_4m) 5841#else 5842ENTRY(ienab_bis) 5843#endif 5844 set ICR_SI_SET, %o1 5845 retl 5846 st %o0, [%o1] 5847 5848#if defined(SUN4) || defined(SUN4C) 5849ENTRY(ienab_bic_4m) 5850#else 5851ENTRY(ienab_bic) 5852#endif 5853 set ICR_SI_CLR, %o1 5854 retl 5855 st %o0, [%o1] 5856 5857/* 5858 * raise(cpu, level) 5859 */ 5860ENTRY(raise) 5861#if !defined(MSIIEP) /* normal suns */ 5862 ! *(ICR_PI_SET + cpu*_MAXNBPG) = PINTR_SINTRLEV(level) 5863 sethi %hi(1 << 16), %o2 5864 sll %o2, %o1, %o2 5865 set ICR_PI_SET, %o1 5866 set _MAXNBPG, %o3 58671: 5868 subcc %o0, 1, %o0 5869 bpos,a 1b 5870 add %o1, %o3, %o1 5871 retl 5872 st %o2, [%o1] 5873#else /* MSIIEP - ignore %o0, only one cpu ever */ 5874 mov 1, %o2 5875 sethi %hi(MSIIEP_PCIC_VA), %o0 5876 sll %o2, %o1, %o2 5877 retl 5878 sth %o2, [%o0 + PCIC_SOFT_INTR_SET_REG] 5879#endif 5880 5881/* 5882 * Read Synchronous Fault Status registers. 5883 * On entry: %l1 == PC, %l3 == fault type, %l4 == storage, %l7 == return address 5884 * Only use %l5 and %l6. 5885 * Note: not C callable. 5886 */ 5887_ENTRY(_C_LABEL(srmmu_get_syncflt)) 5888_ENTRY(_C_LABEL(hypersparc_get_syncflt)) 5889 set SRMMU_SFAR, %l5 5890 lda [%l5] ASI_SRMMU, %l5 ! sync virt addr; must be read first 5891 st %l5, [%l4 + 4] ! => dump.sfva 5892 set SRMMU_SFSR, %l5 5893 lda [%l5] ASI_SRMMU, %l5 ! get sync fault status register 5894 jmp %l7 + 8 ! return to caller 5895 st %l5, [%l4] ! => dump.sfsr 5896 5897_ENTRY(_C_LABEL(viking_get_syncflt)) 5898_ENTRY(_C_LABEL(ms1_get_syncflt)) 5899_ENTRY(_C_LABEL(swift_get_syncflt)) 5900_ENTRY(_C_LABEL(turbosparc_get_syncflt)) 5901_ENTRY(_C_LABEL(cypress_get_syncflt)) 5902 cmp %l3, T_TEXTFAULT 5903 be,a 1f 5904 mov %l1, %l5 ! use PC if type == T_TEXTFAULT 5905 5906 set SRMMU_SFAR, %l5 5907 lda [%l5] ASI_SRMMU, %l5 ! sync virt addr; must be read first 59081: 5909 st %l5, [%l4 + 4] ! => dump.sfva 5910 5911 set SRMMU_SFSR, %l5 5912 lda [%l5] ASI_SRMMU, %l5 ! get sync fault status register 5913 jmp %l7 + 8 ! return to caller 5914 st %l5, [%l4] ! => dump.sfsr 5915 5916#if defined(MULTIPROCESSOR) && 0 /* notyet * 5917/* 5918 * Read Synchronous Fault Status registers. 5919 * On entry: %o0 == &sfsr, %o1 == &sfar 5920 */ 5921_ENTRY(_C_LABEL(smp_get_syncflt)) 5922 save %sp, -CCFSZ, %sp 5923 5924 sethi %hi(CPUINFO_VA), %o4 5925 ld [%l4 + %lo(CPUINFO_VA+CPUINFO_GETSYNCFLT)], %o5 5926 clr %l1 5927 clr %l3 5928 jmpl %o5, %l7 5929 or %o4, %lo(CPUINFO_SYNCFLTDUMP), %l4 5930 5931 ! load values out of the dump 5932 ld [%o4 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP)], %o5 5933 st %o5, [%i0] 5934 ld [%o4 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4)], %o5 5935 st %o5, [%i1] 5936 ret 5937 restore 5938#endif /* MULTIPROCESSOR */ 5939 5940/* 5941 * Read Asynchronous Fault Status registers. 5942 * On entry: %o0 == &afsr, %o1 == &afar 5943 * Return 0 if async register are present. 5944 */ 5945_ENTRY(_C_LABEL(srmmu_get_asyncflt)) 5946 set SRMMU_AFAR, %o4 5947 lda [%o4] ASI_SRMMU, %o4 ! get async fault address 5948 set SRMMU_AFSR, %o3 ! 5949 st %o4, [%o1] 5950 lda [%o3] ASI_SRMMU, %o3 ! get async fault status 5951 st %o3, [%o0] 5952 retl 5953 clr %o0 ! return value 5954 5955_ENTRY(_C_LABEL(cypress_get_asyncflt)) 5956_ENTRY(_C_LABEL(hypersparc_get_asyncflt)) 5957 set SRMMU_AFSR, %o3 ! must read status before fault on HS 5958 lda [%o3] ASI_SRMMU, %o3 ! get async fault status 5959 st %o3, [%o0] 5960 btst AFSR_AFO, %o3 ! and only read fault address 5961 bz 1f ! if valid. 5962 set SRMMU_AFAR, %o4 5963 lda [%o4] ASI_SRMMU, %o4 ! get async fault address 5964 clr %o0 ! return value 5965 retl 5966 st %o4, [%o1] 59671: 5968 retl 5969 clr %o0 ! return value 5970 5971_ENTRY(_C_LABEL(no_asyncflt_regs)) 5972 retl 5973 mov 1, %o0 ! return value 5974 5975_ENTRY(_C_LABEL(hypersparc_pure_vcache_flush)) 5976 /* 5977 * Flush entire on-chip instruction cache, which is 5978 * a pure vitually-indexed/virtually-tagged cache. 5979 */ 5980 retl 5981 sta %g0, [%g0] ASI_HICACHECLR 5982 5983#endif /* SUN4M */ 5984 5985#if !defined(MSIIEP) /* normal suns */ 5986/* 5987 * void lo_microtime(struct timeval *tv) 5988 * 5989 * LBL's sparc bsd 'microtime': We don't need to spl (so this routine 5990 * can be a leaf routine) and we don't keep a 'last' timeval (there 5991 * can't be two calls to this routine in a microsecond). This seems to 5992 * be about 20 times faster than the Sun code on an SS-2. - vj 5993 * 5994 * Read time values from slowest-changing to fastest-changing, 5995 * then re-read out to slowest. If the values read before 5996 * the innermost match those read after, the innermost value 5997 * is consistent with the outer values. If not, it may not 5998 * be and we must retry. Typically this loop runs only once; 5999 * occasionally it runs twice, and only rarely does it run longer. 6000 */ 6001#if defined(SUN4) 6002ENTRY(lo_microtime) 6003#else 6004ENTRY(microtime) 6005#endif 6006 sethi %hi(_C_LABEL(time)), %g2 6007 6008#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4)) 6009 sethi %hi(TIMERREG_VA+4), %g3 6010 or %g3, %lo(TIMERREG_VA+4), %g3 6011#elif (defined(SUN4C) || defined(SUN4)) && !defined(SUN4M) 6012 sethi %hi(TIMERREG_VA), %g3 6013 or %g3, %lo(TIMERREG_VA), %g3 6014#else 6015 sethi %hi(TIMERREG_VA), %g3 6016 or %g3, %lo(TIMERREG_VA), %g3 6017NOP_ON_4_4C_1: 6018 add %g3, 4, %g3 6019#endif 6020 60212: 6022 ldd [%g2+%lo(_C_LABEL(time))], %o2 ! time.tv_sec & time.tv_usec 6023 ld [%g3], %o4 ! usec counter 6024 ldd [%g2+%lo(_C_LABEL(time))], %g4 ! see if time values changed 6025 cmp %g4, %o2 6026 bne 2b ! if time.tv_sec changed 6027 cmp %g5, %o3 6028 bne 2b ! if time.tv_usec changed 6029 tst %o4 6030 6031 bpos 3f ! reached limit? 6032 srl %o4, TMR_SHIFT, %o4 ! convert counter to usec 6033 sethi %hi(_C_LABEL(tick)), %g4 ! bump usec by 1 tick 6034 ld [%g4+%lo(_C_LABEL(tick))], %o1 6035 set TMR_MASK, %g5 6036 add %o1, %o3, %o3 6037 and %o4, %g5, %o4 60383: 6039 add %o4, %o3, %o3 6040 set 1000000, %g5 ! normalize usec value 6041 cmp %o3, %g5 6042 bl,a 4f 6043 st %o2, [%o0] ! (should be able to std here) 6044 add %o2, 1, %o2 ! overflow 6045 sub %o3, %g5, %o3 6046 st %o2, [%o0] ! (should be able to std here) 60474: 6048 retl 6049 st %o3, [%o0+4] 6050 6051#else /* MSIIEP */ 6052/* XXX: uwe: can be merged with 4c/4m version above */ 6053/* 6054 * ms-IIep version of 6055 * void microtime(struct timeval *tv) 6056 * 6057 * This is similar to 4c/4m microtime. The difference is that 6058 * counter uses 31 bits and ticks every 4 CPU cycles (cpu is @100MHz) 6059 * the magic to divide by 25 is stolen from gcc 6060 */ 6061ENTRY(microtime) 6062 sethi %hi(_C_LABEL(time)), %g2 6063 6064 sethi %hi(MSIIEP_PCIC_VA), %g3 6065 or %g3, PCIC_SCCR_REG, %g3 6066 60672: 6068 ldd [%g2+%lo(_C_LABEL(time))], %o2 ! time.tv_sec & time.tv_usec 6069 ld [%g3], %o4 ! system (timer) counter 6070 ldd [%g2+%lo(_C_LABEL(time))], %g4 ! see if time values changed 6071 cmp %g4, %o2 6072 bne 2b ! if time.tv_sec changed 6073 cmp %g5, %o3 6074 bne 2b ! if time.tv_usec changed 6075 tst %o4 6076 !! %o2 - time.tv_sec; %o3 - time.tv_usec; %o4 - timer counter 6077 6078!!! BEGIN ms-IIep specific code 6079 bpos 3f ! if limit not reached yet 6080 clr %g4 ! then use timer as is 6081 6082 sethi %hi(0x80000000), %g5 6083 sethi %hi(_C_LABEL(tick)), %g4 6084 andn %o4, %g5, %o4 ! cleat limit reached flag 6085 ld [%g4+%lo(_C_LABEL(tick))], %g4 6086 6087 !! %g4 - either 0 or tick (if timer has hit the limit) 60883: 6089 inc -1, %o4 ! timer is 1-based, adjust 6090 !! divide by 25 magic stollen from a gcc output 6091 sethi %hi(1374389535), %g5 6092 or %g5, %lo(1374389535), %g5 6093 umul %o4, %g5, %g0 6094 rd %y, %o4 6095 srl %o4, 3, %o4 6096 add %o4, %g4, %o4 ! may be bump usec by tick 6097!!! END ms-IIep specific code 6098 6099 add %o3, %o4, %o3 ! add timer to time.tv_usec 6100 set 1000000, %g5 ! normalize usec value 6101 cmp %o3, %g5 6102 bl 4f 6103 nop 6104 inc %o2 ! overflow into tv_sec 6105 sub %o3, %g5, %o3 61064: 6107 retl 6108 std %o2, [%o0] 6109#endif /* MSIIEP */ 6110 6111/* 6112 * delay function 6113 * 6114 * void delay(N) -- delay N microseconds 6115 * 6116 * Register usage: %o0 = "N" number of usecs to go (counts down to zero) 6117 * %o1 = "timerblurb" (stays constant) 6118 * %o2 = counter for 1 usec (counts down from %o1 to zero) 6119 * 6120 */ 6121 6122ENTRY(delay) ! %o0 = n 6123 subcc %o0, %g0, %g0 6124 be 2f 6125 6126 sethi %hi(_C_LABEL(timerblurb)), %o1 6127 ld [%o1 + %lo(_C_LABEL(timerblurb))], %o1 ! %o1 = timerblurb 6128 6129 addcc %o1, %g0, %o2 ! %o2 = cntr (start @ %o1), clear CCs 6130 ! first time through only 6131 6132 ! delay 1 usec 61331: bne 1b ! come back here if not done 6134 subcc %o2, 1, %o2 ! %o2 = %o2 - 1 [delay slot] 6135 6136 subcc %o0, 1, %o0 ! %o0 = %o0 - 1 6137 bne 1b ! done yet? 6138 addcc %o1, %g0, %o2 ! reinit %o2 and CCs [delay slot] 6139 ! harmless if not branching 61402: 6141 retl ! return 6142 nop ! [delay slot] 6143 6144#if defined(KGDB) || defined(DDB) || defined(DIAGNOSTIC) 6145/* 6146 * Write all windows (user or otherwise), except the current one. 6147 * 6148 * THIS COULD BE DONE IN USER CODE 6149 */ 6150ENTRY(write_all_windows) 6151 /* 6152 * g2 = g1 = nwindows - 1; 6153 * while (--g1 > 0) save(); 6154 * while (--g2 > 0) restore(); 6155 */ 6156 sethi %hi(_C_LABEL(nwindows)), %g1 6157 ld [%g1 + %lo(_C_LABEL(nwindows))], %g1 6158 dec %g1 6159 mov %g1, %g2 6160 61611: deccc %g1 6162 bg,a 1b 6163 save %sp, -64, %sp 6164 61652: deccc %g2 6166 bg,a 2b 6167 restore 6168 6169 retl 6170 nop 6171#endif /* KGDB */ 6172 6173ENTRY(setjmp) 6174 std %sp, [%o0+0] ! stack pointer & return pc 6175 st %fp, [%o0+8] ! frame pointer 6176 retl 6177 clr %o0 6178 6179Lpanic_ljmp: 6180 .asciz "longjmp botch" 6181 _ALIGN 6182 6183ENTRY(longjmp) 6184 addcc %o1, %g0, %g6 ! compute v ? v : 1 in a global register 6185 be,a 0f 6186 mov 1, %g6 61870: 6188 mov %o0, %g1 ! save a in another global register 6189 ld [%g1+8], %g7 /* get caller's frame */ 61901: 6191 cmp %fp, %g7 ! compare against desired frame 6192 bl,a 1b ! if below, 6193 restore ! pop frame and loop 6194 be,a 2f ! if there, 6195 ldd [%g1+0], %o2 ! fetch return %sp and pc, and get out 6196 6197Llongjmpbotch: 6198 ! otherwise, went too far; bomb out 6199 save %sp, -CCFSZ, %sp /* preserve current window */ 6200 sethi %hi(Lpanic_ljmp), %o0 6201 call _C_LABEL(panic) 6202 or %o0, %lo(Lpanic_ljmp), %o0; 6203 unimp 0 6204 62052: 6206 cmp %o2, %sp ! %sp must not decrease 6207 bge,a 3f 6208 mov %o2, %sp ! it is OK, put it in place 6209 b,a Llongjmpbotch 62103: 6211 jmp %o3 + 8 ! success, return %g6 6212 mov %g6, %o0 6213 6214 .data 6215 .globl _C_LABEL(kernel_top) 6216_C_LABEL(kernel_top): 6217 .word 0 6218 .globl _C_LABEL(bootinfo) 6219_C_LABEL(bootinfo): 6220 .word 0 6221 6222 .globl _C_LABEL(proc0paddr) 6223_C_LABEL(proc0paddr): 6224 .word _C_LABEL(u0) ! KVA of proc0 uarea 6225 6226/* interrupt counters XXX THESE BELONG ELSEWHERE (if anywhere) */ 6227 .globl _C_LABEL(intrcnt), _C_LABEL(eintrcnt) 6228 .globl _C_LABEL(intrnames), _C_LABEL(eintrnames) 6229_C_LABEL(intrnames): 6230 .asciz "spur" 6231 .asciz "lev1" 6232 .asciz "lev2" 6233 .asciz "lev3" 6234 .asciz "lev4" 6235 .asciz "lev5" 6236 .asciz "lev6" 6237 .asciz "lev7" 6238 .asciz "lev8" 6239 .asciz "lev9" 6240 .asciz "clock" 6241 .asciz "lev11" 6242 .asciz "lev12" 6243 .asciz "lev13" 6244 .asciz "prof" 6245_C_LABEL(eintrnames): 6246 _ALIGN 6247_C_LABEL(intrcnt): 6248 .skip 4*15 6249_C_LABEL(eintrcnt): 6250 6251 .comm _C_LABEL(nwindows), 4 6252 .comm _C_LABEL(romp), 4 6253