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