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