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 brz %g4, search_done; \ 166 nop; \ 167 \ 168 add %g4, HMEBLK_TAG, %g4; /* %g4 is now hmeblk PA */ \ 169 ldxa [%g4]ASI_MEM, %g6; \ 170 sub %g4, HMEBLK_TAG, %g4; \ 171 cmp %g5, %g6; \ 172 bne,a %xcc, search_loop; \ 173 add %g4, HMEBLK_NEXTPA, %g4; \ 174 \ 175 /* Found a match. Is it in the right address space? */ \ 176 add %g4, (HMEBLK_TAG + 8), %g4; \ 177 ldxa [%g4]ASI_MEM, %g6; \ 178 sub %g4, (HMEBLK_TAG + 8), %g4; \ 179 cmp %g6, %g2; \ 180 bne,a %xcc, search_loop; \ 181 add %g4, HMEBLK_NEXTPA, %g4; \ 182 \ 183search_done: 184 185/* 186 * uint64_t 187 * kdi_hblk_to_ttep(uint64_t hmeblkpa, uintptr_t va) 188 * { 189 * size_t ttesz = ldphys(hmeblkpa + HMEBLK_MISC) & HBLK_SZMASK; 190 * uint_t idx; 191 * 192 * if (ttesz == TTE8K) 193 * idx = (va >> MMU_PAGESHIFT) & (NHMENTS - 1); 194 * else 195 * idx = 0; 196 * 197 * return (hmeblkpa + (idx * sizeof (struct sf_hment)) + 198 * HMEBLK_HME + SFHME_TTE); 199 * } 200 */ 201 202/* 203 * Parameters: %g1: VA, %g4: hmeblk PA 204 * Scratch: %g1, %g2, %g3, %g4, %g5, %g6 available 205 * Return: TTE PA in %g2 206 */ 207 208#define KDI_HBLK_TO_TTEP \ 209 add %g4, HMEBLK_MISC, %g3; \ 210 lda [%g3]ASI_MEM, %g3; \ 211 and %g3, HBLK_SZMASK, %g3; /* ttesz in %g3 */ \ 212 \ 213 cmp %g3, TTE8K; \ 214 bne,a ttep_calc; \ 215 clr %g1; \ 216 srlx %g1, MMU_PAGESHIFT, %g1; \ 217 and %g1, NHMENTS - 1, %g1; \ 218 \ 219ttep_calc: /* idx in %g1 */ \ 220 mulx %g1, SFHME_SIZE, %g2; \ 221 add %g2, %g4, %g2; \ 222 add %g2, (HMEBLK_HME1 + SFHME_TTE), %g2; 223 224/* 225 * uint64_t 226 * kdi_vatotte(uintptr_t va, int cnum) 227 * { 228 * sfmmu_t *sfmmup = ksfmmup; 229 * uint64_t hmebpa, hmetag, hmeblkpa; 230 * int i; 231 * 232 * for (i = 1; i < DEFAULT_MAX_HASHCNT + 1; i++) { 233 * hmebpa = kdi_c_hme_hash_function(sfmmup, va, HME_HASH_SHIFT(i)); 234 * hmetag = kdi_c_hme_hash_tag(i, va); 235 * hmeblkpa = kdi_c_hme_hash_table_search(sfmmup, hmebpa, hmetag); 236 * 237 * if (hmeblkpa != NULL) { 238 * uint64_t tte = lddphys(kdi_c_hblk_to_ttep(hmeblkpa, 239 * va)); 240 * 241 * if ((int64_t)tte < 0) 242 * return (tte); 243 * else 244 * return (0); 245 * } 246 * } 247 * 248 * return (0); 249 * } 250 */ 251 252#if defined(lint) 253/*ARGSUSED*/ 254int 255kdi_vatotte(uintptr_t va, int cnum, tte_t *ttep) 256{ 257 return (0); 258} 259 260void 261kdi_trap_vatotte(void) 262{ 263} 264 265#else 266 267 /* 268 * Invocation in normal context as a VA-to-TTE translator 269 * for kernel context only. This routine returns 0 on 270 * success and -1 on error. 271 * 272 * %o0 = VA, input register 273 * %o1 = KCONTEXT 274 * %o2 = ttep, output register 275 */ 276 ENTRY_NP(kdi_vatotte) 277 mov %o0, %g1 /* VA in %g1 */ 278 mov %o1, %g2 /* cnum in %g2 */ 279 280 set kdi_trap_vatotte, %g3 281 jmpl %g3, %g7 /* => %g1: TTE or 0 */ 282 add %g7, 8, %g7 283 284 brz %g1, 1f 285 nop 286 287 /* Got a valid TTE */ 288 stx %g1, [%o2] 289 retl 290 clr %o0 291 292 /* Failed translation */ 2931: retl 294 mov -1, %o0 295 SET_SIZE(kdi_vatotte) 296 297 /* 298 * %g1 = vaddr passed in, tte or 0 (error) when return 299 * %g2 = KCONTEXT 300 * %g7 = return address 301 */ 302 ENTRY_NP(kdi_trap_vatotte) 303 304 cmp %g2, KCONTEXT /* make sure called in kernel ctx */ 305 bne,a,pn %icc, 6f 306 clr %g1 307 308 sethi %hi(ksfmmup), %g2 309 ldx [%g2 + %lo(ksfmmup)], %g2 310 311 mov 1, %g3 /* VA %g1, ksfmmup %g2, idx %g3 */ 312 mov HBLK_RANGE_SHIFT, %g4 313 ba 3f 314 nop 315 3161: mulx %g3, 3, %g4 /* 3: see TTE_BSZS_SHIFT */ 317 add %g4, MMU_PAGESHIFT, %g4 318 3193: KDI_HME_HASH_FUNCTION /* %g1, %g2, %g4 => hash in %g4 */ 320 KDI_HME_HASH_TAG /* %g1, %g3 => tag in %g5 */ 321 KDI_HME_HASH_TABLE_SEARCH /* %g2, %g4, %g5 => hmeblk PA in %g4 */ 322 323 brz %g4, 5f 324 nop 325 326 KDI_HBLK_TO_TTEP /* %g1, %g4 => TTE PA in %g2 */ 327 ldxa [%g2]ASI_MEM, %g1 328 brgez,a %g1, 4f 329 clr %g1 3304: 331 /* 332 * If soft execute bit is set, make sure HW execute permission 333 * is also set. But, clear soft execute bit before giving tte to 334 * the caller. 335 */ 336 TTE_CHK_SOFTEXEC_ML(%g1) 337 bz,pt %icc, 6f 338 andcc %g1, TTE_EXECPRM_INT, %g0 339 bnz,pt %icc, 7f 340 nop 341 TTE_SET_EXEC_ML(%g1, %g2, %g4, kdi_trap_vatotte) 3427: 343 TTE_CLR_SOFTEXEC_ML(%g1) 344 ba,a 6f 345 3465: add %g3, 1, %g3 347 set mmu_hashcnt, %g4 348 lduw [%g4], %g4 349 cmp %g3, %g4 350 ble 1b 351 nop 352 353 clr %g1 354 3556: jmp %g7 356 nop 357 SET_SIZE(kdi_trap_vatotte) 358 359#endif /* lint */ 360