1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/asm_linkage.h> 27 #include <sys/intreg.h> 28 #include <sys/ivintr.h> 29 #include <sys/mmu.h> 30 #include <sys/machpcb.h> 31 #include <sys/machtrap.h> 32 #include <sys/machlock.h> 33 #include <sys/fdreg.h> 34 #include <sys/vis.h> 35 #include <sys/traptrace.h> 36 #include <sys/panic.h> 37 #include <sys/machasi.h> 38 #include <sys/clock.h> 39 #include <vm/hat_sfmmu.h> 40 41 #include "assym.h" 42 43 44 ! 45 ! REGOFF must add up to allow double word access to r_tstate. 46 ! PCB_WBUF must also be aligned. 47 ! 48 #if (REGOFF & 7) != 0 49 #error "struct regs not aligned" 50 #endif 51 52 /* 53 * Absolute external symbols. 54 * On the sun4u we put the panic buffer in the third and fourth pages. 55 * We set things up so that the first 2 pages of KERNELBASE is illegal 56 * to act as a redzone during copyin/copyout type operations. One of 57 * the reasons the panic buffer is allocated in low memory to 58 * prevent being overwritten during booting operations (besides 59 * the fact that it is small enough to share pages with others). 60 */ 61 62 .seg ".data" 63 .global panicbuf 64 65 PROM = 0xFFE00000 ! address of prom virtual area 66 panicbuf = SYSBASE32 + PAGESIZE ! address of panic buffer 67 68 .type panicbuf, #object 69 .size panicbuf, PANICBUFSIZE 70 71 /* 72 * Absolute external symbol - intr_vec_table. 73 * 74 * With new bus structures supporting a larger number of interrupt 75 * numbers, the interrupt vector table, intr_vec_table[] has been 76 * moved out of kernel nucleus and allocated after panicbuf. 77 */ 78 .global intr_vec_table 79 80 intr_vec_table = SYSBASE32 + PAGESIZE + PANICBUFSIZE ! address of interrupt table 81 82 .type intr_vec_table, #object 83 .size intr_vec_table, MAXIVNUM * CPTRSIZE + MAX_RSVD_IV * IV_SIZE + MAX_RSVD_IVX * (IV_SIZE + CPTRSIZE * (NCPU - 1)) 84 85 /* 86 * The thread 0 stack. This must be the first thing in the data 87 * segment (other than an sccs string) so that we don't stomp 88 * on anything important if the stack overflows. We get a 89 * red zone below this stack for free when the kernel text is 90 * write protected. 91 */ 92 93 .global t0stack 94 .align 16 95 .type t0stack, #object 96 t0stack: 97 .skip T0STKSZ ! thread 0 stack 98 t0stacktop: 99 .size t0stack, T0STKSZ 100 101 /* 102 * cpu0 and its ptl1_panic stack. The cpu structure must be allocated 103 * on a single page for ptl1_panic's physical address accesses. 104 */ 105 .global cpu0 106 .align MMU_PAGESIZE 107 cpu0: 108 .type cpu0, #object 109 .skip CPU_ALLOC_SIZE 110 .size cpu0, CPU_ALLOC_SIZE 111 112 .global t0 113 .align PTR24_ALIGN ! alignment for mutex. 114 .type t0, #object 115 t0: 116 .skip THREAD_SIZE ! thread 0 117 .size t0, THREAD_SIZE 118 119 #ifdef TRAPTRACE 120 .global trap_trace_ctl 121 .global trap_tr0 122 .global trap_trace_bufsize 123 .global trap_freeze 124 .global trap_freeze_pc 125 126 .align 4 127 trap_trace_bufsize: 128 .word TRAP_TSIZE ! default trap buffer size 129 trap_freeze: 130 .word 0 131 132 .align 64 133 trap_trace_ctl: 134 .skip NCPU * TRAPTR_SIZE ! NCPU control headers 135 136 .align 16 137 trap_tr0: 138 .skip TRAP_TSIZE ! one buffer for the boot cpu 139 140 /* 141 * When an assertion in TRACE_PTR was failed, %pc is saved in trap_freeze_pc to 142 * show in which TRACE_PTR the assertion failure happened. 143 */ 144 .align 8 145 trap_freeze_pc: 146 .nword 0 147 #endif /* TRAPTRACE */ 148 149 .align 4 150 .seg ".text" 151 152 #ifdef NOPROM 153 .global availmem 154 availmem: 155 .word 0 156 #endif /* NOPROM */ 157 158 .align 8 159 _local_p1275cis: 160 .nword 0 161 162 .seg ".data" 163 164 .global nwindows, nwin_minus_one, winmask 165 nwindows: 166 .word 8 167 nwin_minus_one: 168 .word 7 169 winmask: 170 .word 8 171 172 .global afsrbuf 173 afsrbuf: 174 .word 0,0,0,0 175 176 /* 177 * System initialization 178 * 179 * Our contract with the boot prom specifies that the MMU is on and the 180 * first 16 meg of memory is mapped with a level-1 pte. We are called 181 * with p1275cis ptr in %o0 and kdi_dvec in %o1; we start execution 182 * directly from physical memory, so we need to get up into our proper 183 * addresses quickly: all code before we do this must be position 184 * independent. 185 * 186 * NB: Above is not true for boot/stick kernel, the only thing mapped is 187 * the text+data+bss. The kernel is loaded directly into KERNELBASE. 188 * 189 * entry, the romvec pointer (romp) is the first argument; 190 * i.e., %o0. 191 * the bootops vector is in the third argument (%o1) 192 * 193 * Our tasks are: 194 * save parameters 195 * construct mappings for KERNELBASE (not needed for boot/stick kernel) 196 * hop up into high memory (not needed for boot/stick kernel) 197 * initialize stack pointer 198 * initialize trap base register 199 * initialize window invalid mask 200 * initialize psr (with traps enabled) 201 * figure out all the module type stuff 202 * tear down the 1-1 mappings 203 * dive into main() 204 */ 205 ENTRY_NP(_start) 206 ! 207 ! Stash away our arguments in memory. 208 ! 209 sethi %hi(_local_p1275cis), %g1 210 stn %o4, [%g1 + %lo(_local_p1275cis)] 211 212 ! 213 ! Initialize CPU state registers 214 ! 215 wrpr %g0, PSTATE_KERN, %pstate 216 wr %g0, %g0, %fprs 217 218 ! 219 ! call krtld to link the world together 220 ! 221 call kobj_start 222 mov %o4, %o0 223 224 CLEARTICKNPT ! allow user rdtick 225 ! 226 ! Get maxwin from %ver 227 ! 228 rdpr %ver, %g1 229 and %g1, VER_MAXWIN, %g1 230 231 ! 232 ! Stuff some memory cells related to numbers of windows. 233 ! 234 sethi %hi(nwin_minus_one), %g2 235 st %g1, [%g2 + %lo(nwin_minus_one)] 236 inc %g1 237 sethi %hi(nwindows), %g2 238 st %g1, [%g2 + %lo(nwindows)] 239 dec %g1 240 mov -2, %g2 241 sll %g2, %g1, %g2 242 sethi %hi(winmask), %g4 243 st %g2, [%g4 + %lo(winmask)] 244 245 ! 246 ! save a pointer to obp's tba for later use by kmdb 247 ! 248 rdpr %tba, %g1 249 set boot_tba, %g2 250 stx %g1, [%g2] 251 252 ! 253 ! copy obp's breakpoint trap entry to obp_bpt 254 ! 255 rdpr %tba, %g1 256 set T_SOFTWARE_TRAP | ST_MON_BREAKPOINT, %g2 257 sll %g2, 5, %g2 258 or %g1, %g2, %g1 259 set obp_bpt, %g2 260 ldx [%g1], %g3 261 stx %g3, [%g2] 262 flush %g2 263 ldx [%g1 + 8], %g3 264 stx %g3, [%g2 + 8] 265 flush %g2 + 8 266 ldx [%g1 + 16], %g3 267 stx %g3, [%g2 + 16] 268 flush %g2 + 16 269 ldx [%g1 + 24], %g3 270 stx %g3, [%g2 + 24] 271 flush %g2 + 24 272 273 ! 274 ! Initialize thread 0's stack. 275 ! 276 set t0stacktop, %g1 ! setup kernel stack pointer 277 sub %g1, SA(KFPUSIZE+GSR_SIZE), %g2 278 and %g2, 0x3f, %g3 279 sub %g2, %g3, %o1 280 sub %o1, SA(MPCBSIZE) + STACK_BIAS, %sp 281 282 ! 283 ! Initialize global thread register. 284 ! 285 set t0, THREAD_REG 286 287 ! 288 ! Fill in enough of the cpu structure so that 289 ! the wbuf management code works. Make sure the 290 ! boot cpu is inserted in cpu[] based on cpuid. 291 ! 292 CPU_INDEX(%g2, %g1) 293 sll %g2, CPTRSHIFT, %g2 ! convert cpuid to cpu[] offset 294 set cpu0, %o0 ! &cpu0 295 set cpu, %g1 ! &cpu[] 296 stn %o0, [%g1 + %g2] ! cpu[cpuid] = &cpu0 297 298 stn %o0, [THREAD_REG + T_CPU] ! threadp()->t_cpu = cpu[cpuid] 299 stn THREAD_REG, [%o0 + CPU_THREAD] ! cpu[cpuid]->cpu_thread = threadp() 300 301 302 ! We do NOT need to bzero our BSS...boot has already done it for us. 303 ! Just need to reference edata so that we don't break /dev/ksyms 304 set edata, %g0 305 306 ! 307 ! Call mlsetup with address of prototype user registers. 308 ! 309 call mlsetup 310 add %sp, REGOFF + STACK_BIAS, %o0 311 312 #if (REGOFF != MPCB_REGS) 313 #error "hole in struct machpcb between frame and regs?" 314 #endif 315 316 ! 317 ! Now call main. We will return as process 1 (init). 318 ! 319 call main 320 nop 321 322 ! 323 ! Main should never return. 324 ! 325 set .mainretmsg, %o0 326 call panic 327 nop 328 SET_SIZE(_start) 329 330 .mainretmsg: 331 .asciz "main returned" 332 .align 4 333 334 335 /* 336 * Generic system trap handler. 337 * 338 * Some kernel trap handlers save themselves from buying a window by 339 * borrowing some of sys_trap's unused locals. %l0 thru %l3 may be used 340 * for this purpose, as user_rtt and priv_rtt do not depend on them. 341 * %l4 thru %l7 should NOT be used this way. 342 * 343 * Entry Conditions: 344 * %pstate am:0 priv:1 ie:0 345 * globals are either ag or ig (not mg!) 346 * 347 * Register Inputs: 348 * %g1 pc of trap handler 349 * %g2, %g3 args for handler 350 * %g4 desired %pil (-1 means current %pil) 351 * %g5, %g6 destroyed 352 * %g7 saved 353 * 354 * Register Usage: 355 * %l0, %l1 temps 356 * %l3 saved %g1 357 * %l6 curthread for user traps, %pil for priv traps 358 * %l7 regs 359 * 360 * Called function prototype variants: 361 * 362 * func(struct regs *rp); 363 * func(struct regs *rp, uintptr_t arg1 [%g2], uintptr_t arg2 [%g3]) 364 * func(struct regs *rp, uintptr_t arg1 [%g2], 365 * uint32_t arg2 [%g3.l], uint32_t arg3 [%g3.h]) 366 * func(struct regs *rp, uint32_t arg1 [%g2.l], 367 * uint32_t arg2 [%g3.l], uint32_t arg3 [%g3.h], uint32_t [%g2.h]) 368 */ 369 370 ENTRY_NP(sys_trap) 371 ! 372 ! force tl=1, update %cwp, branch to correct handler 373 ! 374 wrpr %g0, 1, %tl 375 rdpr %tstate, %g5 376 btst TSTATE_PRIV, %g5 377 and %g5, TSTATE_CWP, %g6 378 bnz,pn %xcc, priv_trap 379 wrpr %g0, %g6, %cwp 380 381 ALTENTRY(user_trap) 382 ! 383 ! user trap 384 ! 385 ! make all windows clean for kernel 386 ! buy a window using the current thread's stack 387 ! 388 sethi %hi(nwin_minus_one), %g5 389 ld [%g5 + %lo(nwin_minus_one)], %g5 390 wrpr %g0, %g5, %cleanwin 391 CPU_ADDR(%g5, %g6) 392 ldn [%g5 + CPU_THREAD], %g5 393 ldn [%g5 + T_STACK], %g6 394 sub %g6, STACK_BIAS, %g6 395 save %g6, 0, %sp 396 ! 397 ! set window registers so that current windows are "other" windows 398 ! 399 rdpr %canrestore, %l0 400 rdpr %wstate, %l1 401 wrpr %g0, 0, %canrestore 402 sllx %l1, WSTATE_SHIFT, %l1 403 wrpr %l1, WSTATE_K64, %wstate 404 wrpr %g0, %l0, %otherwin 405 ! 406 ! set pcontext to run kernel 407 ! 408 sethi %hi(kcontextreg), %l0 409 ldx [%l0 + %lo(kcontextreg)], %l0 410 mov MMU_PCONTEXT, %l1 ! if kcontextreg==PCONTEXT, do nothing 411 ldxa [%l1]ASI_MMU_CTX, %l2 412 xor %l0, %l2, %l2 413 srlx %l2, CTXREG_NEXT_SHIFT, %l2 414 brz %l2, 2f ! if N_pgsz0/1 changed, need demap 415 sethi %hi(FLUSH_ADDR), %l3 416 mov DEMAP_ALL_TYPE, %l2 417 stxa %g0, [%l2]ASI_DTLB_DEMAP 418 stxa %g0, [%l2]ASI_ITLB_DEMAP 419 2: 420 stxa %l0, [%l1]ASI_MMU_CTX 421 flush %l3 ! flush required by immu 422 1: 423 424 set utl0, %g6 ! bounce to utl0 425 have_win: 426 SYSTRAP_TRACE(%o1, %o2, %o3) 427 428 429 ! 430 ! at this point we have a new window we can play in, 431 ! and %g6 is the label we want done to bounce to 432 ! 433 ! save needed current globals 434 ! 435 mov %g1, %l3 ! pc 436 mov %g2, %o1 ! arg #1 437 mov %g3, %o2 ! arg #2 438 srlx %g3, 32, %o3 ! pseudo arg #3 439 srlx %g2, 32, %o4 ! pseudo arg #4 440 mov %g5, %l6 ! curthread if user trap, %pil if priv trap 441 ! 442 ! save trap state on stack 443 ! 444 add %sp, REGOFF + STACK_BIAS, %l7 445 rdpr %tpc, %l0 446 rdpr %tnpc, %l1 447 rdpr %tstate, %l2 448 stn %l0, [%l7 + PC_OFF] 449 stn %l1, [%l7 + nPC_OFF] 450 stx %l2, [%l7 + TSTATE_OFF] 451 ! 452 ! setup pil 453 ! 454 brlz,pt %g4, 1f 455 nop 456 #ifdef DEBUG 457 ! 458 ! ASSERT(%g4 >= %pil). 459 ! 460 rdpr %pil, %l0 461 cmp %g4, %l0 462 bge,pt %xcc, 0f 463 nop ! yes, nop; to avoid anull 464 set bad_g4_called, %l3 465 mov 1, %o1 466 st %o1, [%l3] 467 set bad_g4, %l3 ! pc 468 set sys_trap_wrong_pil, %o1 ! arg #1 469 mov %g4, %o2 ! arg #2 470 ba 1f ! stay at the current %pil 471 mov %l0, %o3 ! arg #3 472 0: 473 #endif /* DEBUG */ 474 wrpr %g0, %g4, %pil 475 1: 476 ! 477 ! set trap regs to execute in kernel at %g6 478 ! done resumes execution there 479 ! 480 wrpr %g0, %g6, %tnpc 481 rdpr %cwp, %l0 482 set TSTATE_KERN, %l1 483 wrpr %l1, %l0, %tstate 484 done 485 /* NOTREACHED */ 486 SET_SIZE(user_trap) 487 SET_SIZE(sys_trap) 488 489 490 ENTRY_NP(prom_trap) 491 ! 492 ! prom trap switches the stack to 32-bit 493 ! if we took a trap from a 64-bit window 494 ! Then buys a window on the current stack. 495 ! 496 save %sp, -SA64(REGOFF + REGSIZE), %sp 497 /* 32 bit frame, 64 bit sized */ 498 set ptl0, %g6 499 ba,a,pt %xcc, have_win 500 SET_SIZE(prom_trap) 501 502 ENTRY_NP(priv_trap) 503 ! 504 ! kernel trap 505 ! buy a window on the current stack 506 ! 507 ! is the trap PC in the range allocated to Open Firmware? 508 rdpr %tpc, %g5 509 set OFW_END_ADDR, %g6 510 cmp %g5, %g6 511 bgu,a,pn %xcc, 1f 512 rdpr %pil, %g5 513 set OFW_START_ADDR, %g6 514 cmp %g5, %g6 515 bgeu,pn %xcc, prom_trap 516 rdpr %pil, %g5 517 1: 518 ! 519 ! check if the primary context is of kernel. 520 ! 521 mov MMU_PCONTEXT, %g6 522 ldxa [%g6]ASI_MMU_CTX, %g5 523 sllx %g5, CTXREG_CTX_SHIFT, %g5 ! keep just the ctx bits 524 brnz,pn %g5, 2f ! assumes KCONTEXT == 0 525 rdpr %pil, %g5 526 ! 527 ! primary context is of kernel. 528 ! 529 set ktl0, %g6 530 save %sp, -SA(REGOFF + REGSIZE), %sp 531 ba,a,pt %xcc, have_win 532 2: 533 ! 534 ! primary context is of user. caller of sys_trap() 535 ! or priv_trap() did not set kernel context. raise 536 ! trap level to MAXTL-1 so that ptl1_panic() prints 537 ! out all levels of trap data. 538 ! 539 rdpr %ver, %g5 540 srlx %g5, VER_MAXTL_SHIFT, %g5 541 and %g5, VER_MAXTL_MASK, %g5 ! %g5 = MAXTL 542 sub %g5, 1, %g5 543 wrpr %g0, %g5, %tl 544 mov PTL1_BAD_CTX, %g1 545 ba,a,pt %xcc, ptl1_panic 546 SET_SIZE(priv_trap) 547 548 ENTRY_NP(utl0) 549 SAVE_GLOBALS(%l7) 550 SAVE_OUTS(%l7) 551 mov %l6, THREAD_REG 552 wrpr %g0, PSTATE_KERN, %pstate ! enable ints 553 jmpl %l3, %o7 ! call trap handler 554 mov %l7, %o0 555 ! 556 ALTENTRY(user_rtt) 557 ! 558 ! Register inputs 559 ! %l7 - regs 560 ! 561 ! disable interrupts and check for ASTs and wbuf restores 562 ! keep cpu_base_spl in %l4 and THREAD_REG in %l6 (needed 563 ! in wbuf.s when globals have already been restored). 564 ! 565 wrpr %g0, PIL_MAX, %pil 566 ldn [THREAD_REG + T_CPU], %l0 567 ld [%l0 + CPU_BASE_SPL], %l4 568 569 ldub [THREAD_REG + T_ASTFLAG], %l2 570 brz,pt %l2, 1f 571 ld [%sp + STACK_BIAS + MPCB_WBCNT], %l3 572 ! 573 ! call trap to do ast processing 574 ! 575 wrpr %g0, %l4, %pil ! pil = cpu_base_spl 576 mov %l7, %o0 577 call trap 578 mov T_AST, %o2 579 ba,a,pt %xcc, user_rtt 580 1: 581 brz,pt %l3, 2f 582 mov THREAD_REG, %l6 583 ! 584 ! call restore_wbuf to push wbuf windows to stack 585 ! 586 wrpr %g0, %l4, %pil ! pil = cpu_base_spl 587 mov %l7, %o0 588 call trap 589 mov T_FLUSH_PCB, %o2 590 ba,a,pt %xcc, user_rtt 591 2: 592 #ifdef TRAPTRACE 593 TRACE_RTT(TT_SYS_RTT_USER, %l0, %l1, %l2, %l3) 594 #endif /* TRAPTRACE */ 595 ld [%sp + STACK_BIAS + MPCB_WSTATE], %l3 ! get wstate 596 597 ! 598 ! restore user globals and outs 599 ! 600 rdpr %pstate, %l1 601 wrpr %l1, PSTATE_IE, %pstate 602 RESTORE_GLOBALS(%l7) 603 ! switch to alternate globals, saving THREAD_REG in %l6 604 wrpr %l1, PSTATE_IE | PSTATE_AG, %pstate 605 mov %sp, %g6 ! remember the mpcb pointer in %g6 606 RESTORE_OUTS(%l7) 607 ! 608 ! set %pil from cpu_base_spl 609 ! 610 wrpr %g0, %l4, %pil 611 ! 612 ! raise tl (now using nucleus context) 613 ! 614 wrpr %g0, 1, %tl 615 616 ! switch "other" windows back to "normal" windows. 617 rdpr %otherwin, %g1 618 wrpr %g0, 0, %otherwin 619 add %l3, WSTATE_CLEAN_OFFSET, %l3 ! convert to "clean" wstate 620 wrpr %g0, %l3, %wstate 621 wrpr %g0, %g1, %canrestore 622 623 ! set pcontext to scontext for user execution 624 mov MMU_SCONTEXT, %g3 625 ldxa [%g3]ASI_MMU_CTX, %g2 626 627 mov MMU_PCONTEXT, %g3 628 ldxa [%g3]ASI_MMU_CTX, %g4 ! need N_pgsz0/1 bits 629 srlx %g4, CTXREG_NEXT_SHIFT, %g4 630 sllx %g4, CTXREG_NEXT_SHIFT, %g4 631 or %g4, %g2, %g2 ! Or in Nuc pgsz bits 632 633 sethi %hi(FLUSH_ADDR), %g4 634 stxa %g2, [%g3]ASI_MMU_CTX 635 flush %g4 ! flush required by immu 636 ! 637 ! Within the code segment [rtt_ctx_start - rtt_ctx_end], 638 ! PCONTEXT is set to run user code. If a trap happens in this 639 ! window, and the trap needs to be handled at TL=0, the handler 640 ! must make sure to set PCONTEXT to run kernel. A convenience 641 ! macro, RESET_USER_RTT_REGS(scr1, scr2, label) is available to 642 ! TL>1 handlers for this purpose. 643 ! 644 ! %g1 = %canrestore 645 ! %l7 = regs 646 ! %g6 = mpcb 647 ! 648 .global rtt_ctx_start 649 rtt_ctx_start: 650 ! 651 ! setup trap regs 652 ! 653 ldn [%l7 + PC_OFF], %g3 654 ldn [%l7 + nPC_OFF], %g2 655 ldx [%l7 + TSTATE_OFF], %l0 656 andn %l0, TSTATE_CWP, %g7 657 wrpr %g3, %tpc 658 wrpr %g2, %tnpc 659 660 ! 661 ! Restore to window we originally trapped in. 662 ! First attempt to restore from the watchpoint saved register window 663 ! 664 tst %g1 665 bne,a 1f 666 clrn [%g6 + STACK_BIAS + MPCB_RSP0] 667 tst %fp 668 be,a 1f 669 clrn [%g6 + STACK_BIAS + MPCB_RSP0] 670 ! test for user return window in pcb 671 ldn [%g6 + STACK_BIAS + MPCB_RSP0], %g1 672 cmp %fp, %g1 673 bne 1f 674 clrn [%g6 + STACK_BIAS + MPCB_RSP0] 675 restored 676 restore 677 ! restore from user return window 678 RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN0) 679 ! 680 ! Attempt to restore from the scond watchpoint saved register window 681 tst %fp 682 be,a 2f 683 clrn [%g6 + STACK_BIAS + MPCB_RSP1] 684 ldn [%g6 + STACK_BIAS + MPCB_RSP1], %g1 685 cmp %fp, %g1 686 bne 2f 687 clrn [%g6 + STACK_BIAS + MPCB_RSP1] 688 restored 689 restore 690 RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN1) 691 save 692 b,a 2f 693 1: 694 restore ! should not trap 695 2: 696 ! 697 ! set %cleanwin to %canrestore 698 ! set %tstate to the correct %cwp 699 ! retry resumes user execution 700 ! 701 rdpr %canrestore, %g1 702 wrpr %g0, %g1, %cleanwin 703 rdpr %cwp, %g1 704 wrpr %g1, %g7, %tstate 705 retry 706 .global rtt_ctx_end 707 rtt_ctx_end: 708 /* NOTREACHED */ 709 SET_SIZE(user_rtt) 710 SET_SIZE(utl0) 711 712 ENTRY_NP(ptl0) 713 SAVE_GLOBALS(%l7) 714 SAVE_OUTS(%l7) 715 CPU_ADDR(%g5, %g6) 716 ldn [%g5 + CPU_THREAD], THREAD_REG 717 wrpr %g0, PSTATE_KERN, %pstate ! enable ints 718 jmpl %l3, %o7 ! call trap handler 719 mov %l7, %o0 720 ! 721 ALTENTRY(prom_rtt) 722 #ifdef TRAPTRACE 723 TRACE_RTT(TT_SYS_RTT_PROM, %l0, %l1, %l2, %l3) 724 #endif /* TRAPTRACE */ 725 ba,pt %xcc, common_rtt 726 mov THREAD_REG, %l0 727 SET_SIZE(prom_rtt) 728 SET_SIZE(ptl0) 729 730 ENTRY_NP(ktl0) 731 SAVE_GLOBALS(%l7) 732 SAVE_OUTS(%l7) ! for the call bug workaround 733 wrpr %g0, PSTATE_KERN, %pstate ! enable ints 734 jmpl %l3, %o7 ! call trap handler 735 mov %l7, %o0 736 ! 737 ALTENTRY(priv_rtt) 738 #ifdef TRAPTRACE 739 TRACE_RTT(TT_SYS_RTT_PRIV, %l0, %l1, %l2, %l3) 740 #endif /* TRAPTRACE */ 741 ! 742 ! Register inputs 743 ! %l7 - regs 744 ! %l6 - trap %pil 745 ! 746 ! Check for a kernel preemption request 747 ! 748 ldn [THREAD_REG + T_CPU], %l0 749 ldub [%l0 + CPU_KPRUNRUN], %l0 750 brz,pt %l0, 1f 751 nop 752 753 ! 754 ! Attempt to preempt 755 ! 756 ldstub [THREAD_REG + T_PREEMPT_LK], %l0 ! load preempt lock 757 brnz,pn %l0, 1f ! can't call kpreempt if this thread is 758 nop ! already in it... 759 760 call kpreempt 761 mov %l6, %o0 ! pass original interrupt level 762 763 stub %g0, [THREAD_REG + T_PREEMPT_LK] ! nuke the lock 764 765 rdpr %pil, %o0 ! compare old pil level 766 cmp %l6, %o0 ! with current pil level 767 movg %xcc, %o0, %l6 ! if current is lower, drop old pil 768 1: 769 ! 770 ! If we interrupted the mutex_owner_running() critical region we 771 ! must reset the PC and nPC back to the beginning to prevent missed 772 ! wakeups. See the comments in mutex_owner_running() for details. 773 ! 774 ldn [%l7 + PC_OFF], %l0 775 set mutex_owner_running_critical_start, %l1 776 sub %l0, %l1, %l0 777 cmp %l0, mutex_owner_running_critical_size 778 bgeu,pt %xcc, 2f 779 mov THREAD_REG, %l0 780 stn %l1, [%l7 + PC_OFF] ! restart mutex_owner_running() 781 add %l1, 4, %l1 782 ba,pt %xcc, common_rtt 783 stn %l1, [%l7 + nPC_OFF] 784 785 2: 786 ! 787 ! If we interrupted the mutex_exit() critical region we must reset 788 ! the PC and nPC back to the beginning to prevent missed wakeups. 789 ! See the comments in mutex_exit() for details. 790 ! 791 ldn [%l7 + PC_OFF], %l0 792 set mutex_exit_critical_start, %l1 793 sub %l0, %l1, %l0 794 cmp %l0, mutex_exit_critical_size 795 bgeu,pt %xcc, common_rtt 796 mov THREAD_REG, %l0 797 stn %l1, [%l7 + PC_OFF] ! restart mutex_exit() 798 add %l1, 4, %l1 799 stn %l1, [%l7 + nPC_OFF] 800 801 common_rtt: 802 ! 803 ! restore globals and outs 804 ! 805 rdpr %pstate, %l1 806 wrpr %l1, PSTATE_IE, %pstate 807 RESTORE_GLOBALS(%l7) 808 ! switch to alternate globals 809 wrpr %l1, PSTATE_IE | PSTATE_AG, %pstate 810 RESTORE_OUTS(%l7) 811 ! 812 ! set %pil from max(old pil, cpu_base_spl) 813 ! 814 ldn [%l0 + T_CPU], %l0 815 ld [%l0 + CPU_BASE_SPL], %l0 816 cmp %l6, %l0 817 movg %xcc, %l6, %l0 818 wrpr %g0, %l0, %pil 819 ! 820 ! raise tl 821 ! setup trap regs 822 ! restore to window we originally trapped in 823 ! 824 wrpr %g0, 1, %tl 825 ldn [%l7 + PC_OFF], %g1 826 ldn [%l7 + nPC_OFF], %g2 827 ldx [%l7 + TSTATE_OFF], %l0 828 andn %l0, TSTATE_CWP, %g7 829 wrpr %g1, %tpc 830 wrpr %g2, %tnpc 831 restore 832 ! 833 ! set %tstate to the correct %cwp 834 ! retry resumes prom execution 835 ! 836 rdpr %cwp, %g1 837 wrpr %g1, %g7, %tstate 838 retry 839 /* NOTREACHED */ 840 SET_SIZE(priv_rtt) 841 SET_SIZE(ktl0) 842 843 #ifdef DEBUG 844 .seg ".data" 845 .align 4 846 847 .global bad_g4_called 848 bad_g4_called: 849 .word 0 850 851 sys_trap_wrong_pil: 852 .asciz "sys_trap: %g4(%d) is lower than %pil(%d)" 853 .align 4 854 .seg ".text" 855 856 ENTRY_NP(bad_g4) 857 mov %o1, %o0 858 mov %o2, %o1 859 call panic 860 mov %o3, %o2 861 SET_SIZE(bad_g4) 862 #endif /* DEBUG */ 863 864 /* 865 * sys_tl1_panic can be called by traps at tl1 which 866 * really want to panic, but need the rearrangement of 867 * the args as provided by this wrapper routine. 868 */ 869 ENTRY_NP(sys_tl1_panic) 870 mov %o1, %o0 871 mov %o2, %o1 872 call panic 873 mov %o3, %o2 874 SET_SIZE(sys_tl1_panic) 875 876 /* 877 * Turn on or off bits in the auxiliary i/o register. 878 * 879 * set_auxioreg(bit, flag) 880 * int bit; bit mask in aux i/o reg 881 * int flag; 0 = off, otherwise on 882 * 883 * This is intrinsicly ugly but is used by the floppy driver. It is also 884 * used to turn on/off the led. 885 */ 886 887 .seg ".data" 888 .align 4 889 auxio_panic: 890 .asciz "set_auxioreg: interrupts already disabled on entry" 891 .align 4 892 .seg ".text" 893 894 ENTRY_NP(set_auxioreg) 895 /* 896 * o0 = bit mask 897 * o1 = flag: 0 = off, otherwise on 898 * 899 * disable interrupts while updating auxioreg 900 */ 901 rdpr %pstate, %o2 902 #ifdef DEBUG 903 andcc %o2, PSTATE_IE, %g0 /* if interrupts already */ 904 bnz,a,pt %icc, 1f /* disabled, panic */ 905 nop 906 sethi %hi(auxio_panic), %o0 907 call panic 908 or %o0, %lo(auxio_panic), %o0 909 1: 910 #endif /* DEBUG */ 911 wrpr %o2, PSTATE_IE, %pstate /* disable interrupts */ 912 sethi %hi(v_auxio_addr), %o3 913 ldn [%o3 + %lo(v_auxio_addr)], %o4 914 ldub [%o4], %g1 /* read aux i/o register */ 915 tst %o1 916 bnz,a 2f 917 bset %o0, %g1 /* on */ 918 bclr %o0, %g1 /* off */ 919 2: 920 or %g1, AUX_MBO, %g1 /* Must Be Ones */ 921 stb %g1, [%o4] /* write aux i/o register */ 922 retl 923 wrpr %g0, %o2, %pstate /* enable interrupt */ 924 SET_SIZE(set_auxioreg) 925 926 /* 927 * Flush all windows to memory, except for the one we entered in. 928 * We do this by doing NWINDOW-2 saves then the same number of restores. 929 * This leaves the WIM immediately before window entered in. 930 * This is used for context switching. 931 */ 932 933 ENTRY_NP(flush_windows) 934 retl 935 flushw 936 SET_SIZE(flush_windows) 937 938 ENTRY_NP(debug_flush_windows) 939 set nwindows, %g1 940 ld [%g1], %g1 941 mov %g1, %g2 942 943 1: 944 save %sp, -WINDOWSIZE, %sp 945 brnz %g2, 1b 946 dec %g2 947 948 mov %g1, %g2 949 2: 950 restore 951 brnz %g2, 2b 952 dec %g2 953 954 retl 955 nop 956 957 SET_SIZE(debug_flush_windows) 958 959 /* 960 * flush user windows to memory. 961 */ 962 963 ENTRY_NP(flush_user_windows) 964 rdpr %otherwin, %g1 965 brz %g1, 3f 966 clr %g2 967 1: 968 save %sp, -WINDOWSIZE, %sp 969 rdpr %otherwin, %g1 970 brnz %g1, 1b 971 add %g2, 1, %g2 972 2: 973 sub %g2, 1, %g2 ! restore back to orig window 974 brnz %g2, 2b 975 restore 976 3: 977 retl 978 nop 979 SET_SIZE(flush_user_windows) 980 981 /* 982 * Throw out any user windows in the register file. 983 * Used by setregs (exec) to clean out old user. 984 * Used by sigcleanup to remove extraneous windows when returning from a 985 * signal. 986 */ 987 988 ENTRY_NP(trash_user_windows) 989 rdpr %otherwin, %g1 990 brz %g1, 3f ! no user windows? 991 ldn [THREAD_REG + T_STACK], %g5 992 993 ! 994 ! There are old user windows in the register file. We disable ints 995 ! and increment cansave so that we don't overflow on these windows. 996 ! Also, this sets up a nice underflow when first returning to the 997 ! new user. 998 ! 999 rdpr %pstate, %g2 1000 wrpr %g2, PSTATE_IE, %pstate 1001 rdpr %cansave, %g3 1002 rdpr %otherwin, %g1 ! re-read in case of interrupt 1003 add %g3, %g1, %g3 1004 wrpr %g0, 0, %otherwin 1005 wrpr %g0, %g3, %cansave 1006 wrpr %g0, %g2, %pstate 1007 3: 1008 retl 1009 clr [%g5 + MPCB_WBCNT] ! zero window buffer cnt 1010 SET_SIZE(trash_user_windows) 1011 1012 1013 /* 1014 * Setup g7 via the CPU data structure. 1015 */ 1016 1017 ENTRY_NP(set_tbr) 1018 retl 1019 ta 72 ! no tbr, stop simulation 1020 SET_SIZE(set_tbr) 1021 1022 1023 #define PTL1_SAVE_WINDOW(RP) \ 1024 stxa %l0, [RP + RW64_LOCAL + (0 * RW64_LOCAL_INCR)] %asi; \ 1025 stxa %l1, [RP + RW64_LOCAL + (1 * RW64_LOCAL_INCR)] %asi; \ 1026 stxa %l2, [RP + RW64_LOCAL + (2 * RW64_LOCAL_INCR)] %asi; \ 1027 stxa %l3, [RP + RW64_LOCAL + (3 * RW64_LOCAL_INCR)] %asi; \ 1028 stxa %l4, [RP + RW64_LOCAL + (4 * RW64_LOCAL_INCR)] %asi; \ 1029 stxa %l5, [RP + RW64_LOCAL + (5 * RW64_LOCAL_INCR)] %asi; \ 1030 stxa %l6, [RP + RW64_LOCAL + (6 * RW64_LOCAL_INCR)] %asi; \ 1031 stxa %l7, [RP + RW64_LOCAL + (7 * RW64_LOCAL_INCR)] %asi; \ 1032 stxa %i0, [RP + RW64_IN + (0 * RW64_IN_INCR)] %asi; \ 1033 stxa %i1, [RP + RW64_IN + (1 * RW64_IN_INCR)] %asi; \ 1034 stxa %i2, [RP + RW64_IN + (2 * RW64_IN_INCR)] %asi; \ 1035 stxa %i3, [RP + RW64_IN + (3 * RW64_IN_INCR)] %asi; \ 1036 stxa %i4, [RP + RW64_IN + (4 * RW64_IN_INCR)] %asi; \ 1037 stxa %i5, [RP + RW64_IN + (5 * RW64_IN_INCR)] %asi; \ 1038 stxa %i6, [RP + RW64_IN + (6 * RW64_IN_INCR)] %asi; \ 1039 stxa %i7, [RP + RW64_IN + (7 * RW64_IN_INCR)] %asi 1040 #define PTL1_NEXT_WINDOW(scr) \ 1041 add scr, RWIN64SIZE, scr 1042 1043 #define PTL1_RESET_RWINDOWS(scr) \ 1044 sethi %hi(nwin_minus_one), scr; \ 1045 ld [scr + %lo(nwin_minus_one)], scr; \ 1046 wrpr scr, %cleanwin; \ 1047 dec scr; \ 1048 wrpr scr, %cansave; \ 1049 wrpr %g0, %canrestore; \ 1050 wrpr %g0, %otherwin 1051 1052 #define PTL1_DCACHE_LINE_SIZE 4 /* small enough for all CPUs */ 1053 1054 /* 1055 * ptl1_panic is called when the kernel detects that it is in an invalid state 1056 * and the trap level is greater than 0. ptl1_panic is responsible to save the 1057 * current CPU state, to restore the CPU state to normal, and to call panic. 1058 * The CPU state must be saved reliably without causing traps. ptl1_panic saves 1059 * it in the ptl1_state structure, which is a member of the machcpu structure. 1060 * In order to access the ptl1_state structure without causing traps, physical 1061 * addresses are used so that we can avoid MMU miss traps. The restriction of 1062 * physical memory accesses is that the ptl1_state structure must be on a single 1063 * physical page. This is because (1) a single physical address for each 1064 * ptl1_state structure is needed and (2) it simplifies physical address 1065 * calculation for each member of the structure. 1066 * ptl1_panic is a likely spot for stack overflows to wind up; thus, the current 1067 * stack may not be usable. In order to call panic reliably in such a state, 1068 * each CPU needs a dedicated ptl1 panic stack. 1069 * CPU_ALLOC_SIZE, which is defined to be MMU_PAGESIZE, is used to allocate the 1070 * cpu structure and a ptl1 panic stack. They are put together on the same page 1071 * for memory space efficiency. The low address part is used for the cpu 1072 * structure, and the high address part is for a ptl1 panic stack. 1073 * The cpu_pa array holds the physical addresses of the allocated cpu structures, 1074 * as the cpu array holds their virtual addresses. 1075 * 1076 * %g1 reason to be called 1077 * %g2 broken 1078 * %g3 broken 1079 */ 1080 ENTRY_NP(ptl1_panic) 1081 ! 1082 ! flush D$ first, so that stale data will not be accessed later. 1083 ! Data written via ASI_MEM bypasses D$. If D$ contains data at the same 1084 ! address, where data was written via ASI_MEM, a load from that address 1085 ! using a virtual address and the default ASI still takes the old data. 1086 ! Flushing D$ erases old data in D$, so that it will not be loaded. 1087 ! Since we can afford only 2 registers (%g2 and %g3) for this job, we 1088 ! flush entire D$. 1089 ! For FJ OPL processors (IMPL values < SPITFIRE_IMPL), DC flushing 1090 ! is not needed. 1091 ! 1092 GET_CPU_IMPL(%g2) 1093 cmp %g2, SPITFIRE_IMPL 1094 blt,pn %icc, 1f ! Skip flushing for OPL processors 1095 nop 1096 sethi %hi(dcache_size), %g2 1097 ld [%g2 + %lo(dcache_size)], %g2 1098 sethi %hi(dcache_linesize), %g3 1099 ld [%g3 + %lo(dcache_linesize)], %g3 1100 sub %g2, %g3, %g2 1101 0: stxa %g0, [%g2] ASI_DC_TAG 1102 membar #Sync 1103 brnz,pt %g2, 0b 1104 sub %g2, %g3, %g2 1105 1: 1106 ! 1107 ! increment the entry counter. 1108 ! save CPU state if this is the first entry. 1109 ! 1110 CPU_PADDR(%g2, %g3); 1111 add %g2, CPU_PTL1, %g2 ! pstate = &CPU->mcpu.ptl1_state 1112 wr %g0, ASI_MEM, %asi ! physical address access 1113 ! 1114 ! pstate->ptl1_entry_count++ 1115 ! 1116 lduwa [%g2 + PTL1_ENTRY_COUNT] %asi, %g3 1117 add %g3, 1, %g3 1118 stuwa %g3, [%g2 + PTL1_ENTRY_COUNT] %asi 1119 ! 1120 ! CPU state saving is skipped from the 2nd entry to ptl1_panic since we 1121 ! do not want to clobber the state from the original failure. panic() 1122 ! is responsible for handling multiple or recursive panics. 1123 ! 1124 cmp %g3, 2 ! if (ptl1_entry_count >= 2) 1125 bge,pn %icc, state_saved ! goto state_saved 1126 add %g2, PTL1_REGS, %g3 ! %g3 = &pstate->ptl1_regs[0] 1127 ! 1128 ! save CPU state 1129 ! 1130 save_cpu_state: 1131 ! save current global registers 1132 ! so that all them become available for use 1133 ! 1134 stxa %g1, [%g3 + PTL1_G1] %asi 1135 stxa %g2, [%g3 + PTL1_G2] %asi 1136 stxa %g3, [%g3 + PTL1_G3] %asi 1137 stxa %g4, [%g3 + PTL1_G4] %asi 1138 stxa %g5, [%g3 + PTL1_G5] %asi 1139 stxa %g6, [%g3 + PTL1_G6] %asi 1140 stxa %g7, [%g3 + PTL1_G7] %asi 1141 ! 1142 ! %tl, %tt, %tstate, %tpc, %tnpc for each TL 1143 ! 1144 rdpr %tl, %g1 1145 brz %g1, 1f ! if(trap_level == 0) -------+ 1146 add %g3, PTL1_TRAP_REGS, %g4 ! %g4 = &ptl1_trap_regs[0]; ! 1147 0: ! -----------<----------+ ! 1148 stwa %g1, [%g4 + PTL1_TL] %asi ! ! 1149 rdpr %tt, %g5 ! ! 1150 stwa %g5, [%g4 + PTL1_TT] %asi ! ! 1151 rdpr %tstate, %g5 ! ! 1152 stxa %g5, [%g4 + PTL1_TSTATE] %asi ! ! 1153 rdpr %tpc, %g5 ! ! 1154 stxa %g5, [%g4 + PTL1_TPC] %asi ! ! 1155 rdpr %tnpc, %g5 ! ! 1156 stxa %g5, [%g4 + PTL1_TNPC] %asi ! ! 1157 add %g4, PTL1_TRAP_REGS_INCR, %g4 ! ! 1158 deccc %g1 ! ! 1159 bnz,a,pt %icc, 0b ! if(trap_level != 0) --+ ! 1160 wrpr %g1, %tl ! 1161 1: ! ----------<----------------+ 1162 ! 1163 ! %pstate, %pil, SOFTINT, (S)TICK 1164 ! Pending interrupts is also cleared in order to avoid a recursive call 1165 ! to ptl1_panic in case the interrupt handler causes a panic. 1166 ! 1167 rdpr %pil, %g1 1168 stba %g1, [%g3 + PTL1_PIL] %asi 1169 rdpr %pstate, %g1 1170 stha %g1, [%g3 + PTL1_PSTATE] %asi 1171 rd SOFTINT, %g1 1172 sta %g1, [%g3 + PTL1_SOFTINT] %asi 1173 wr %g1, CLEAR_SOFTINT 1174 sethi %hi(traptrace_use_stick), %g1 1175 ld [%g1 + %lo(traptrace_use_stick)], %g1 1176 brz,a,pn %g1, 2f 1177 rdpr %tick, %g1 1178 rd STICK, %g1 1179 2: stxa %g1, [%g3 + PTL1_TICK] %asi 1180 1181 ! 1182 ! MMU registers because ptl1_panic may be called from 1183 ! the MMU trap handlers. 1184 ! 1185 mov MMU_SFAR, %g1 1186 ldxa [%g1]ASI_DMMU, %g4 1187 stxa %g4, [%g3 + PTL1_DMMU_SFAR]%asi 1188 mov MMU_SFSR, %g1 1189 ldxa [%g1]ASI_DMMU, %g4 1190 stxa %g4, [%g3 + PTL1_DMMU_SFSR]%asi 1191 ldxa [%g1]ASI_IMMU, %g4 1192 stxa %g4, [%g3 + PTL1_IMMU_SFSR]%asi 1193 mov MMU_TAG_ACCESS, %g1 1194 ldxa [%g1]ASI_DMMU, %g4 1195 stxa %g4, [%g3 + PTL1_DMMU_TAG_ACCESS]%asi 1196 ldxa [%g1]ASI_IMMU, %g4 1197 stxa %g4, [%g3 + PTL1_IMMU_TAG_ACCESS]%asi 1198 1199 ! 1200 ! Save register window state and register windows. 1201 ! 1202 rdpr %cwp, %g1 1203 stba %g1, [%g3 + PTL1_CWP] %asi 1204 rdpr %wstate, %g1 1205 stba %g1, [%g3 + PTL1_WSTATE] %asi 1206 rdpr %otherwin, %g1 1207 stba %g1, [%g3 + PTL1_OTHERWIN] %asi 1208 rdpr %cleanwin, %g1 1209 stba %g1, [%g3 + PTL1_CLEANWIN] %asi 1210 rdpr %cansave, %g1 1211 stba %g1, [%g3 + PTL1_CANSAVE] %asi 1212 rdpr %canrestore, %g1 1213 stba %g1, [%g3 + PTL1_CANRESTORE] %asi 1214 1215 PTL1_RESET_RWINDOWS(%g1) 1216 clr %g1 1217 wrpr %g1, %cwp 1218 add %g3, PTL1_RWINDOW, %g4 ! %g4 = &ptl1_rwindow[0]; 1219 1220 3: PTL1_SAVE_WINDOW(%g4) ! <-------------+ 1221 inc %g1 ! 1222 cmp %g1, MAXWIN ! 1223 bgeu,pn %icc, 5f ! 1224 wrpr %g1, %cwp ! 1225 rdpr %cwp, %g2 ! 1226 cmp %g1, %g2 ! saturation check 1227 be,pt %icc, 3b ! 1228 PTL1_NEXT_WINDOW(%g4) ! ------+ 1229 5: 1230 ! 1231 ! most crucial CPU state was saved. 1232 ! Proceed to go back to TL = 0. 1233 ! 1234 state_saved: 1235 wrpr %g0, 1, %tl 1236 wrpr %g0, PIL_MAX, %pil 1237 ! 1238 PTL1_RESET_RWINDOWS(%g1) 1239 wrpr %g0, %cwp 1240 wrpr %g0, %cleanwin 1241 wrpr %g0, WSTATE_KERN, %wstate 1242 ! 1243 ! Set pcontext to run kernel. 1244 ! 1245 ! For OPL, load kcontexreg instead of clearing primary 1246 ! context register. This is to avoid changing nucleus page 1247 ! size bits after boot initialization. 1248 ! 1249 #ifdef _OPL 1250 sethi %hi(kcontextreg), %g4 1251 ldx [%g4 + %lo(kcontextreg)], %g4 1252 #endif /* _OPL */ 1253 1254 set DEMAP_ALL_TYPE, %g1 1255 sethi %hi(FLUSH_ADDR), %g3 1256 set MMU_PCONTEXT, %g2 1257 1258 stxa %g0, [%g1]ASI_DTLB_DEMAP 1259 stxa %g0, [%g1]ASI_ITLB_DEMAP 1260 1261 #ifdef _OPL 1262 stxa %g4, [%g2]ASI_MMU_CTX 1263 #else /* _OPL */ 1264 stxa %g0, [%g2]ASI_MMU_CTX 1265 #endif /* _OPL */ 1266 1267 flush %g3 1268 1269 rdpr %cwp, %g1 1270 set TSTATE_KERN, %g3 1271 wrpr %g3, %g1, %tstate 1272 set ptl1_panic_tl0, %g3 1273 wrpr %g0, %g3, %tnpc 1274 done ! go to -->-+ TL:1 1275 ! 1276 ptl1_panic_tl0: ! ----<-----+ TL:0 1277 CPU_ADDR(%l0, %l1) ! %l0 = cpu[cpuid] 1278 add %l0, CPU_PTL1, %l1 ! %l1 = &CPU->mcpu.ptl1_state 1279 ! 1280 ! prepare to call panic() 1281 ! 1282 ldn [%l0 + CPU_THREAD], THREAD_REG ! restore %g7 1283 ldn [%l1 + PTL1_STKTOP], %l2 ! %sp = ptl1_stktop 1284 sub %l2, SA(MINFRAME) + STACK_BIAS, %sp 1285 clr %fp ! no frame below this window 1286 clr %i7 1287 ! 1288 ! enable limited interrupts 1289 ! 1290 wrpr %g0, CLOCK_LEVEL, %pil 1291 wrpr %g0, PSTATE_KERN, %pstate 1292 ! 1293 ba,pt %xcc, ptl1_panic_handler 1294 mov %l1, %o0 1295 /*NOTREACHED*/ 1296 SET_SIZE(ptl1_panic) 1297 1298 #ifdef PTL1_PANIC_DEBUG 1299 1300 /* 1301 * ptl1_recurse() calls itself a number of times to either set up a known 1302 * stack or to cause a kernel stack overflow. It decrements the arguments 1303 * on each recursion. 1304 * It's called by #ifdef PTL1_PANIC_DEBUG code in startup.c to set the 1305 * registers to a known state to facilitate debugging. 1306 */ 1307 ENTRY_NP(ptl1_recurse) 1308 save %sp, -SA(MINFRAME), %sp 1309 1310 set ptl1_recurse_call, %o7 1311 cmp %o7, %i7 ! if ptl1_recurse is called 1312 be,pt %icc, 0f ! by itself, then skip 1313 nop ! register initialization 1314 1315 /* 1316 * Initialize Out Registers to Known Values 1317 */ 1318 set 0x01000, %l0 ! %i0 is the ... 1319 ! recursion_depth_count 1320 sub %i0, 1, %o0; 1321 sub %i1, 1, %o1; 1322 add %l0, %o0, %o2; 1323 add %l0, %o2, %o3; 1324 add %l0, %o3, %o4; 1325 add %l0, %o4, %o5; 1326 ba,a 1f 1327 nop 1328 1329 0: /* Outs = Ins - 1 */ 1330 sub %i0, 1, %o0; 1331 sub %i1, 1, %o1; 1332 sub %i2, 1, %o2; 1333 sub %i3, 1, %o3; 1334 sub %i4, 1, %o4; 1335 sub %i5, 1, %o5; 1336 1337 /* Locals = Ins + 1 */ 1338 1: add %i0, 1, %l0; 1339 add %i1, 1, %l1; 1340 add %i2, 1, %l2; 1341 add %i3, 1, %l3; 1342 add %i4, 1, %l4; 1343 add %i5, 1, %l5; 1344 1345 set 0x0100000, %g5 1346 add %g5, %g0, %g1 1347 add %g5, %g1, %g2 1348 add %g5, %g2, %g3 1349 add %g5, %g3, %g4 1350 add %g5, %g4, %g5 1351 1352 brz,pn %i1, ptl1_recurse_trap ! if trpp_count == 0) { 1353 nop ! trap to ptl1_panic 1354 ! 1355 brz,pn %i0, ptl1_recure_exit ! if(depth_count == 0) { 1356 nop ! skip recursive call 1357 ! } 1358 ptl1_recurse_call: 1359 call ptl1_recurse 1360 nop 1361 1362 ptl1_recure_exit: 1363 ret 1364 restore 1365 1366 ptl1_recurse_trap: 1367 ta PTL1_DEBUG_TRAP; ! Trap Always to ptl1_panic() 1368 nop ! NOTREACHED 1369 SET_SIZE(ptl1_recurse) 1370 1371 /* 1372 * Asm function to handle a cross trap to call ptl1_panic() 1373 */ 1374 ENTRY_NP(ptl1_panic_xt) 1375 ba ptl1_panic 1376 mov PTL1_BAD_DEBUG, %g1 1377 SET_SIZE(ptl1_panic_xt) 1378 1379 #endif /* PTL1_PANIC_DEBUG */ 1380 1381 #ifdef TRAPTRACE 1382 1383 ENTRY_NP(trace_ptr_panic) 1384 ! 1385 ! freeze the trap trace to disable the assertions. Otherwise, 1386 ! ptl1_panic is likely to be repeatedly called from there. 1387 ! %g2 and %g3 are used as scratch registers in ptl1_panic. 1388 ! 1389 mov 1, %g3 1390 sethi %hi(trap_freeze), %g2 1391 st %g3, [%g2 + %lo(trap_freeze)] 1392 ! 1393 ! %g1 contains the %pc address where an assertion was failed. 1394 ! save it in trap_freeze_pc for a debugging hint if there is 1395 ! no value saved in it. 1396 ! 1397 set trap_freeze_pc, %g2 1398 casn [%g2], %g0, %g1 1399 1400 ba ptl1_panic 1401 mov PTL1_BAD_TRACE_PTR, %g1 1402 SET_SIZE(trace_ptr_panic) 1403 1404 #endif /* TRAPTRACE */ 1405 /* 1406 * set_kcontextreg() sets PCONTEXT to kctx 1407 * if PCONTEXT==kctx, do nothing 1408 * if N_pgsz0|N_pgsz1 differ, do demap all first 1409 */ 1410 ENTRY_NP(set_kcontextreg) 1411 ! SET_KCONTEXTREG(reg0, reg1, reg2, reg3, reg4, label1, label2, label3) 1412 SET_KCONTEXTREG(%o0, %o1, %o2, %o3, %o4, l1, l2, l3) 1413 retl 1414 nop 1415 SET_SIZE(set_kcontextreg) 1416 1417 /* 1418 * The interface for a 32-bit client program that takes over the TBA 1419 * calling the 64-bit romvec OBP. 1420 */ 1421 1422 ENTRY(client_handler) 1423 save %sp, -SA64(MINFRAME64), %sp ! 32 bit frame, 64 bit sized 1424 sethi %hi(tba_taken_over), %l2 1425 ld [%l2+%lo(tba_taken_over)], %l3 1426 brz %l3, 1f ! is the tba_taken_over = 1 ? 1427 rdpr %wstate, %l5 ! save %wstate 1428 andn %l5, WSTATE_MASK, %l6 1429 wrpr %l6, WSTATE_KMIX, %wstate 1430 1431 ! 1432 ! switch to PCONTEXT=0 1433 ! 1434 #ifndef _OPL 1435 mov MMU_PCONTEXT, %o2 1436 ldxa [%o2]ASI_DMMU, %o2 1437 srlx %o2, CTXREG_NEXT_SHIFT, %o2 1438 brz,pt %o2, 1f ! nucleus pgsz is 0, no problem 1439 nop 1440 rdpr %pstate, %l4 ! disable interrupts 1441 andn %l4, PSTATE_IE, %o2 1442 wrpr %g0, %o2, %pstate 1443 mov DEMAP_ALL_TYPE, %o2 ! set PCONTEXT=0 1444 stxa %g0, [%o2]ASI_DTLB_DEMAP 1445 stxa %g0, [%o2]ASI_ITLB_DEMAP 1446 mov MMU_PCONTEXT, %o2 1447 stxa %g0, [%o2]ASI_DMMU 1448 membar #Sync 1449 sethi %hi(FLUSH_ADDR), %o2 1450 flush %o2 ! flush required by immu 1451 wrpr %g0, %l4, %pstate ! restore interrupt state 1452 #endif /* _OPL */ 1453 1454 1: mov %i1, %o0 1455 rdpr %pstate, %l4 ! Get the present pstate value 1456 andn %l4, PSTATE_AM, %l6 1457 wrpr %l6, 0, %pstate ! Set PSTATE_AM = 0 1458 jmpl %i0, %o7 ! Call cif handler 1459 nop 1460 wrpr %l4, 0, %pstate ! restore pstate 1461 brz %l3, 1f ! is the tba_taken_over = 1 1462 nop 1463 wrpr %g0, %l5, %wstate ! restore wstate 1464 1465 ! 1466 ! switch to PCONTEXT=kcontexreg 1467 ! 1468 #ifndef _OPL 1469 sethi %hi(kcontextreg), %o3 1470 ldx [%o3 + %lo(kcontextreg)], %o3 1471 brz %o3, 1f 1472 nop 1473 rdpr %pstate, %l4 ! disable interrupts 1474 andn %l4, PSTATE_IE, %o2 1475 wrpr %g0, %o2, %pstate 1476 mov DEMAP_ALL_TYPE, %o2 1477 stxa %g0, [%o2]ASI_DTLB_DEMAP 1478 stxa %g0, [%o2]ASI_ITLB_DEMAP 1479 mov MMU_PCONTEXT, %o2 1480 stxa %o3, [%o2]ASI_DMMU 1481 membar #Sync 1482 sethi %hi(FLUSH_ADDR), %o2 1483 flush %o2 ! flush required by immu 1484 wrpr %g0, %l4, %pstate ! restore interrupt state 1485 #endif /* _OPL */ 1486 1487 1: ret ! Return result ... 1488 restore %o0, %g0, %o0 ! delay; result in %o0 1489 SET_SIZE(client_handler) 1490