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 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 /*
  29  * SFMMU primitives.  These primitives should only be used by sfmmu
  30  * routines.
  31  */
  32 
  33 #if defined(lint)
  34 #include <sys/types.h>
  35 #else   /* lint */
  36 #include "assym.h"
  37 #endif  /* lint */
  38 
  39 #include <sys/asm_linkage.h>
  40 #include <sys/machtrap.h>
  41 #include <sys/machasi.h>
  42 #include <sys/sun4asi.h>
  43 #include <sys/pte.h>
  44 #include <sys/mmu.h>
  45 #include <vm/hat_sfmmu.h>
  46 #include <vm/seg_spt.h>
  47 #include <sys/machparam.h>
  48 #include <sys/privregs.h>
  49 #include <sys/scb.h>
  50 #include <sys/intreg.h>
  51 #include <sys/machthread.h>
  52 #include <sys/clock.h>
  53 #include <sys/trapstat.h>
  54 
  55 /*
  56  * sfmmu related subroutines
  57  */
  58 
  59 #if defined (lint)
  60 
  61 /*
  62  * sfmmu related subroutines
  63  */
  64 /* ARGSUSED */
  65 void
  66 sfmmu_raise_tsb_exception(uint64_t sfmmup, uint64_t rctx)
  67 {}
  68 
  69 /* ARGSUSED */
  70 void
  71 sfmmu_itlb_ld_kva(caddr_t vaddr, tte_t *tte)
  72 {}
  73 
  74 /* ARGSUSED */
  75 void
  76 sfmmu_dtlb_ld_kva(caddr_t vaddr, tte_t *tte)
  77 {}
  78 
  79 int
  80 sfmmu_getctx_pri()
  81 { return(0); }
  82 
  83 int
  84 sfmmu_getctx_sec()
  85 { return(0); }
  86 
  87 /* ARGSUSED */
  88 void
  89 sfmmu_setctx_sec(uint_t ctx)
  90 {}
  91 
  92 /* ARGSUSED */
  93 void
  94 sfmmu_load_mmustate(sfmmu_t *sfmmup)
  95 {
  96 }
  97 
  98 #else   /* lint */
  99 
 100 /*
 101  * Invalidate either the context of a specific victim or any process
 102  * currently running on this CPU. 
 103  *
 104  * %g1 = sfmmup whose ctx is being invalidated
 105  *       when called from sfmmu_wrap_around, %g1 == INVALID_CONTEXT
 106  * Note %g1 is the only input argument used by this xcall handler.
 107  */
 108         ENTRY(sfmmu_raise_tsb_exception)
 109         !
 110         ! if (victim == INVALID_CONTEXT ||
 111         !     current CPU tsbmiss->usfmmup == victim sfmmup) {
 112         !       if (shctx_on) {
 113         !               shctx = INVALID;
 114         !       }
 115         !       if (sec-ctx > INVALID_CONTEXT) {
 116         !               write INVALID_CONTEXT to sec-ctx
 117         !       }
 118         !       if (pri-ctx > INVALID_CONTEXT) {
 119         !               write INVALID_CONTEXT to pri-ctx
 120         !       }
 121         ! }
 122 
 123         sethi   %hi(ksfmmup), %g3
 124         ldx     [%g3 + %lo(ksfmmup)], %g3
 125         cmp     %g1, %g3
 126         be,a,pn %xcc, ptl1_panic                /* can't invalidate kernel ctx */
 127           mov   PTL1_BAD_RAISE_TSBEXCP, %g1
 128 
 129         set     INVALID_CONTEXT, %g2
 130         cmp     %g1, INVALID_CONTEXT
 131         be,pn   %xcc, 0f                        /* called from wrap_around? */
 132           mov   MMU_SCONTEXT, %g3
 133 
 134         CPU_TSBMISS_AREA(%g5, %g6)              /* load cpu tsbmiss area */
 135         ldx     [%g5 + TSBMISS_UHATID], %g5     /* load usfmmup */
 136         cmp     %g5, %g1                        /* hat toBe-invalid running? */
 137         bne,pt  %xcc, 3f
 138           nop
 139 
 140 0:
 141         sethi   %hi(shctx_on), %g5
 142         ld      [%g5 + %lo(shctx_on)], %g5
 143         brz     %g5, 1f
 144           mov     MMU_SHARED_CONTEXT, %g5
 145         sethi   %hi(FLUSH_ADDR), %g4
 146         stxa    %g0, [%g5]ASI_MMU_CTX
 147         flush   %g4
 148 
 149 1:
 150         ldxa    [%g3]ASI_MMU_CTX, %g5           /* %g5 = pgsz | sec-ctx */
 151         set     CTXREG_CTX_MASK, %g4
 152         and     %g5, %g4, %g5                   /* %g5 = sec-ctx */
 153         cmp     %g5, INVALID_CONTEXT            /* kernel ctx or invald ctx? */
 154         ble,pn  %xcc, 2f                        /* yes, no need to change */
 155           mov   MMU_PCONTEXT, %g7
 156 
 157         stxa    %g2, [%g3]ASI_MMU_CTX           /* set invalid ctx */
 158         membar  #Sync
 159         
 160 2:
 161         ldxa    [%g7]ASI_MMU_CTX, %g3           /* get pgz | pri-ctx */
 162         and     %g3, %g4, %g5                   /* %g5 = pri-ctx */
 163         cmp     %g5, INVALID_CONTEXT            /* kernel ctx or invald ctx? */
 164         ble,pn  %xcc, 3f                        /* yes, no need to change */
 165           srlx  %g3, CTXREG_NEXT_SHIFT, %g3     /* %g3 = nucleus pgsz */
 166         sllx    %g3, CTXREG_NEXT_SHIFT, %g3     /* need to preserve nucleus pgsz */
 167         or      %g3, %g2, %g2                   /* %g2 = nucleus pgsz | INVALID_CONTEXT */
 168         
 169         stxa    %g2, [%g7]ASI_MMU_CTX           /* set pri-ctx to invalid */
 170 3:
 171         retry
 172         SET_SIZE(sfmmu_raise_tsb_exception)
 173         
 174 
 175 
 176         /*
 177          * %o0 = virtual address
 178          * %o1 = address of TTE to be loaded
 179          */
 180         ENTRY_NP(sfmmu_itlb_ld_kva)
 181         rdpr    %pstate, %o3
 182 #ifdef DEBUG
 183         PANIC_IF_INTR_DISABLED_PSTR(%o3, msfmmu_di_l1, %g1)
 184 #endif /* DEBUG */
 185         wrpr    %o3, PSTATE_IE, %pstate         ! Disable interrupts
 186         srln    %o0, MMU_PAGESHIFT, %o0
 187         slln    %o0, MMU_PAGESHIFT, %o0         ! Clear page offset
 188 
 189         ldx     [%o1], %g1
 190         set     MMU_TAG_ACCESS, %o5
 191 #ifdef  CHEETAHPLUS_ERRATUM_34
 192         !
 193         ! If this is Cheetah or derivative and the specified TTE is locked
 194         ! and hence to be loaded into the T16, fully-associative TLB, we
 195         ! must avoid Cheetah+ erratum 34.  In Cheetah+ erratum 34, under
 196         ! certain conditions an ITLB locked index 0 TTE will erroneously be
 197         ! displaced when a new TTE is loaded via ASI_ITLB_IN.  To avoid
 198         ! this erratum, we scan the T16 top down for an unlocked TTE and
 199         ! explicitly load the specified TTE into that index.
 200         !
 201         GET_CPU_IMPL(%g2)
 202         cmp     %g2, CHEETAH_IMPL
 203         bl,pn   %icc, 0f
 204           nop
 205 
 206         andcc   %g1, TTE_LCK_INT, %g0
 207         bz      %icc, 0f                        ! Lock bit is not set;
 208                                                 !   load normally.
 209           or    %g0, (15 << 3), %g3               ! Start searching from the
 210                                                 !   top down.
 211 
 212 1:
 213         ldxa    [%g3]ASI_ITLB_ACCESS, %g4       ! Load TTE from t16
 214 
 215         !
 216         ! If this entry isn't valid, we'll choose to displace it (regardless
 217         ! of the lock bit).
 218         !
 219         cmp     %g4, %g0
 220         bge     %xcc, 2f                        ! TTE is > 0 iff not valid
 221           andcc %g4, TTE_LCK_INT, %g0           ! Check for lock bit
 222         bz      %icc, 2f                        ! If unlocked, go displace
 223           nop
 224         sub     %g3, (1 << 3), %g3
 225         brgz    %g3, 1b                         ! Still more TLB entries
 226           nop                                   ! to search
 227 
 228         sethi   %hi(sfmmu_panic5), %o0          ! We searched all entries and
 229         call    panic                           ! found no unlocked TTE so
 230           or    %o0, %lo(sfmmu_panic5), %o0     ! give up.
 231 
 232 
 233 2:
 234         !
 235         ! We have found an unlocked or non-valid entry; we'll explicitly load
 236         ! our locked entry here.
 237         !
 238         sethi   %hi(FLUSH_ADDR), %o1            ! Flush addr doesn't matter
 239         stxa    %o0, [%o5]ASI_IMMU
 240         stxa    %g1, [%g3]ASI_ITLB_ACCESS
 241         flush   %o1                             ! Flush required for I-MMU
 242         ba      3f                              ! Delay slot of ba is empty
 243           nop                                   !   per Erratum 64
 244 
 245 0:
 246 #endif  /* CHEETAHPLUS_ERRATUM_34 */
 247         sethi   %hi(FLUSH_ADDR), %o1            ! Flush addr doesn't matter
 248         stxa    %o0, [%o5]ASI_IMMU
 249         stxa    %g1, [%g0]ASI_ITLB_IN
 250         flush   %o1                             ! Flush required for I-MMU
 251 3:
 252         retl
 253           wrpr  %g0, %o3, %pstate               ! Enable interrupts
 254         SET_SIZE(sfmmu_itlb_ld_kva)
 255 
 256         /*
 257          * Load an entry into the DTLB.
 258          *
 259          * Special handling is required for locked entries since there
 260          * are some TLB slots that are reserved for the kernel but not
 261          * always held locked.  We want to avoid loading locked TTEs
 262          * into those slots since they could be displaced.
 263          *
 264          * %o0 = virtual address
 265          * %o1 = address of TTE to be loaded
 266          */
 267         ENTRY_NP(sfmmu_dtlb_ld_kva)
 268         rdpr    %pstate, %o3
 269 #ifdef DEBUG
 270         PANIC_IF_INTR_DISABLED_PSTR(%o3, msfmmu_di_l2, %g1)
 271 #endif /* DEBUG */
 272         wrpr    %o3, PSTATE_IE, %pstate         ! disable interrupts
 273         srln    %o0, MMU_PAGESHIFT, %o0
 274         slln    %o0, MMU_PAGESHIFT, %o0         ! clear page offset
 275 
 276         ldx     [%o1], %g1
 277 
 278         set     MMU_TAG_ACCESS, %o5
 279         
 280         set     cpu_impl_dual_pgsz, %o2
 281         ld      [%o2], %o2
 282         brz     %o2, 1f
 283           nop
 284 
 285         sethi   %hi(ksfmmup), %o2
 286         ldx     [%o2 + %lo(ksfmmup)], %o2
 287         ldub    [%o2 + SFMMU_CEXT], %o2
 288         sll     %o2, TAGACCEXT_SHIFT, %o2
 289 
 290         set     MMU_TAG_ACCESS_EXT, %o4         ! can go into T8 if unlocked
 291         stxa    %o2,[%o4]ASI_DMMU
 292         membar  #Sync
 293 1:
 294         andcc   %g1, TTE_LCK_INT, %g0           ! Locked entries require
 295         bnz,pn  %icc, 2f                        ! special handling
 296           sethi %hi(dtlb_resv_ttenum), %g3
 297         stxa    %o0,[%o5]ASI_DMMU               ! Load unlocked TTE
 298         stxa    %g1,[%g0]ASI_DTLB_IN            ! via DTLB_IN
 299         membar  #Sync
 300         retl
 301           wrpr  %g0, %o3, %pstate               ! enable interrupts
 302 2:
 303 #ifdef  CHEETAHPLUS_ERRATUM_34
 304         GET_CPU_IMPL(%g2)
 305 #endif
 306         ld      [%g3 + %lo(dtlb_resv_ttenum)], %g3
 307         sll     %g3, 3, %g3                     ! First reserved idx in TLB 0
 308         sub     %g3, (1 << 3), %g3                ! Decrement idx
 309         ! Erratum 15 workaround due to ld [%g3 + %lo(dtlb_resv_ttenum)], %g3
 310         ldxa    [%g3]ASI_DTLB_ACCESS, %g4       ! Load TTE from TLB 0
 311 3:
 312         ldxa    [%g3]ASI_DTLB_ACCESS, %g4       ! Load TTE from TLB 0
 313         !
 314         ! If this entry isn't valid, we'll choose to displace it (regardless
 315         ! of the lock bit).
 316         !
 317         brgez,pn %g4, 4f                        ! TTE is > 0 iff not valid
 318           nop
 319         andcc   %g4, TTE_LCK_INT, %g0           ! Check for lock bit
 320         bz,pn   %icc, 4f                        ! If unlocked, go displace
 321           nop
 322         sub     %g3, (1 << 3), %g3                ! Decrement idx
 323 #ifdef  CHEETAHPLUS_ERRATUM_34
 324         !
 325         ! If this is a Cheetah or derivative, we must work around Erratum 34
 326         ! for the DTLB.  Erratum 34 states that under certain conditions, 
 327         ! a locked entry 0 TTE may be improperly displaced.  To avoid this,
 328         ! we do not place a locked TTE in entry 0.
 329         !
 330         brgz    %g3, 3b
 331           nop
 332         cmp     %g2, CHEETAH_IMPL
 333         bge,pt  %icc, 5f
 334           nop
 335         brz     %g3, 3b
 336          nop
 337 #else   /* CHEETAHPLUS_ERRATUM_34 */
 338         brgez   %g3, 3b
 339           nop
 340 #endif  /* CHEETAHPLUS_ERRATUM_34 */
 341 5:
 342         sethi   %hi(sfmmu_panic5), %o0          ! We searched all entries and
 343         call    panic                           ! found no unlocked TTE so
 344           or    %o0, %lo(sfmmu_panic5), %o0     ! give up.
 345 4:
 346         stxa    %o0,[%o5]ASI_DMMU               ! Setup tag access
 347 #ifdef  OLYMPUS_SHARED_FTLB
 348         stxa    %g1,[%g0]ASI_DTLB_IN
 349 #else
 350         stxa    %g1,[%g3]ASI_DTLB_ACCESS        ! Displace entry at idx
 351 #endif
 352         membar  #Sync
 353         retl
 354           wrpr  %g0, %o3, %pstate               ! enable interrupts
 355         SET_SIZE(sfmmu_dtlb_ld_kva)
 356 
 357         ENTRY_NP(sfmmu_getctx_pri)
 358         set     MMU_PCONTEXT, %o0
 359         retl
 360           ldxa  [%o0]ASI_MMU_CTX, %o0
 361         SET_SIZE(sfmmu_getctx_pri)
 362 
 363         ENTRY_NP(sfmmu_getctx_sec)
 364         set     MMU_SCONTEXT, %o0
 365         set     CTXREG_CTX_MASK, %o1
 366         ldxa    [%o0]ASI_MMU_CTX, %o0
 367         retl
 368           and   %o0, %o1, %o0
 369         SET_SIZE(sfmmu_getctx_sec)
 370 
 371         /*
 372          * Set the secondary context register for this process.
 373          * %o0 = page_size | context number for this process.
 374          */
 375         ENTRY_NP(sfmmu_setctx_sec)
 376         /*
 377          * From resume we call sfmmu_setctx_sec with interrupts disabled.
 378          * But we can also get called from C with interrupts enabled. So,
 379          * we need to check first.
 380          */
 381 
 382         /* If interrupts are not disabled, then disable them */
 383         rdpr    %pstate, %g1
 384         btst    PSTATE_IE, %g1
 385         bnz,a,pt %icc, 1f
 386           wrpr  %g1, PSTATE_IE, %pstate         /* disable interrupts */
 387 
 388 1:
 389         mov     MMU_SCONTEXT, %o1
 390 
 391         sethi   %hi(FLUSH_ADDR), %o4
 392         stxa    %o0, [%o1]ASI_MMU_CTX           /* set 2nd context reg. */
 393         flush   %o4
 394         sethi   %hi(shctx_on), %g3
 395         ld      [%g3 + %lo(shctx_on)], %g3
 396         brz     %g3, 2f
 397           nop
 398         set     CTXREG_CTX_MASK, %o4
 399         and     %o0,%o4,%o1
 400         cmp     %o1, INVALID_CONTEXT
 401         bne,pn %icc, 2f
 402           mov     MMU_SHARED_CONTEXT, %o1
 403         sethi   %hi(FLUSH_ADDR), %o4
 404         stxa    %g0, [%o1]ASI_MMU_CTX           /* set 2nd context reg. */
 405         flush   %o4
 406 
 407         /*
 408          * if the routine was entered with intr enabled, then enable intr now.
 409          * otherwise, keep intr disabled, return without enabing intr.
 410          * %g1 - old intr state
 411          */
 412 2:      btst    PSTATE_IE, %g1
 413         bnz,a,pt %icc, 3f
 414           wrpr  %g0, %g1, %pstate               /* enable interrupts */
 415 3:      retl
 416           nop
 417         SET_SIZE(sfmmu_setctx_sec)
 418 
 419         /*
 420          * set ktsb_phys to 1 if the processor supports ASI_QUAD_LDD_PHYS.
 421          * returns the detection value in %o0.
 422          *
 423          * Currently ASI_QUAD_LDD_PHYS is supported in processors as follows
 424          *  - cheetah+ and later (greater or equal to CHEETAH_PLUS_IMPL)
 425          *  - FJ OPL Olympus-C and later  (less than SPITFIRE_IMPL)
 426          *
 427          */
 428         ENTRY_NP(sfmmu_setup_4lp)
 429         GET_CPU_IMPL(%o0);
 430         cmp     %o0, CHEETAH_PLUS_IMPL
 431         bge,pt  %icc, 4f
 432           mov   1, %o1
 433         cmp     %o0, SPITFIRE_IMPL
 434         bge,a,pn %icc, 3f
 435           clr   %o1
 436 4:
 437         set     ktsb_phys, %o2
 438         st      %o1, [%o2]
 439 3:      retl
 440         mov     %o1, %o0
 441         SET_SIZE(sfmmu_setup_4lp)
 442 
 443 
 444         /*
 445          * Called to load MMU registers and tsbmiss area
 446          * for the active process.  This function should
 447          * only be called from TL=0.
 448          *
 449          * %o0 - hat pointer
 450          *
 451          */
 452         ENTRY_NP(sfmmu_load_mmustate)
 453 
 454 #ifdef DEBUG
 455         PANIC_IF_INTR_ENABLED_PSTR(msfmmu_ei_l3, %g1)
 456 #endif /* DEBUG */
 457 
 458         sethi   %hi(ksfmmup), %o3
 459         ldx     [%o3 + %lo(ksfmmup)], %o3
 460         cmp     %o3, %o0
 461         be,pn   %xcc, 8f                        ! if kernel as, do nothing
 462           nop      
 463         /*
 464          * We need to set up the TSB base register, tsbmiss
 465          * area, and load locked TTE(s) for the TSB.
 466          */
 467         ldx     [%o0 + SFMMU_TSB], %o1          ! %o1 = first tsbinfo
 468         ldx     [%o1 + TSBINFO_NEXTPTR], %g2    ! %g2 = second tsbinfo
 469 
 470 #ifdef UTSB_PHYS
 471         /*
 472          * UTSB_PHYS accesses user TSBs via physical addresses.  The first
 473          * TSB is in the MMU I/D TSB Base registers.  The 2nd, 3rd and 
 474          * 4th TSBs use designated ASI_SCRATCHPAD regs as pseudo TSB base regs.
 475          */
 476          
 477         /* create/set first UTSBREG actually loaded into MMU_TSB  */
 478         MAKE_UTSBREG(%o1, %o2, %o3)             ! %o2 = first utsbreg
 479         LOAD_TSBREG(%o2, %o3, %o4)              ! write TSB base register
 480 
 481         brz,a,pt  %g2, 2f
 482           mov   -1, %o2                         ! use -1 if no second TSB
 483 
 484         MAKE_UTSBREG(%g2, %o2, %o3)             ! %o2 = second utsbreg
 485 2:
 486         SET_UTSBREG(SCRATCHPAD_UTSBREG2, %o2, %o3)
 487 
 488         /* make 3rd and 4th TSB */
 489         CPU_TSBMISS_AREA(%o4, %o3)              ! %o4 = tsbmiss area
 490 
 491         ldx     [%o0 + SFMMU_SCDP], %g2         ! %g2 = sfmmu_scd
 492         brz,pt  %g2, 3f
 493           mov   -1, %o2                         ! use -1 if no third TSB
 494 
 495         ldx     [%g2 + SCD_SFMMUP], %g3         ! %g3 = scdp->scd_sfmmup
 496         ldx     [%g3 + SFMMU_TSB], %o1          ! %o1 = first scd tsbinfo
 497         brz,pn %o1, 5f
 498           nop                                   ! panic if no third TSB
 499 
 500         /* make 3rd UTSBREG */
 501         MAKE_UTSBREG(%o1, %o2, %o3)             ! %o2 = third utsbreg
 502 3:
 503         SET_UTSBREG(SCRATCHPAD_UTSBREG3, %o2, %o3)
 504         stn     %o2, [%o4 + TSBMISS_TSBSCDPTR]
 505 
 506         brz,pt  %g2, 4f
 507           mov   -1, %o2                         ! use -1 if no 3rd or 4th TSB
 508 
 509         ldx     [%o1 + TSBINFO_NEXTPTR], %g2    ! %g2 = second scd tsbinfo
 510         brz,pt  %g2, 4f
 511           mov   -1, %o2                         ! use -1 if no 4th TSB
 512 
 513         /* make 4th UTSBREG */
 514         MAKE_UTSBREG(%g2, %o2, %o3)             ! %o2 = fourth utsbreg
 515 4:
 516         SET_UTSBREG(SCRATCHPAD_UTSBREG4, %o2, %o3)
 517         stn     %o2, [%o4 + TSBMISS_TSBSCDPTR4M]
 518         ba,pt   %icc, 6f
 519           mov   %o4, %o2                        ! %o2 = tsbmiss area
 520 5:
 521         sethi   %hi(panicstr), %g1              ! panic if no 3rd TSB
 522         ldx     [%g1 + %lo(panicstr)], %g1
 523         tst     %g1
 524 
 525         bnz,pn  %xcc, 8f
 526           nop    
 527 
 528         sethi   %hi(sfmmu_panic10), %o0
 529         call    panic
 530           or     %o0, %lo(sfmmu_panic10), %o0
 531           
 532 #else /* UTSBREG_PHYS */
 533 
 534         brz,pt  %g2, 4f 
 535           nop
 536         /*
 537          * We have a second TSB for this process, so we need to
 538          * encode data for both the first and second TSB in our single
 539          * TSB base register.  See hat_sfmmu.h for details on what bits
 540          * correspond to which TSB.
 541          * We also need to load a locked TTE into the TLB for the second TSB
 542          * in this case.
 543          */
 544         MAKE_TSBREG_SECTSB(%o2, %o1, %g2, %o3, %o4, %g3, sfmmu_tsb_2nd)
 545         ! %o2 = tsbreg
 546         sethi   %hi(utsb4m_dtlb_ttenum), %o3
 547         sethi   %hi(utsb4m_vabase), %o4
 548         ld      [%o3 + %lo(utsb4m_dtlb_ttenum)], %o3
 549         ldx     [%o4 + %lo(utsb4m_vabase)], %o4 ! %o4 = TLB tag for sec TSB
 550         sll     %o3, DTACC_SHIFT, %o3           ! %o3 = sec TSB TLB index
 551         RESV_OFFSET(%g2, %o4, %g3, sfmmu_tsb_2nd)       ! or-in bits of TSB VA
 552         LOAD_TSBTTE(%g2, %o3, %o4, %g3)         ! load sec TSB locked TTE
 553         sethi   %hi(utsb_vabase), %g3
 554         ldx     [%g3 + %lo(utsb_vabase)], %g3   ! %g3 = TLB tag for first TSB
 555         ba,pt   %xcc, 5f
 556           nop
 557 
 558 4:      sethi   %hi(utsb_vabase), %g3
 559         ldx     [%g3 + %lo(utsb_vabase)], %g3   ! %g3 = TLB tag for first TSB
 560         MAKE_TSBREG(%o2, %o1, %g3, %o3, %o4, sfmmu_tsb_1st)     ! %o2 = tsbreg
 561 
 562 5:      LOAD_TSBREG(%o2, %o3, %o4)              ! write TSB base register
 563 
 564         /*
 565          * Load the TTE for the first TSB at the appropriate location in
 566          * the TLB
 567          */
 568         sethi   %hi(utsb_dtlb_ttenum), %o2
 569         ld      [%o2 + %lo(utsb_dtlb_ttenum)], %o2
 570         sll     %o2, DTACC_SHIFT, %o2           ! %o1 = first TSB TLB index
 571         RESV_OFFSET(%o1, %g3, %o3, sfmmu_tsb_1st)       ! or-in bits of TSB VA
 572         LOAD_TSBTTE(%o1, %o2, %g3, %o4)         ! load first TSB locked TTE
 573         CPU_TSBMISS_AREA(%o2, %o3)
 574 #endif /* UTSB_PHYS */
 575 6:
 576         ldx     [%o0 + SFMMU_ISMBLKPA], %o1     ! copy members of sfmmu
 577                                                 ! we need to access from
 578         stx     %o1, [%o2 + TSBMISS_ISMBLKPA]   ! sfmmu_tsb_miss into the
 579         ldub    [%o0 + SFMMU_TTEFLAGS], %o3     ! per-CPU tsbmiss area.
 580         stx     %o0, [%o2 + TSBMISS_UHATID]
 581         stub    %o3, [%o2 + TSBMISS_UTTEFLAGS]
 582 #ifdef UTSB_PHYS
 583         ldx     [%o0 + SFMMU_SRDP], %o1
 584         ldub    [%o0 + SFMMU_RTTEFLAGS], %o4
 585         stub    %o4,  [%o2 + TSBMISS_URTTEFLAGS]
 586         stx     %o1, [%o2 +  TSBMISS_SHARED_UHATID]
 587         brz,pn  %o1, 8f                         ! check for sfmmu_srdp
 588           add   %o0, SFMMU_HMERMAP, %o1
 589         add     %o2, TSBMISS_SHMERMAP, %o2
 590         mov     SFMMU_HMERGNMAP_WORDS, %o3
 591                                                 ! set tsbmiss shmermap
 592         SET_REGION_MAP(%o1, %o2, %o3, %o4, load_shme_mmustate)
 593 
 594         ldx     [%o0 + SFMMU_SCDP], %o4         ! %o4 = sfmmu_scd
 595         CPU_TSBMISS_AREA(%o2, %o3)              ! %o2 = tsbmiss area
 596         mov     SFMMU_HMERGNMAP_WORDS, %o3
 597         brnz,pt %o4, 7f                       ! check for sfmmu_scdp else
 598           add   %o2, TSBMISS_SCDSHMERMAP, %o2 ! zero tsbmiss scd_shmermap
 599         ZERO_REGION_MAP(%o2, %o3, zero_scd_mmustate)
 600         ba 8f
 601           nop
 602 7:
 603         add     %o4, SCD_HMERMAP, %o1
 604         SET_REGION_MAP(%o1, %o2, %o3, %o4, load_scd_mmustate)
 605 #endif /* UTSB_PHYS */
 606 
 607 8:
 608         retl
 609           nop
 610         SET_SIZE(sfmmu_load_mmustate)
 611 
 612 #endif /* lint */
 613 
 614 #if defined (lint)
 615 /*
 616  * Invalidate all of the entries within the tsb, by setting the inv bit
 617  * in the tte_tag field of each tsbe.
 618  *
 619  * We take advantage of the fact TSBs are page aligned and a multiple of
 620  * PAGESIZE to use block stores.
 621  *
 622  * See TSB_LOCK_ENTRY and the miss handlers for how this works in practice
 623  * (in short, we set all bits in the upper word of the tag, and we give the
 624  * invalid bit precedence over other tag bits in both places).
 625  */
 626 /* ARGSUSED */
 627 void
 628 sfmmu_inv_tsb_fast(caddr_t tsb_base, uint_t tsb_bytes)
 629 {}
 630 
 631 #else /* lint */
 632 
 633 #define VIS_BLOCKSIZE   64
 634 
 635         ENTRY(sfmmu_inv_tsb_fast)
 636 
 637         ! Get space for aligned block of saved fp regs.
 638         save    %sp, -SA(MINFRAME + 2*VIS_BLOCKSIZE), %sp
 639 
 640         ! kpreempt_disable();
 641         ldsb    [THREAD_REG + T_PREEMPT], %l3
 642         inc     %l3
 643         stb     %l3, [THREAD_REG + T_PREEMPT]
 644 
 645         ! See if fpu was in use.  If it was, we need to save off the
 646         ! floating point registers to the stack.
 647         rd      %fprs, %l0                      ! %l0 = cached copy of fprs
 648         btst    FPRS_FEF, %l0
 649         bz,pt   %icc, 4f
 650           nop
 651 
 652         ! save in-use fpregs on stack
 653         membar  #Sync                           ! make sure tranx to fp regs
 654                                                 ! have completed
 655         add     %fp, STACK_BIAS - 65, %l1       ! get stack frame for fp regs
 656         and     %l1, -VIS_BLOCKSIZE, %l1        ! block align frame
 657         stda    %d0, [%l1]ASI_BLK_P             ! %l1 = addr of saved fp regs
 658 
 659         ! enable fp
 660 4:      membar  #StoreStore|#StoreLoad|#LoadStore
 661         wr      %g0, FPRS_FEF, %fprs
 662         wr      %g0, ASI_BLK_P, %asi
 663 
 664         ! load up FP registers with invalid TSB tag.
 665         fone    %d0                     ! ones in tag
 666         fzero   %d2                     ! zeros in TTE
 667         fone    %d4                     ! ones in tag
 668         fzero   %d6                     ! zeros in TTE
 669         fone    %d8                     ! ones in tag
 670         fzero   %d10                    ! zeros in TTE
 671         fone    %d12                    ! ones in tag
 672         fzero   %d14                    ! zeros in TTE
 673         ba,pt   %xcc, .sfmmu_inv_doblock
 674           mov   (4*VIS_BLOCKSIZE), %i4  ! we do 4 stda's each loop below
 675 
 676 .sfmmu_inv_blkstart:
 677       ! stda    %d0, [%i0+192]%asi  ! in dly slot of branch that got us here
 678         stda    %d0, [%i0+128]%asi
 679         stda    %d0, [%i0+64]%asi
 680         stda    %d0, [%i0]%asi
 681 
 682         add     %i0, %i4, %i0
 683         sub     %i1, %i4, %i1
 684 
 685 .sfmmu_inv_doblock:
 686         cmp     %i1, (4*VIS_BLOCKSIZE)  ! check for completion
 687         bgeu,a  %icc, .sfmmu_inv_blkstart
 688           stda  %d0, [%i0+192]%asi
 689 
 690 .sfmmu_inv_finish:
 691         membar  #Sync
 692         btst    FPRS_FEF, %l0           ! saved from above
 693         bz,a    .sfmmu_inv_finished
 694           wr    %l0, 0, %fprs           ! restore fprs
 695 
 696         ! restore fpregs from stack
 697         ldda    [%l1]ASI_BLK_P, %d0
 698         membar  #Sync
 699         wr      %l0, 0, %fprs           ! restore fprs
 700 
 701 .sfmmu_inv_finished:
 702         ! kpreempt_enable();
 703         ldsb    [THREAD_REG + T_PREEMPT], %l3
 704         dec     %l3
 705         stb     %l3, [THREAD_REG + T_PREEMPT]
 706         ret
 707           restore
 708         SET_SIZE(sfmmu_inv_tsb_fast)
 709 
 710 #endif /* lint */
 711 
 712 #if defined(lint)
 713 
 714 /*
 715  * Prefetch "struct tsbe" while walking TSBs.
 716  * prefetch 7 cache lines ahead of where we are at now.
 717  * #n_reads is being used since #one_read only applies to
 718  * floating point reads, and we are not doing floating point
 719  * reads.  However, this has the negative side effect of polluting
 720  * the ecache.
 721  * The 448 comes from (7 * 64) which is how far ahead of our current
 722  * address, we want to prefetch.
 723  */
 724 /*ARGSUSED*/
 725 void
 726 prefetch_tsbe_read(struct tsbe *tsbep)
 727 {}
 728 
 729 /* Prefetch the tsbe that we are about to write */
 730 /*ARGSUSED*/
 731 void
 732 prefetch_tsbe_write(struct tsbe *tsbep)
 733 {}
 734 
 735 #else /* lint */
 736 
 737         ENTRY(prefetch_tsbe_read)
 738         retl
 739           prefetch      [%o0+448], #n_reads
 740         SET_SIZE(prefetch_tsbe_read)
 741 
 742         ENTRY(prefetch_tsbe_write)
 743         retl
 744           prefetch      [%o0], #n_writes
 745         SET_SIZE(prefetch_tsbe_write)
 746 #endif /* lint */
 747