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/* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#if !defined(lint) 28#include <sys/asm_linkage.h> 29#include "assym.h" 30#endif 31 32#include <sys/sun4asi.h> 33#include <sys/machparam.h> 34#include <vm/hat_sfmmu.h> 35 36/* 37 * This file contains a kmdb-support function which retrieves the TTE for a 38 * given VA/context pair, and returns it to the caller if the TTE is valid. 39 * The code here is essentially an assembly implementation of the unix-tte 40 * word used to allow OBP to do the same thing. 41 * 42 * Depending on the invocation context, the translator may be invoked either 43 * as a normal function (kdi_vatotte) or as a trap handler fragment 44 * (kdi_trap_vatotte). 45 */ 46 47/* 48 * uint64_t 49 * kdi_hme_hash_function(sfmmu_t *sfmmup, uintptr_t va, uint_t hmeshift) 50 * { 51 * uintptr_t hash = (uintptr_t)sfmmup ^ (va >> hmeshift); 52 * 53 * if (sfmmup == KHATID) { 54 * return (khme_hash_pa + (hash & KHMEHASH_SZ) * 55 * sizeof (struct hmehash_bucket)); 56 * } else { 57 * return (uhme_hash_pa + (hash & UHMEHASH_SZ) * 58 * sizeof (struct hmehash_bucket)); 59 * } 60 * } 61 */ 62 63/* 64 * Parameters: %g1: VA, %g2: sfmmup, %g4: hmeshift 65 * Scratch: %g4, %g5, %g6 available 66 * Return: Hash value in %g4 67 */ 68 69#define KDI_HME_HASH_FUNCTION \ 70 srlx %g1, %g4, %g4; /* va >> hmeshift */ \ 71 xor %g4, %g2, %g4; /* hash in g4 */ \ 72 set KHATID, %g5; \ 73 ldx [%g5], %g5; \ 74 cmp %g2, %g5; \ 75 be %xcc, is_khat; \ 76 nop; \ 77 \ 78 /* sfmmup != KHATID */ \ 79 set UHMEHASH_SZ, %g5; \ 80 ld [%g5], %g5; \ 81 and %g4, %g5, %g4; \ 82 mulx %g4, HMEBUCK_SIZE, %g4; /* g4 = off from hash_pa */ \ 83 set uhme_hash_pa, %g5; \ 84 ldx [%g5], %g5; \ 85 ba hash_done; \ 86 add %g4, %g5, %g4; \ 87 \ 88is_khat: /* sfmmup == KHATID */ \ 89 set KHMEHASH_SZ, %g5; \ 90 ld [%g5], %g5; \ 91 and %g4, %g5, %g4; \ 92 mulx %g4, HMEBUCK_SIZE, %g4; /* g4 = off from hash_pa */ \ 93 set khme_hash_pa, %g5; \ 94 ldx [%g5], %g5; \ 95 add %g4, %g5, %g4; \ 96 \ 97hash_done: 98 99/* 100 * uint64_t 101 * kdi_hme_hash_tag(uint64_t rehash, uintptr_t va) 102 * { 103 * uint_t hmeshift = HME_HASH_SHIFT(rehash); 104 * uint64_t bspage = HME_HASH_BSPAGE(va, hmeshift); 105 * return (rehash | (bspage << HTAG_BSPAGE_SHIFT)); 106 * } 107 */ 108 109/* 110 * Parameters: %g1: VA, %g3: rehash 111 * Scratch: %g5, %g6 available 112 * Return: hmeblk tag in %g5 113 */ 114 115#define KDI_HME_HASH_TAG \ 116 cmp %g3, TTE8K; \ 117 be,a %xcc, bspage; \ 118 mov HBLK_RANGE_SHIFT, %g5; \ 119 mulx %g3, 3, %g5; \ 120 add %g5, MMU_PAGESHIFT, %g5; \ 121 \ 122bspage: /* TTE_PAGE_SHIFT in %g5 */ \ 123 srlx %g1, %g5, %g6; \ 124 sub %g5, MMU_PAGESHIFT, %g5; \ 125 sllx %g6, %g5, %g5; \ 126 \ 127 /* BSPAGE in %g5 */ \ 128 sllx %g5, HTAG_BSPAGE_SHIFT, %g5; \ 129 sllx %g3, HTAG_REHASH_SHIFT, %g6; \ 130 or %g6, SFMMU_INVALID_SHMERID, %g6; \ 131 or %g5, %g6, %g5 132 133/* 134 * uint64_t 135 * kdi_hme_hash_table_search(sfmmu_t *sfmmup, uint64_t hmebpa, uint64_t hblktag) 136 * { 137 * struct hme_blk *hblkp; 138 * uint64_t blkpap = hmebpa + HMEBP_HBLK; 139 * uint64_t blkpa; 140 * 141 * while ((blkpa = lddphys(blkpap)) != NULL) { 142 * if (lddphys(blkpa + HMEBLK_TAG) == hblktag) { 143 * if ((sfmmu_t *)lddphys(blkpa + HMEBLK_TAG + 8) == 144 * sfmmup) 145 * return (blkpa); 146 * } 147 * 148 * blkpap = blkpa + HMEBLK_NEXTPA; 149 * } 150 * 151 * return (NULL); 152 * } 153 */ 154 155/* 156 * Parameters: %g2: sfmmup, %g4: hmebp PA, %g5: hmeblk tag 157 * Scratch: %g4, %g5, %g6 available 158 * Return: hmeblk PA in %g4 159 */ 160 161#define KDI_HME_HASH_TABLE_SEARCH \ 162 add %g4, HMEBUCK_NEXTPA, %g4; /* %g4 is hmebucket PA */ \ 163search_loop: \ 164 ldxa [%g4]ASI_MEM, %g4; \ 165 cmp %g4, HMEBLK_ENDPA; \ 166 be,pn %xcc, search_done; \ 167 nop; \ 168 \ 169 add %g4, HMEBLK_TAG, %g4; /* %g4 is now hmeblk PA */ \ 170 ldxa [%g4]ASI_MEM, %g6; \ 171 sub %g4, HMEBLK_TAG, %g4; \ 172 cmp %g5, %g6; \ 173 bne,a %xcc, search_loop; \ 174 add %g4, HMEBLK_NEXTPA, %g4; \ 175 \ 176 /* Found a match. Is it in the right address space? */ \ 177 add %g4, (HMEBLK_TAG + 8), %g4; \ 178 ldxa [%g4]ASI_MEM, %g6; \ 179 sub %g4, (HMEBLK_TAG + 8), %g4; \ 180 cmp %g6, %g2; \ 181 bne,a %xcc, search_loop; \ 182 add %g4, HMEBLK_NEXTPA, %g4; \ 183 \ 184search_done: 185 186/* 187 * uint64_t 188 * kdi_hblk_to_ttep(uint64_t hmeblkpa, uintptr_t va) 189 * { 190 * size_t ttesz = ldphys(hmeblkpa + HMEBLK_MISC) & HBLK_SZMASK; 191 * uint_t idx; 192 * 193 * if (ttesz == TTE8K) 194 * idx = (va >> MMU_PAGESHIFT) & (NHMENTS - 1); 195 * else 196 * idx = 0; 197 * 198 * return (hmeblkpa + (idx * sizeof (struct sf_hment)) + 199 * HMEBLK_HME + SFHME_TTE); 200 * } 201 */ 202 203/* 204 * Parameters: %g1: VA, %g4: hmeblk PA 205 * Scratch: %g1, %g2, %g3, %g4, %g5, %g6 available 206 * Return: TTE PA in %g2 207 */ 208 209#define KDI_HBLK_TO_TTEP \ 210 add %g4, HMEBLK_MISC, %g3; \ 211 lda [%g3]ASI_MEM, %g3; \ 212 and %g3, HBLK_SZMASK, %g3; /* ttesz in %g3 */ \ 213 \ 214 cmp %g3, TTE8K; \ 215 bne,a ttep_calc; \ 216 clr %g1; \ 217 srlx %g1, MMU_PAGESHIFT, %g1; \ 218 and %g1, NHMENTS - 1, %g1; \ 219 \ 220ttep_calc: /* idx in %g1 */ \ 221 mulx %g1, SFHME_SIZE, %g2; \ 222 add %g2, %g4, %g2; \ 223 add %g2, (HMEBLK_HME1 + SFHME_TTE), %g2; 224 225/* 226 * uint64_t 227 * kdi_vatotte(uintptr_t va, int cnum) 228 * { 229 * sfmmu_t *sfmmup = ksfmmup; 230 * uint64_t hmebpa, hmetag, hmeblkpa; 231 * int i; 232 * 233 * for (i = 1; i < DEFAULT_MAX_HASHCNT + 1; i++) { 234 * hmebpa = kdi_c_hme_hash_function(sfmmup, va, HME_HASH_SHIFT(i)); 235 * hmetag = kdi_c_hme_hash_tag(i, va); 236 * hmeblkpa = kdi_c_hme_hash_table_search(sfmmup, hmebpa, hmetag); 237 * 238 * if (hmeblkpa != NULL) { 239 * uint64_t tte = lddphys(kdi_c_hblk_to_ttep(hmeblkpa, 240 * va)); 241 * 242 * if ((int64_t)tte < 0) 243 * return (tte); 244 * else 245 * return (0); 246 * } 247 * } 248 * 249 * return (0); 250 * } 251 */ 252 253#if defined(lint) 254/*ARGSUSED*/ 255int 256kdi_vatotte(uintptr_t va, int cnum, tte_t *ttep) 257{ 258 return (0); 259} 260 261void 262kdi_trap_vatotte(void) 263{ 264} 265 266#else 267 268 /* 269 * Invocation in normal context as a VA-to-TTE translator 270 * for kernel context only. This routine returns 0 on 271 * success and -1 on error. 272 * 273 * %o0 = VA, input register 274 * %o1 = KCONTEXT 275 * %o2 = ttep, output register 276 */ 277 ENTRY_NP(kdi_vatotte) 278 mov %o0, %g1 /* VA in %g1 */ 279 mov %o1, %g2 /* cnum in %g2 */ 280 281 set kdi_trap_vatotte, %g3 282 jmpl %g3, %g7 /* => %g1: TTE or 0 */ 283 add %g7, 8, %g7 284 285 brz %g1, 1f 286 nop 287 288 /* Got a valid TTE */ 289 stx %g1, [%o2] 290 retl 291 clr %o0 292 293 /* Failed translation */ 2941: retl 295 mov -1, %o0 296 SET_SIZE(kdi_vatotte) 297 298 /* 299 * %g1 = vaddr passed in, tte or 0 (error) when return 300 * %g2 = KCONTEXT 301 * %g7 = return address 302 */ 303 ENTRY_NP(kdi_trap_vatotte) 304 305 cmp %g2, KCONTEXT /* make sure called in kernel ctx */ 306 bne,a,pn %icc, 6f 307 clr %g1 308 309 sethi %hi(ksfmmup), %g2 310 ldx [%g2 + %lo(ksfmmup)], %g2 311 312 mov 1, %g3 /* VA %g1, ksfmmup %g2, idx %g3 */ 313 mov HBLK_RANGE_SHIFT, %g4 314 ba 3f 315 nop 316 3171: mulx %g3, 3, %g4 /* 3: see TTE_BSZS_SHIFT */ 318 add %g4, MMU_PAGESHIFT, %g4 319 3203: KDI_HME_HASH_FUNCTION /* %g1, %g2, %g4 => hash in %g4 */ 321 KDI_HME_HASH_TAG /* %g1, %g3 => tag in %g5 */ 322 KDI_HME_HASH_TABLE_SEARCH /* %g2, %g4, %g5 => hmeblk PA in %g4 */ 323 324 brz %g4, 5f 325 nop 326 327 KDI_HBLK_TO_TTEP /* %g1, %g4 => TTE PA in %g2 */ 328 ldxa [%g2]ASI_MEM, %g1 329 brgez,a %g1, 4f 330 clr %g1 3314: 332 /* 333 * If soft execute bit is set, make sure HW execute permission 334 * is also set. But, clear soft execute bit before giving tte to 335 * the caller. 336 */ 337 TTE_CHK_SOFTEXEC_ML(%g1) 338 bz,pt %icc, 6f 339 andcc %g1, TTE_EXECPRM_INT, %g0 340 bnz,pt %icc, 7f 341 nop 342 TTE_SET_EXEC_ML(%g1, %g2, %g4, kdi_trap_vatotte) 3437: 344 TTE_CLR_SOFTEXEC_ML(%g1) 345 ba,a 6f 346 3475: add %g3, 1, %g3 348 set mmu_hashcnt, %g4 349 lduw [%g4], %g4 350 cmp %g3, %g4 351 ble 1b 352 nop 353 354 clr %g1 355 3566: jmp %g7 357 nop 358 SET_SIZE(kdi_trap_vatotte) 359 360#endif /* lint */ 361