1 /*- 2 * Copyright (c) 2010 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/lock.h> 32 #include <sys/mutex.h> 33 #include <sys/proc.h> 34 #include <sys/systm.h> 35 36 #include <vm/vm.h> 37 #include <vm/pmap.h> 38 #include <vm/uma.h> 39 #include <vm/vm_map.h> 40 41 #include <machine/md_var.h> 42 #include <machine/pmap.h> 43 #include <machine/vmparam.h> 44 45 uintptr_t moea64_get_unique_vsid(void); 46 void moea64_release_vsid(uint64_t vsid); 47 static void slb_zone_init(void *); 48 49 uma_zone_t slbt_zone; 50 uma_zone_t slb_cache_zone; 51 52 SYSINIT(slb_zone_init, SI_SUB_KMEM, SI_ORDER_ANY, slb_zone_init, NULL); 53 54 struct slbtnode { 55 uint16_t ua_alloc; 56 uint8_t ua_level; 57 /* Only 36 bits needed for full 64-bit address space. */ 58 uint64_t ua_base; 59 union { 60 struct slbtnode *ua_child[16]; 61 struct slb slb_entries[16]; 62 } u; 63 }; 64 65 /* 66 * For a full 64-bit address space, there are 36 bits in play in an 67 * esid, so 8 levels, with the leaf being at level 0. 68 * 69 * |3333|3322|2222|2222|1111|1111|11 | | | esid 70 * |5432|1098|7654|3210|9876|5432|1098|7654|3210| bits 71 * +----+----+----+----+----+----+----+----+----+-------- 72 * | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | level 73 */ 74 #define UAD_ROOT_LEVEL 8 75 #define UAD_LEAF_LEVEL 0 76 77 static inline int 78 esid2idx(uint64_t esid, int level) 79 { 80 int shift; 81 82 shift = level * 4; 83 return ((esid >> shift) & 0xF); 84 } 85 86 /* 87 * The ua_base field should have 0 bits after the first 4*(level+1) 88 * bits; i.e. only 89 */ 90 #define uad_baseok(ua) \ 91 (esid2base(ua->ua_base, ua->ua_level) == ua->ua_base) 92 93 94 static inline uint64_t 95 esid2base(uint64_t esid, int level) 96 { 97 uint64_t mask; 98 int shift; 99 100 shift = (level + 1) * 4; 101 mask = ~((1ULL << shift) - 1); 102 return (esid & mask); 103 } 104 105 /* 106 * Allocate a new leaf node for the specified esid/vmhandle from the 107 * parent node. 108 */ 109 static struct slb * 110 make_new_leaf(uint64_t esid, uint64_t slbv, struct slbtnode *parent) 111 { 112 struct slbtnode *child; 113 struct slb *retval; 114 int idx; 115 116 idx = esid2idx(esid, parent->ua_level); 117 KASSERT(parent->u.ua_child[idx] == NULL, ("Child already exists!")); 118 119 /* unlock and M_WAITOK and loop? */ 120 child = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); 121 KASSERT(child != NULL, ("unhandled NULL case")); 122 123 child->ua_level = UAD_LEAF_LEVEL; 124 child->ua_base = esid2base(esid, child->ua_level); 125 idx = esid2idx(esid, child->ua_level); 126 child->u.slb_entries[idx].slbv = slbv; 127 child->u.slb_entries[idx].slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; 128 setbit(&child->ua_alloc, idx); 129 130 retval = &child->u.slb_entries[idx]; 131 132 /* 133 * The above stores must be visible before the next one, so 134 * that a lockless searcher always sees a valid path through 135 * the tree. 136 */ 137 powerpc_sync(); 138 139 idx = esid2idx(esid, parent->ua_level); 140 parent->u.ua_child[idx] = child; 141 setbit(&parent->ua_alloc, idx); 142 143 return (retval); 144 } 145 146 /* 147 * Allocate a new intermediate node to fit between the parent and 148 * esid. 149 */ 150 static struct slbtnode* 151 make_intermediate(uint64_t esid, struct slbtnode *parent) 152 { 153 struct slbtnode *child, *inter; 154 int idx, level; 155 156 idx = esid2idx(esid, parent->ua_level); 157 child = parent->u.ua_child[idx]; 158 KASSERT(esid2base(esid, child->ua_level) != child->ua_base, 159 ("No need for an intermediate node?")); 160 161 /* 162 * Find the level where the existing child and our new esid 163 * meet. It must be lower than parent->ua_level or we would 164 * have chosen a different index in parent. 165 */ 166 level = child->ua_level + 1; 167 while (esid2base(esid, level) != 168 esid2base(child->ua_base, level)) 169 level++; 170 KASSERT(level < parent->ua_level, 171 ("Found splitting level %d for %09jx and %09jx, " 172 "but it's the same as %p's", 173 level, esid, child->ua_base, parent)); 174 175 /* unlock and M_WAITOK and loop? */ 176 inter = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); 177 KASSERT(inter != NULL, ("unhandled NULL case")); 178 179 /* Set up intermediate node to point to child ... */ 180 inter->ua_level = level; 181 inter->ua_base = esid2base(esid, inter->ua_level); 182 idx = esid2idx(child->ua_base, inter->ua_level); 183 inter->u.ua_child[idx] = child; 184 setbit(&inter->ua_alloc, idx); 185 powerpc_sync(); 186 187 /* Set up parent to point to intermediate node ... */ 188 idx = esid2idx(inter->ua_base, parent->ua_level); 189 parent->u.ua_child[idx] = inter; 190 setbit(&parent->ua_alloc, idx); 191 192 return (inter); 193 } 194 195 uint64_t 196 kernel_va_to_slbv(vm_offset_t va) 197 { 198 uint64_t esid, slbv; 199 200 esid = (uintptr_t)va >> ADDR_SR_SHFT; 201 202 /* Set kernel VSID to deterministic value */ 203 slbv = (KERNEL_VSID((uintptr_t)va >> ADDR_SR_SHFT)) << SLBV_VSID_SHIFT; 204 205 /* Figure out if this is a large-page mapping */ 206 if (hw_direct_map && va < VM_MIN_KERNEL_ADDRESS) { 207 /* 208 * XXX: If we have set up a direct map, assumes 209 * all physical memory is mapped with large pages. 210 */ 211 if (mem_valid(va, 0) == 0) 212 slbv |= SLBV_L; 213 } 214 215 return (slbv); 216 } 217 218 struct slb * 219 user_va_to_slb_entry(pmap_t pm, vm_offset_t va) 220 { 221 uint64_t esid = va >> ADDR_SR_SHFT; 222 struct slbtnode *ua; 223 int idx; 224 225 ua = pm->pm_slb_tree_root; 226 227 for (;;) { 228 KASSERT(uad_baseok(ua), ("uad base %016jx level %d bad!", 229 ua->ua_base, ua->ua_level)); 230 idx = esid2idx(esid, ua->ua_level); 231 232 /* 233 * This code is specific to ppc64 where a load is 234 * atomic, so no need for atomic_load macro. 235 */ 236 if (ua->ua_level == UAD_LEAF_LEVEL) 237 return ((ua->u.slb_entries[idx].slbe & SLBE_VALID) ? 238 &ua->u.slb_entries[idx] : NULL); 239 240 ua = ua->u.ua_child[idx]; 241 if (ua == NULL || 242 esid2base(esid, ua->ua_level) != ua->ua_base) 243 return (NULL); 244 } 245 246 return (NULL); 247 } 248 249 uint64_t 250 va_to_vsid(pmap_t pm, vm_offset_t va) 251 { 252 struct slb *entry; 253 254 /* Shortcut kernel case */ 255 if (pm == kernel_pmap) 256 return (KERNEL_VSID((uintptr_t)va >> ADDR_SR_SHFT)); 257 258 /* 259 * If there is no vsid for this VA, we need to add a new entry 260 * to the PMAP's segment table. 261 */ 262 263 entry = user_va_to_slb_entry(pm, va); 264 265 if (entry == NULL) 266 return (allocate_user_vsid(pm, 267 (uintptr_t)va >> ADDR_SR_SHFT, 0)); 268 269 return ((entry->slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT); 270 } 271 272 uint64_t 273 allocate_user_vsid(pmap_t pm, uint64_t esid, int large) 274 { 275 uint64_t vsid, slbv; 276 struct slbtnode *ua, *next, *inter; 277 struct slb *slb; 278 int idx; 279 280 KASSERT(pm != kernel_pmap, ("Attempting to allocate a kernel VSID")); 281 282 PMAP_LOCK_ASSERT(pm, MA_OWNED); 283 vsid = moea64_get_unique_vsid(); 284 285 slbv = vsid << SLBV_VSID_SHIFT; 286 if (large) 287 slbv |= SLBV_L; 288 289 ua = pm->pm_slb_tree_root; 290 291 /* Descend to the correct leaf or NULL pointer. */ 292 for (;;) { 293 KASSERT(uad_baseok(ua), 294 ("uad base %09jx level %d bad!", ua->ua_base, ua->ua_level)); 295 idx = esid2idx(esid, ua->ua_level); 296 297 if (ua->ua_level == UAD_LEAF_LEVEL) { 298 ua->u.slb_entries[idx].slbv = slbv; 299 eieio(); 300 ua->u.slb_entries[idx].slbe = (esid << SLBE_ESID_SHIFT) 301 | SLBE_VALID; 302 setbit(&ua->ua_alloc, idx); 303 slb = &ua->u.slb_entries[idx]; 304 break; 305 } 306 307 next = ua->u.ua_child[idx]; 308 if (next == NULL) { 309 slb = make_new_leaf(esid, slbv, ua); 310 break; 311 } 312 313 /* 314 * Check if the next item down has an okay ua_base. 315 * If not, we need to allocate an intermediate node. 316 */ 317 if (esid2base(esid, next->ua_level) != next->ua_base) { 318 inter = make_intermediate(esid, ua); 319 slb = make_new_leaf(esid, slbv, inter); 320 break; 321 } 322 323 ua = next; 324 } 325 326 /* 327 * Someone probably wants this soon, and it may be a wired 328 * SLB mapping, so pre-spill this entry. 329 */ 330 eieio(); 331 slb_insert_user(pm, slb); 332 333 return (vsid); 334 } 335 336 void 337 free_vsid(pmap_t pm, uint64_t esid, int large) 338 { 339 struct slbtnode *ua; 340 int idx; 341 342 PMAP_LOCK_ASSERT(pm, MA_OWNED); 343 344 ua = pm->pm_slb_tree_root; 345 /* Descend to the correct leaf. */ 346 for (;;) { 347 KASSERT(uad_baseok(ua), 348 ("uad base %09jx level %d bad!", ua->ua_base, ua->ua_level)); 349 350 idx = esid2idx(esid, ua->ua_level); 351 if (ua->ua_level == UAD_LEAF_LEVEL) { 352 ua->u.slb_entries[idx].slbv = 0; 353 eieio(); 354 ua->u.slb_entries[idx].slbe = 0; 355 clrbit(&ua->ua_alloc, idx); 356 return; 357 } 358 359 ua = ua->u.ua_child[idx]; 360 if (ua == NULL || 361 esid2base(esid, ua->ua_level) != ua->ua_base) { 362 /* Perhaps just return instead of assert? */ 363 KASSERT(0, 364 ("Asked to remove an entry that was never inserted!")); 365 return; 366 } 367 } 368 } 369 370 static void 371 free_slb_tree_node(struct slbtnode *ua) 372 { 373 int idx; 374 375 for (idx = 0; idx < 16; idx++) { 376 if (ua->ua_level != UAD_LEAF_LEVEL) { 377 if (ua->u.ua_child[idx] != NULL) 378 free_slb_tree_node(ua->u.ua_child[idx]); 379 } else { 380 if (ua->u.slb_entries[idx].slbv != 0) 381 moea64_release_vsid(ua->u.slb_entries[idx].slbv 382 >> SLBV_VSID_SHIFT); 383 } 384 } 385 386 uma_zfree(slbt_zone, ua); 387 } 388 389 void 390 slb_free_tree(pmap_t pm) 391 { 392 393 free_slb_tree_node(pm->pm_slb_tree_root); 394 } 395 396 struct slbtnode * 397 slb_alloc_tree(void) 398 { 399 struct slbtnode *root; 400 401 root = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); 402 root->ua_level = UAD_ROOT_LEVEL; 403 404 return (root); 405 } 406 407 /* Lock entries mapping kernel text and stacks */ 408 409 #define SLB_SPILLABLE(slbe) \ 410 (((slbe & SLBE_ESID_MASK) < VM_MIN_KERNEL_ADDRESS && \ 411 (slbe & SLBE_ESID_MASK) > 16*SEGMENT_LENGTH) || \ 412 (slbe & SLBE_ESID_MASK) > VM_MAX_KERNEL_ADDRESS) 413 void 414 slb_insert_kernel(uint64_t slbe, uint64_t slbv) 415 { 416 struct slb *slbcache; 417 int i, j; 418 419 /* We don't want to be preempted while modifying the kernel map */ 420 critical_enter(); 421 422 slbcache = PCPU_GET(slb); 423 424 /* Check for an unused slot, abusing the user slot as a full flag */ 425 if (slbcache[USER_SLB_SLOT].slbe == 0) { 426 for (i = 0; i < USER_SLB_SLOT; i++) { 427 if (!(slbcache[i].slbe & SLBE_VALID)) 428 goto fillkernslb; 429 } 430 431 if (i == USER_SLB_SLOT) 432 slbcache[USER_SLB_SLOT].slbe = 1; 433 } 434 435 for (i = mftb() % 64, j = 0; j < 64; j++, i = (i+1) % 64) { 436 if (i == USER_SLB_SLOT) 437 continue; 438 439 if (SLB_SPILLABLE(slbcache[i].slbe)) 440 break; 441 } 442 443 KASSERT(j < 64, ("All kernel SLB slots locked!")); 444 445 fillkernslb: 446 slbcache[i].slbv = slbv; 447 slbcache[i].slbe = slbe | (uint64_t)i; 448 449 /* If it is for this CPU, put it in the SLB right away */ 450 if (pmap_bootstrapped) { 451 /* slbie not required */ 452 __asm __volatile ("slbmte %0, %1" :: 453 "r"(slbcache[i].slbv), "r"(slbcache[i].slbe)); 454 } 455 456 critical_exit(); 457 } 458 459 void 460 slb_insert_user(pmap_t pm, struct slb *slb) 461 { 462 int i; 463 464 PMAP_LOCK_ASSERT(pm, MA_OWNED); 465 466 if (pm->pm_slb_len < 64) { 467 i = pm->pm_slb_len; 468 pm->pm_slb_len++; 469 } else { 470 i = mftb() % 64; 471 } 472 473 /* Note that this replacement is atomic with respect to trap_subr */ 474 pm->pm_slb[i] = slb; 475 } 476 477 static void 478 slb_zone_init(void *dummy) 479 { 480 481 slbt_zone = uma_zcreate("SLB tree node", sizeof(struct slbtnode), 482 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); 483 slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb *), 484 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); 485 } 486 487 struct slb ** 488 slb_alloc_user_cache(void) 489 { 490 return (uma_zalloc(slb_cache_zone, M_ZERO)); 491 } 492 493 void 494 slb_free_user_cache(struct slb **slb) 495 { 496 uma_zfree(slb_cache_zone, slb); 497 } 498