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 */