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