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