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 /*
  27  * SFMMU primitives.  These primitives should only be used by sfmmu
  28  * routines.
  29  */
  30 
  31 #include "assym.h"
  32 
  33 #include <sys/asm_linkage.h>
  34 #include <sys/machtrap.h>
  35 #include <sys/machasi.h>
  36 #include <sys/sun4asi.h>
  37 #include <sys/pte.h>
  38 #include <sys/mmu.h>
  39 #include <vm/hat_sfmmu.h>
  40 #include <vm/seg_spt.h>
  41 #include <sys/machparam.h>
  42 #include <sys/privregs.h>
  43 #include <sys/scb.h>
  44 #include <sys/intreg.h>
  45 #include <sys/machthread.h>
  46 #include <sys/clock.h>
  47 #include <sys/trapstat.h>
  48 
  49 /*
  50  * sfmmu related subroutines
  51  */
  52 
  53 /*
  54  * Invalidate either the context of a specific victim or any process
  55  * currently running on this CPU. 
  56  *
  57  * %g1 = sfmmup whose ctx is being stolen (victim)
  58  *       when called from sfmmu_wrap_around, %g1 == INVALID_CONTEXT.
  59  * Note %g1 is the only input argument used by this xcall handler.
  60  */
  61 
  62         ENTRY(sfmmu_raise_tsb_exception)
  63         !
  64         ! if (victim == INVALID_CONTEXT) {
  65         !       if (sec-ctx > INVALID_CONTEXT)
  66         !               write INVALID_CONTEXT to sec-ctx
  67         !       if (pri-ctx > INVALID_CONTEXT) 
  68         !               write INVALID_CONTEXT to pri-ctx
  69         !
  70         ! } else if (current CPU tsbmiss->usfmmup != victim sfmmup) {
  71         !       return
  72         ! } else {
  73         !       if (sec-ctx > INVALID_CONTEXT)
  74         !               write INVALID_CONTEXT to sec-ctx
  75         !       
  76         !       if (pri-ctx > INVALID_CONTEXT)
  77         !               write INVALID_CONTEXT to pri-ctx
  78         ! }
  79         !
  80 
  81         sethi   %hi(ksfmmup), %g3
  82         ldx     [%g3 + %lo(ksfmmup)], %g3
  83         cmp     %g1, %g3
  84         be,a,pn %xcc, ptl1_panic        /* can't invalidate kernel ctx */
  85           mov   PTL1_BAD_RAISE_TSBEXCP, %g1
  86 
  87         set     INVALID_CONTEXT, %g2
  88         
  89         cmp     %g1, INVALID_CONTEXT
  90         bne,pt  %xcc, 1f                        /* called from wrap_around? */
  91           mov   MMU_SCONTEXT, %g3
  92 
  93         ldxa    [%g3]ASI_MMU_CTX, %g5           /* %g5 = sec-ctx */
  94         cmp     %g5, INVALID_CONTEXT            /* kernel  or invalid ctx ? */
  95         ble,pn  %xcc, 0f                        /* yes, no need to change */
  96           mov   MMU_PCONTEXT, %g7
  97         
  98         stxa    %g2, [%g3]ASI_MMU_CTX           /* set invalid ctx */
  99         membar  #Sync
 100 
 101 0:      
 102         ldxa    [%g7]ASI_MMU_CTX, %g5           /* %g5 = pri-ctx */
 103         cmp     %g5, INVALID_CONTEXT            /* kernel or invalid ctx? */
 104         ble,pn  %xcc, 6f                        /* yes, no need to change */
 105           nop
 106 
 107         stxa    %g2, [%g7]ASI_MMU_CTX           /* set pri-ctx to invalid  */
 108         membar  #Sync
 109 
 110 6:      /* flushall tlb */
 111         mov     %o0, %g3
 112         mov     %o1, %g4
 113         mov     %o2, %g6 
 114         mov     %o5, %g7
 115 
 116         mov     %g0, %o0        ! XXX no cpu list yet
 117         mov     %g0, %o1        ! XXX no cpu list yet
 118         mov     MAP_ITLB | MAP_DTLB, %o2
 119         mov     MMU_DEMAP_ALL, %o5
 120         ta      FAST_TRAP
 121         brz,pt  %o0, 5f
 122           nop
 123         ba ptl1_panic           /* bad HV call */
 124           mov   PTL1_BAD_RAISE_TSBEXCP, %g1
 125 5:      
 126         mov     %g3, %o0
 127         mov     %g4, %o1
 128         mov     %g6, %o2
 129         mov     %g7, %o5
 130         
 131         ba      3f
 132           nop
 133 1:
 134         /*
 135          * %g1 = sfmmup
 136          * %g2 = INVALID_CONTEXT
 137          * %g3 = MMU_SCONTEXT
 138          */
 139         CPU_TSBMISS_AREA(%g5, %g6)              /* load cpu tsbmiss area */
 140         ldx     [%g5 + TSBMISS_UHATID], %g5     /* load usfmmup */
 141 
 142         cmp     %g5, %g1                        /* is it the victim? */
 143         bne,pt  %xcc, 2f                        /* is our sec-ctx a victim? */
 144           nop
 145 
 146         ldxa    [%g3]ASI_MMU_CTX, %g5           /* %g5 = sec-ctx */
 147         cmp     %g5, INVALID_CONTEXT            /* kernel  or invalid ctx ? */
 148         ble,pn  %xcc, 0f                        /* yes, no need to change */
 149           mov   MMU_PCONTEXT, %g7
 150 
 151         stxa    %g2, [%g3]ASI_MMU_CTX           /* set sec-ctx to invalid */
 152         membar  #Sync
 153 
 154 0:
 155         ldxa    [%g7]ASI_MMU_CTX, %g4           /* %g4 = pri-ctx */
 156         cmp     %g4, INVALID_CONTEXT            /* is pri-ctx the victim? */
 157         ble     %icc, 3f                        /* no need to change pri-ctx */
 158           nop
 159         stxa    %g2, [%g7]ASI_MMU_CTX           /* set pri-ctx to invalid  */
 160         membar  #Sync
 161 
 162 3:
 163         /* TSB program must be cleared - walkers do not check a context. */
 164         mov     %o0, %g3
 165         mov     %o1, %g4
 166         mov     %o5, %g7
 167         clr     %o0
 168         clr     %o1
 169         mov     MMU_TSB_CTXNON0, %o5
 170         ta      FAST_TRAP
 171         brnz,a,pn %o0, ptl1_panic
 172           mov   PTL1_BAD_HCALL, %g1
 173         mov     %g3, %o0
 174         mov     %g4, %o1
 175         mov     %g7, %o5
 176 2:
 177         retry
 178         SET_SIZE(sfmmu_raise_tsb_exception)
 179 
 180         ENTRY_NP(sfmmu_getctx_pri)
 181         set     MMU_PCONTEXT, %o0
 182         retl
 183         ldxa    [%o0]ASI_MMU_CTX, %o0
 184         SET_SIZE(sfmmu_getctx_pri)
 185 
 186         ENTRY_NP(sfmmu_getctx_sec)
 187         set     MMU_SCONTEXT, %o0
 188         retl
 189         ldxa    [%o0]ASI_MMU_CTX, %o0
 190         SET_SIZE(sfmmu_getctx_sec)
 191 
 192         /*
 193          * Set the secondary context register for this process.
 194          * %o0 = context number
 195          */
 196         ENTRY_NP(sfmmu_setctx_sec)
 197         /*
 198          * From resume we call sfmmu_setctx_sec with interrupts disabled.
 199          * But we can also get called from C with interrupts enabled. So,
 200          * we need to check first.
 201          */
 202 
 203         /* If interrupts are not disabled, then disable them */
 204         rdpr    %pstate, %g1
 205         btst    PSTATE_IE, %g1
 206         bnz,a,pt %icc, 1f
 207         wrpr    %g1, PSTATE_IE, %pstate         /* disable interrupts */
 208 1:
 209         mov     MMU_SCONTEXT, %o1
 210         stxa    %o0, [%o1]ASI_MMU_CTX           /* set 2nd context reg. */
 211         membar  #Sync
 212         /*
 213          * if the routine is entered with intr enabled, then enable intr now.
 214          * otherwise, keep intr disabled, return without enabing intr.
 215          * %g1 - old intr state
 216          */
 217         btst    PSTATE_IE, %g1
 218         bnz,a,pt %icc, 2f
 219         wrpr    %g0, %g1, %pstate               /* enable interrupts */
 220 2:      retl
 221         nop
 222         SET_SIZE(sfmmu_setctx_sec)
 223 
 224         /*
 225          * set ktsb_phys to 1 if the processor supports ASI_QUAD_LDD_PHYS.
 226          * returns the detection value in %o0.
 227          */
 228         ENTRY_NP(sfmmu_setup_4lp)
 229         set     ktsb_phys, %o2
 230         mov     1, %o1
 231         st      %o1, [%o2]
 232         retl
 233         mov     %o1, %o0
 234         SET_SIZE(sfmmu_setup_4lp)
 235 
 236         /*
 237          * Called to load MMU registers and tsbmiss area
 238          * for the active process.  This function should
 239          * only be called from TL=0.
 240          *
 241          * %o0 - hat pointer
 242          */
 243         ENTRY_NP(sfmmu_load_mmustate)
 244 
 245 #ifdef DEBUG
 246         PANIC_IF_INTR_ENABLED_PSTR(msfmmu_ei_l1, %g1)
 247 #endif /* DEBUG */
 248 
 249         sethi   %hi(ksfmmup), %o3
 250         ldx     [%o3 + %lo(ksfmmup)], %o3
 251         cmp     %o3, %o0
 252         be,pn   %xcc, 7f                        ! if kernel as, do nothing
 253           nop
 254         
 255         set     MMU_SCONTEXT, %o3
 256         ldxa    [%o3]ASI_MMU_CTX, %o5
 257         
 258         cmp     %o5, INVALID_CONTEXT            ! ctx is invalid?
 259         bne,pt  %icc, 1f
 260           nop
 261 
 262         CPU_TSBMISS_AREA(%o2, %o3)              ! %o2 = tsbmiss area
 263         stx     %o0, [%o2 + TSBMISS_UHATID]
 264         stx     %g0, [%o2 +  TSBMISS_SHARED_UHATID]
 265 #ifdef DEBUG
 266         /* check if hypervisor/hardware should handle user TSB */
 267         sethi   %hi(hv_use_non0_tsb), %o2
 268         ld      [%o2 + %lo(hv_use_non0_tsb)], %o2
 269         brz,pn  %o2, 0f
 270           nop
 271 #endif /* DEBUG */
 272         clr     %o0                             ! ntsb = 0 for invalid ctx
 273         clr     %o1                             ! HV_TSB_INFO_PA = 0 if inv ctx
 274         mov     MMU_TSB_CTXNON0, %o5
 275         ta      FAST_TRAP                       ! set TSB info for user process
 276         brnz,a,pn %o0, panic_bad_hcall
 277           mov   MMU_TSB_CTXNON0, %o1
 278 0:
 279         retl
 280           nop
 281 1:              
 282         /*
 283          * We need to set up the TSB base register, tsbmiss
 284          * area, and pass the TSB information into the hypervisor
 285          */
 286         ldx     [%o0 + SFMMU_TSB], %o1          ! %o1 = first tsbinfo
 287         ldx     [%o1 + TSBINFO_NEXTPTR], %g2    ! %g2 = second tsbinfo
 288 
 289         /* create/set first UTSBREG */
 290         MAKE_UTSBREG(%o1, %o2, %o3)             ! %o2 = user tsbreg
 291         SET_UTSBREG(SCRATCHPAD_UTSBREG1, %o2, %o3)
 292 
 293         brz,pt  %g2, 2f
 294           mov   -1, %o2                         ! use -1 if no second TSB
 295 
 296         /* make 2nd UTSBREG */
 297         MAKE_UTSBREG(%g2, %o2, %o3)             ! %o2 = user tsbreg
 298 2:
 299         SET_UTSBREG(SCRATCHPAD_UTSBREG2, %o2, %o3)
 300 
 301         /* make 3rd and 4th TSB */
 302         CPU_TSBMISS_AREA(%o4, %o3)              ! %o4 = tsbmiss area
 303 
 304         ldx     [%o0 + SFMMU_SCDP], %g2         ! %g2 = sfmmu_scd
 305         brz,pt  %g2, 3f
 306           mov   -1, %o2                         ! use -1 if no third TSB
 307 
 308         ldx     [%g2 + SCD_SFMMUP], %g3         ! %g3 = scdp->scd_sfmmup
 309         ldx     [%g3 + SFMMU_TSB], %o1          ! %o1 = first scd tsbinfo
 310         brz,pn %o1, 9f
 311           nop                                   ! panic if no third TSB
 312 
 313         /* make 3rd UTSBREG */
 314         MAKE_UTSBREG(%o1, %o2, %o3)             ! %o2 = user tsbreg
 315 3:
 316         SET_UTSBREG_SHCTX(%o4, TSBMISS_TSBSCDPTR, %o2)
 317 
 318         brz,pt  %g2, 4f
 319           mov   -1, %o2                         ! use -1 if no 3rd or 4th TSB
 320 
 321         brz,pt  %o1, 4f
 322           mov   -1, %o2                         ! use -1 if no 3rd or 4th TSB
 323         ldx     [%o1 + TSBINFO_NEXTPTR], %g2    ! %g2 = second scd tsbinfo
 324         brz,pt  %g2, 4f
 325           mov   -1, %o2                         ! use -1 if no 4th TSB
 326 
 327         /* make 4th UTSBREG */
 328         MAKE_UTSBREG(%g2, %o2, %o3)             ! %o2 = user tsbreg
 329 4:
 330         SET_UTSBREG_SHCTX(%o4, TSBMISS_TSBSCDPTR4M, %o2)
 331 
 332 #ifdef DEBUG
 333         /* check if hypervisor/hardware should handle user TSB */
 334         sethi   %hi(hv_use_non0_tsb), %o2
 335         ld      [%o2 + %lo(hv_use_non0_tsb)], %o2
 336         brz,pn  %o2, 6f
 337           nop
 338 #endif /* DEBUG */
 339         CPU_ADDR(%o2, %o4)      ! load CPU struct addr to %o2 using %o4
 340         ldub    [%o2 + CPU_TSTAT_FLAGS], %o1    ! load cpu_tstat_flag to %o1
 341 
 342         mov     %o0, %o3                        ! preserve %o0
 343         btst    TSTAT_TLB_STATS, %o1
 344         bnz,a,pn %icc, 5f                       ! ntsb = 0 if TLB stats enabled
 345           clr   %o0
 346         
 347         ldx     [%o3 + SFMMU_HVBLOCK + HV_TSB_INFO_CNT], %o0
 348 5:
 349         ldx     [%o3 + SFMMU_HVBLOCK + HV_TSB_INFO_PA], %o1     
 350         mov     MMU_TSB_CTXNON0, %o5
 351         ta      FAST_TRAP                       ! set TSB info for user process
 352         brnz,a,pn %o0, panic_bad_hcall
 353         mov     MMU_TSB_CTXNON0, %o1
 354         mov     %o3, %o0                        ! restore %o0
 355 6:
 356         ldx     [%o0 + SFMMU_ISMBLKPA], %o1     ! copy members of sfmmu
 357         CPU_TSBMISS_AREA(%o2, %o3)              ! %o2 = tsbmiss area
 358         stx     %o1, [%o2 + TSBMISS_ISMBLKPA]   ! sfmmu_tsb_miss into the
 359         ldub    [%o0 + SFMMU_TTEFLAGS], %o3     ! per-CPU tsbmiss area.
 360         ldub    [%o0 + SFMMU_RTTEFLAGS], %o4
 361         ldx     [%o0 + SFMMU_SRDP], %o1
 362         stx     %o0, [%o2 + TSBMISS_UHATID]
 363         stub    %o3, [%o2 + TSBMISS_UTTEFLAGS]
 364         stub    %o4,  [%o2 + TSBMISS_URTTEFLAGS]
 365         stx     %o1, [%o2 +  TSBMISS_SHARED_UHATID]
 366         brz,pn  %o1, 7f                         ! check for sfmmu_srdp
 367           add   %o0, SFMMU_HMERMAP, %o1
 368         add     %o2, TSBMISS_SHMERMAP, %o2
 369         mov     SFMMU_HMERGNMAP_WORDS, %o3
 370                                                 ! set tsbmiss shmermap
 371         SET_REGION_MAP(%o1, %o2, %o3, %o4, load_shme_mmustate)
 372 
 373         ldx     [%o0 + SFMMU_SCDP], %o4         ! %o4 = sfmmu_scd
 374         CPU_TSBMISS_AREA(%o2, %o3)              ! %o2 = tsbmiss area
 375         mov     SFMMU_HMERGNMAP_WORDS, %o3
 376         brnz,pt %o4, 8f                         ! check for sfmmu_scdp else
 377           add   %o2, TSBMISS_SCDSHMERMAP, %o2   ! zero tsbmiss scd_shmermap
 378         ZERO_REGION_MAP(%o2, %o3, zero_scd_mmustate)
 379 7:
 380         retl
 381         nop
 382 8:                                              ! set tsbmiss scd_shmermap
 383         add     %o4, SCD_HMERMAP, %o1
 384         SET_REGION_MAP(%o1, %o2, %o3, %o4, load_scd_mmustate)
 385         retl
 386           nop
 387 9:
 388         sethi   %hi(panicstr), %g1              ! panic if no 3rd TSB  
 389         ldx     [%g1 + %lo(panicstr)], %g1                             
 390         tst     %g1
 391                                                            
 392         bnz,pn  %xcc, 7b                                            
 393           nop                                                            
 394                                                                         
 395         sethi   %hi(sfmmu_panic10), %o0                                 
 396         call    panic                                                 
 397           or      %o0, %lo(sfmmu_panic10), %o0                         
 398 
 399         SET_SIZE(sfmmu_load_mmustate)
 400         
 401         ENTRY(prefetch_tsbe_read)
 402         retl
 403         nop
 404         SET_SIZE(prefetch_tsbe_read)
 405 
 406         ENTRY(prefetch_tsbe_write)
 407         retl
 408         nop
 409         SET_SIZE(prefetch_tsbe_write)