1 /* $OpenBSD: uvm_addr.c,v 1.30 2021/03/20 10:24:21 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* #define DEBUG */ 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <uvm/uvm.h> 24 #include <uvm/uvm_addr.h> 25 #include <sys/pool.h> 26 27 /* Max gap between hint allocations. */ 28 #define UADDR_HINT_MAXGAP (4 * PAGE_SIZE) 29 /* Number of pivots in pivot allocator. */ 30 #define NUM_PIVOTS 16 31 /* 32 * Max number (inclusive) of pages the pivot allocator 33 * will place between allocations. 34 * 35 * The uaddr_pivot_random() function attempts to bias towards 36 * small space between allocations, so putting a large number here is fine. 37 */ 38 #define PIVOT_RND 8 39 /* 40 * Number of allocations that a pivot can supply before expiring. 41 * When a pivot expires, a new pivot has to be found. 42 * 43 * Must be at least 1. 44 */ 45 #define PIVOT_EXPIRE 1024 46 47 48 /* Pool with uvm_addr_state structures. */ 49 struct pool uaddr_pool; 50 struct pool uaddr_bestfit_pool; 51 struct pool uaddr_pivot_pool; 52 struct pool uaddr_rnd_pool; 53 54 /* uvm_addr state for bestfit selector. */ 55 struct uaddr_bestfit_state { 56 struct uvm_addr_state ubf_uaddr; 57 struct uaddr_free_rbtree ubf_free; 58 }; 59 60 /* uvm_addr state for rnd selector. */ 61 struct uaddr_rnd_state { 62 struct uvm_addr_state ur_uaddr; 63 #if 0 64 TAILQ_HEAD(, vm_map_entry) ur_free; 65 #endif 66 }; 67 68 /* 69 * Definition of a pivot in pivot selector. 70 */ 71 struct uaddr_pivot { 72 vaddr_t addr; /* End of prev. allocation. */ 73 int expire;/* Best before date. */ 74 int dir; /* Direction. */ 75 struct vm_map_entry *entry; /* Will contain next alloc. */ 76 }; 77 /* uvm_addr state for pivot selector. */ 78 struct uaddr_pivot_state { 79 struct uvm_addr_state up_uaddr; 80 81 /* Free space tree, for fast pivot selection. */ 82 struct uaddr_free_rbtree up_free; 83 84 /* List of pivots. The pointers point to after the last allocation. */ 85 struct uaddr_pivot up_pivots[NUM_PIVOTS]; 86 }; 87 88 /* Forward declaration (see below). */ 89 extern const struct uvm_addr_functions uaddr_kernel_functions; 90 struct uvm_addr_state uaddr_kbootstrap; 91 92 93 /* 94 * Support functions. 95 */ 96 97 #ifndef SMALL_KERNEL 98 struct vm_map_entry *uvm_addr_entrybyspace(struct uaddr_free_rbtree*, 99 vsize_t); 100 #endif /* !SMALL_KERNEL */ 101 void uaddr_kinsert(struct vm_map *, 102 struct uvm_addr_state *, struct vm_map_entry *); 103 void uaddr_kremove(struct vm_map *, 104 struct uvm_addr_state *, struct vm_map_entry *); 105 void uaddr_kbootstrapdestroy(struct uvm_addr_state *); 106 107 void uaddr_destroy(struct uvm_addr_state *); 108 void uaddr_kbootstrap_destroy(struct uvm_addr_state *); 109 void uaddr_rnd_destroy(struct uvm_addr_state *); 110 void uaddr_bestfit_destroy(struct uvm_addr_state *); 111 void uaddr_pivot_destroy(struct uvm_addr_state *); 112 113 #if 0 114 int uaddr_lin_select(struct vm_map *, 115 struct uvm_addr_state *, struct vm_map_entry **, 116 vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, 117 vaddr_t); 118 #endif 119 int uaddr_kbootstrap_select(struct vm_map *, 120 struct uvm_addr_state *, struct vm_map_entry **, 121 vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, 122 vaddr_t); 123 int uaddr_rnd_select(struct vm_map *, 124 struct uvm_addr_state *, struct vm_map_entry **, 125 vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, 126 vaddr_t); 127 int uaddr_bestfit_select(struct vm_map *, 128 struct uvm_addr_state*, struct vm_map_entry **, 129 vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, 130 vaddr_t); 131 #ifndef SMALL_KERNEL 132 int uaddr_pivot_select(struct vm_map *, 133 struct uvm_addr_state *, struct vm_map_entry **, 134 vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, 135 vaddr_t); 136 int uaddr_stack_brk_select(struct vm_map *, 137 struct uvm_addr_state *, struct vm_map_entry **, 138 vaddr_t *, vsize_t, vaddr_t, vaddr_t, vm_prot_t, 139 vaddr_t); 140 #endif /* !SMALL_KERNEL */ 141 142 void uaddr_rnd_insert(struct vm_map *, 143 struct uvm_addr_state *, struct vm_map_entry *); 144 void uaddr_rnd_remove(struct vm_map *, 145 struct uvm_addr_state *, struct vm_map_entry *); 146 void uaddr_bestfit_insert(struct vm_map *, 147 struct uvm_addr_state *, struct vm_map_entry *); 148 void uaddr_bestfit_remove(struct vm_map *, 149 struct uvm_addr_state *, struct vm_map_entry *); 150 void uaddr_pivot_insert(struct vm_map *, 151 struct uvm_addr_state *, struct vm_map_entry *); 152 void uaddr_pivot_remove(struct vm_map *, 153 struct uvm_addr_state *, struct vm_map_entry *); 154 155 #ifndef SMALL_KERNEL 156 vsize_t uaddr_pivot_random(void); 157 int uaddr_pivot_newpivot(struct vm_map *, 158 struct uaddr_pivot_state *, struct uaddr_pivot *, 159 struct vm_map_entry **, vaddr_t *, 160 vsize_t, vaddr_t, vaddr_t, vsize_t, vsize_t); 161 #endif /* !SMALL_KERNEL */ 162 163 #if defined(DEBUG) || defined(DDB) 164 void uaddr_pivot_print(struct uvm_addr_state *, boolean_t, 165 int (*)(const char *, ...)); 166 #if 0 167 void uaddr_rnd_print(struct uvm_addr_state *, boolean_t, 168 int (*)(const char *, ...)); 169 #endif 170 #endif /* DEBUG || DDB */ 171 172 173 #ifndef SMALL_KERNEL 174 /* 175 * Find smallest entry in tree that will fit sz bytes. 176 */ 177 struct vm_map_entry * 178 uvm_addr_entrybyspace(struct uaddr_free_rbtree *free, vsize_t sz) 179 { 180 struct vm_map_entry *tmp, *res; 181 182 tmp = RBT_ROOT(uaddr_free_rbtree, free); 183 res = NULL; 184 while (tmp) { 185 if (tmp->fspace >= sz) { 186 res = tmp; 187 tmp = RBT_LEFT(uaddr_free_rbtree, tmp); 188 } else if (tmp->fspace < sz) 189 tmp = RBT_RIGHT(uaddr_free_rbtree, tmp); 190 } 191 return res; 192 } 193 #endif /* !SMALL_KERNEL */ 194 195 static inline vaddr_t 196 uvm_addr_align_forward(vaddr_t addr, vaddr_t align, vaddr_t offset) 197 { 198 vaddr_t adjusted; 199 200 KASSERT(offset < align || (align == 0 && offset == 0)); 201 KASSERT((align & (align - 1)) == 0); 202 KASSERT((offset & PAGE_MASK) == 0); 203 204 align = MAX(align, PAGE_SIZE); 205 adjusted = addr & ~(align - 1); 206 adjusted += offset; 207 return (adjusted < addr ? adjusted + align : adjusted); 208 } 209 210 static inline vaddr_t 211 uvm_addr_align_backward(vaddr_t addr, vaddr_t align, vaddr_t offset) 212 { 213 vaddr_t adjusted; 214 215 KASSERT(offset < align || (align == 0 && offset == 0)); 216 KASSERT((align & (align - 1)) == 0); 217 KASSERT((offset & PAGE_MASK) == 0); 218 219 align = MAX(align, PAGE_SIZE); 220 adjusted = addr & ~(align - 1); 221 adjusted += offset; 222 return (adjusted > addr ? adjusted - align : adjusted); 223 } 224 225 /* 226 * Try to fit the requested space into the entry. 227 */ 228 int 229 uvm_addr_fitspace(vaddr_t *min_result, vaddr_t *max_result, 230 vaddr_t low_addr, vaddr_t high_addr, vsize_t sz, 231 vaddr_t align, vaddr_t offset, 232 vsize_t before_gap, vsize_t after_gap) 233 { 234 vaddr_t tmp; 235 vsize_t fspace; 236 237 if (low_addr > high_addr) 238 return ENOMEM; 239 fspace = high_addr - low_addr; 240 if (fspace < before_gap + after_gap) 241 return ENOMEM; 242 if (fspace - before_gap - after_gap < sz) 243 return ENOMEM; 244 245 /* 246 * Calculate lowest address. 247 */ 248 low_addr += before_gap; 249 low_addr = uvm_addr_align_forward(tmp = low_addr, align, offset); 250 if (low_addr < tmp) /* Overflow during alignment. */ 251 return ENOMEM; 252 if (high_addr - after_gap - sz < low_addr) 253 return ENOMEM; 254 255 /* 256 * Calculate highest address. 257 */ 258 high_addr -= after_gap + sz; 259 high_addr = uvm_addr_align_backward(tmp = high_addr, align, offset); 260 if (high_addr > tmp) /* Overflow during alignment. */ 261 return ENOMEM; 262 if (low_addr > high_addr) 263 return ENOMEM; 264 265 *min_result = low_addr; 266 *max_result = high_addr; 267 return 0; 268 } 269 270 271 /* 272 * Initialize uvm_addr. 273 */ 274 void 275 uvm_addr_init(void) 276 { 277 pool_init(&uaddr_pool, sizeof(struct uvm_addr_state), 0, 278 IPL_VM, PR_WAITOK, "uaddr", NULL); 279 pool_init(&uaddr_bestfit_pool, sizeof(struct uaddr_bestfit_state), 0, 280 IPL_VM, PR_WAITOK, "uaddrbest", NULL); 281 pool_init(&uaddr_pivot_pool, sizeof(struct uaddr_pivot_state), 0, 282 IPL_VM, PR_WAITOK, "uaddrpivot", NULL); 283 pool_init(&uaddr_rnd_pool, sizeof(struct uaddr_rnd_state), 0, 284 IPL_VM, PR_WAITOK, "uaddrrnd", NULL); 285 286 uaddr_kbootstrap.uaddr_minaddr = PAGE_SIZE; 287 uaddr_kbootstrap.uaddr_maxaddr = -(vaddr_t)PAGE_SIZE; 288 uaddr_kbootstrap.uaddr_functions = &uaddr_kernel_functions; 289 } 290 291 /* 292 * Invoke destructor function of uaddr. 293 */ 294 void 295 uvm_addr_destroy(struct uvm_addr_state *uaddr) 296 { 297 if (uaddr) 298 (*uaddr->uaddr_functions->uaddr_destroy)(uaddr); 299 } 300 301 /* 302 * Move address forward to satisfy align, offset. 303 */ 304 vaddr_t 305 uvm_addr_align(vaddr_t addr, vaddr_t align, vaddr_t offset) 306 { 307 vaddr_t result = (addr & ~(align - 1)) + offset; 308 if (result < addr) 309 result += align; 310 return result; 311 } 312 313 /* 314 * Move address backwards to satisfy align, offset. 315 */ 316 vaddr_t 317 uvm_addr_align_back(vaddr_t addr, vaddr_t align, vaddr_t offset) 318 { 319 vaddr_t result = (addr & ~(align - 1)) + offset; 320 if (result > addr) 321 result -= align; 322 return result; 323 } 324 325 /* 326 * Directional first fit. 327 * 328 * Do a linear search for free space, starting at addr in entry. 329 * direction == 1: search forward 330 * direction == -1: search backward 331 * 332 * Output: low <= addr <= high and entry will contain addr. 333 * 0 will be returned if no space is available. 334 * 335 * gap describes the space that must appear between the preceding entry. 336 */ 337 int 338 uvm_addr_linsearch(struct vm_map *map, struct uvm_addr_state *uaddr, 339 struct vm_map_entry **entry_out, vaddr_t *addr_out, 340 vaddr_t hint, vsize_t sz, vaddr_t align, vaddr_t offset, 341 int direction, vaddr_t low, vaddr_t high, 342 vsize_t before_gap, vsize_t after_gap) 343 { 344 struct vm_map_entry *entry; 345 vaddr_t low_addr, high_addr; 346 347 KASSERT(entry_out != NULL && addr_out != NULL); 348 KASSERT(direction == -1 || direction == 1); 349 KASSERT((hint & PAGE_MASK) == 0 && (high & PAGE_MASK) == 0 && 350 (low & PAGE_MASK) == 0 && 351 (before_gap & PAGE_MASK) == 0 && (after_gap & PAGE_MASK) == 0); 352 KASSERT(high + sz > high); /* Check for overflow. */ 353 354 /* 355 * Hint magic. 356 */ 357 if (hint == 0) 358 hint = (direction == 1 ? low : high); 359 else if (hint > high) { 360 if (direction != -1) 361 return ENOMEM; 362 hint = high; 363 } else if (hint < low) { 364 if (direction != 1) 365 return ENOMEM; 366 hint = low; 367 } 368 369 for (entry = uvm_map_entrybyaddr(&map->addr, 370 hint - (direction == -1 ? 1 : 0)); entry != NULL; 371 entry = (direction == 1 ? 372 RBT_NEXT(uvm_map_addr, entry) : 373 RBT_PREV(uvm_map_addr, entry))) { 374 if ((direction == 1 && VMMAP_FREE_START(entry) > high) || 375 (direction == -1 && VMMAP_FREE_END(entry) < low)) { 376 break; 377 } 378 379 if (uvm_addr_fitspace(&low_addr, &high_addr, 380 MAX(low, VMMAP_FREE_START(entry)), 381 MIN(high, VMMAP_FREE_END(entry)), 382 sz, align, offset, before_gap, after_gap) == 0) { 383 *entry_out = entry; 384 if (hint >= low_addr && hint <= high_addr) { 385 *addr_out = hint; 386 } else { 387 *addr_out = (direction == 1 ? 388 low_addr : high_addr); 389 } 390 return 0; 391 } 392 } 393 394 return ENOMEM; 395 } 396 397 /* 398 * Invoke address selector of uaddr. 399 * uaddr may be NULL, in which case the algorithm will fail with ENOMEM. 400 * 401 * Will invoke uvm_addr_isavail to fill in last_out. 402 */ 403 int 404 uvm_addr_invoke(struct vm_map *map, struct uvm_addr_state *uaddr, 405 struct vm_map_entry **entry_out, struct vm_map_entry **last_out, 406 vaddr_t *addr_out, 407 vsize_t sz, vaddr_t align, vaddr_t offset, vm_prot_t prot, vaddr_t hint) 408 { 409 int error; 410 411 if (uaddr == NULL) 412 return ENOMEM; 413 414 hint &= ~((vaddr_t)PAGE_MASK); 415 if (hint != 0 && 416 !(hint >= uaddr->uaddr_minaddr && hint < uaddr->uaddr_maxaddr)) 417 return ENOMEM; 418 419 error = (*uaddr->uaddr_functions->uaddr_select)(map, uaddr, 420 entry_out, addr_out, sz, align, offset, prot, hint); 421 422 if (error == 0) { 423 KASSERT(*entry_out != NULL); 424 *last_out = NULL; 425 if (!uvm_map_isavail(map, uaddr, entry_out, last_out, 426 *addr_out, sz)) { 427 panic("uvm_addr_invoke: address selector %p " 428 "(%s 0x%lx-0x%lx) " 429 "returned unavailable address 0x%lx sz 0x%lx", 430 uaddr, uaddr->uaddr_functions->uaddr_name, 431 uaddr->uaddr_minaddr, uaddr->uaddr_maxaddr, 432 *addr_out, sz); 433 } 434 } 435 436 return error; 437 } 438 439 #if defined(DEBUG) || defined(DDB) 440 void 441 uvm_addr_print(struct uvm_addr_state *uaddr, const char *slot, boolean_t full, 442 int (*pr)(const char *, ...)) 443 { 444 if (uaddr == NULL) { 445 (*pr)("- uvm_addr %s: NULL\n", slot); 446 return; 447 } 448 449 (*pr)("- uvm_addr %s: %p (%s 0x%lx-0x%lx)\n", slot, uaddr, 450 uaddr->uaddr_functions->uaddr_name, 451 uaddr->uaddr_minaddr, uaddr->uaddr_maxaddr); 452 if (uaddr->uaddr_functions->uaddr_print == NULL) 453 return; 454 455 (*uaddr->uaddr_functions->uaddr_print)(uaddr, full, pr); 456 } 457 #endif /* DEBUG || DDB */ 458 459 /* 460 * Destroy a uvm_addr_state structure. 461 * The uaddr must have been previously allocated from uaddr_state_pool. 462 */ 463 void 464 uaddr_destroy(struct uvm_addr_state *uaddr) 465 { 466 pool_put(&uaddr_pool, uaddr); 467 } 468 469 470 #if 0 471 /* 472 * Linear allocator. 473 * This allocator uses a first-fit algorithm. 474 * 475 * If hint is set, search will start at the hint position. 476 * Only searches forward. 477 */ 478 479 const struct uvm_addr_functions uaddr_lin_functions = { 480 .uaddr_select = &uaddr_lin_select, 481 .uaddr_destroy = &uaddr_destroy, 482 .uaddr_name = "uaddr_lin" 483 }; 484 485 struct uvm_addr_state * 486 uaddr_lin_create(vaddr_t minaddr, vaddr_t maxaddr) 487 { 488 struct uvm_addr_state *uaddr; 489 490 uaddr = pool_get(&uaddr_pool, PR_WAITOK); 491 uaddr->uaddr_minaddr = minaddr; 492 uaddr->uaddr_maxaddr = maxaddr; 493 uaddr->uaddr_functions = &uaddr_lin_functions; 494 return uaddr; 495 } 496 497 int 498 uaddr_lin_select(struct vm_map *map, struct uvm_addr_state *uaddr, 499 struct vm_map_entry **entry_out, vaddr_t *addr_out, 500 vsize_t sz, vaddr_t align, vaddr_t offset, 501 vm_prot_t prot, vaddr_t hint) 502 { 503 vaddr_t guard_sz; 504 505 /* 506 * Deal with guardpages: search for space with one extra page. 507 */ 508 guard_sz = ((map->flags & VM_MAP_GUARDPAGES) == 0 ? 0 : PAGE_SIZE); 509 510 if (uaddr->uaddr_maxaddr - uaddr->uaddr_minaddr - guard_sz < sz) 511 return ENOMEM; 512 return uvm_addr_linsearch(map, uaddr, entry_out, addr_out, 0, sz, 513 align, offset, 1, uaddr->uaddr_minaddr, uaddr->uaddr_maxaddr - sz, 514 0, guard_sz); 515 } 516 #endif 517 518 /* 519 * Randomized allocator. 520 * This allocator use uvm_map_hint to acquire a random address and searches 521 * from there. 522 */ 523 524 const struct uvm_addr_functions uaddr_rnd_functions = { 525 .uaddr_select = &uaddr_rnd_select, 526 .uaddr_free_insert = &uaddr_rnd_insert, 527 .uaddr_free_remove = &uaddr_rnd_remove, 528 .uaddr_destroy = &uaddr_rnd_destroy, 529 #if defined(DEBUG) || defined(DDB) 530 #if 0 531 .uaddr_print = &uaddr_rnd_print, 532 #endif 533 #endif /* DEBUG || DDB */ 534 .uaddr_name = "uaddr_rnd" 535 }; 536 537 struct uvm_addr_state * 538 uaddr_rnd_create(vaddr_t minaddr, vaddr_t maxaddr) 539 { 540 struct uaddr_rnd_state *uaddr; 541 542 uaddr = pool_get(&uaddr_rnd_pool, PR_WAITOK); 543 uaddr->ur_uaddr.uaddr_minaddr = minaddr; 544 uaddr->ur_uaddr.uaddr_maxaddr = maxaddr; 545 uaddr->ur_uaddr.uaddr_functions = &uaddr_rnd_functions; 546 #if 0 547 TAILQ_INIT(&uaddr->ur_free); 548 #endif 549 return &uaddr->ur_uaddr; 550 } 551 552 int 553 uaddr_rnd_select(struct vm_map *map, struct uvm_addr_state *uaddr, 554 struct vm_map_entry **entry_out, vaddr_t *addr_out, 555 vsize_t sz, vaddr_t align, vaddr_t offset, 556 vm_prot_t prot, vaddr_t hint) 557 { 558 struct vmspace *vm; 559 vaddr_t minaddr, maxaddr; 560 vaddr_t guard_sz; 561 vaddr_t low_addr, high_addr; 562 struct vm_map_entry *entry, *next; 563 vsize_t before_gap, after_gap; 564 vaddr_t tmp; 565 566 KASSERT((map->flags & VM_MAP_ISVMSPACE) != 0); 567 vm = (struct vmspace *)map; 568 569 /* Deal with guardpages: search for space with one extra page. */ 570 guard_sz = ((map->flags & VM_MAP_GUARDPAGES) == 0 ? 0 : PAGE_SIZE); 571 572 if (uaddr->uaddr_maxaddr - guard_sz < sz) 573 return ENOMEM; 574 minaddr = uvm_addr_align_forward(uaddr->uaddr_minaddr, align, offset); 575 maxaddr = uvm_addr_align_backward(uaddr->uaddr_maxaddr - sz - guard_sz, 576 align, offset); 577 578 /* Quick fail if the allocation won't fit. */ 579 if (minaddr >= maxaddr) 580 return ENOMEM; 581 582 /* Select a hint. */ 583 if (hint == 0) 584 hint = uvm_map_hint(vm, prot, minaddr, maxaddr); 585 /* Clamp hint to uaddr range. */ 586 hint = MIN(MAX(hint, minaddr), maxaddr); 587 588 /* Align hint to align,offset parameters. */ 589 tmp = hint; 590 hint = uvm_addr_align_forward(tmp, align, offset); 591 /* Check for overflow during alignment. */ 592 if (hint < tmp || hint > maxaddr) 593 return ENOMEM; /* Compatibility mode: never look backwards. */ 594 595 before_gap = 0; 596 after_gap = guard_sz; 597 hint -= MIN(hint, before_gap); 598 599 /* 600 * Use the augmented address tree to look up the first entry 601 * at or after hint with sufficient space. 602 * 603 * This code is the original optimized code, but will fail if the 604 * subtree it looks at does have sufficient space, but fails to meet 605 * the align constraint. 606 * 607 * Guard: subtree is not exhausted and max(fspace) >= required. 608 */ 609 entry = uvm_map_entrybyaddr(&map->addr, hint); 610 611 /* Walk up the tree, until there is at least sufficient space. */ 612 while (entry != NULL && 613 entry->fspace_augment < before_gap + after_gap + sz) 614 entry = RBT_PARENT(uvm_map_addr, entry); 615 616 while (entry != NULL) { 617 /* Test if this fits. */ 618 if (VMMAP_FREE_END(entry) > hint && 619 uvm_map_uaddr_e(map, entry) == uaddr && 620 uvm_addr_fitspace(&low_addr, &high_addr, 621 MAX(uaddr->uaddr_minaddr, VMMAP_FREE_START(entry)), 622 MIN(uaddr->uaddr_maxaddr, VMMAP_FREE_END(entry)), 623 sz, align, offset, before_gap, after_gap) == 0) { 624 *entry_out = entry; 625 if (hint >= low_addr && hint <= high_addr) 626 *addr_out = hint; 627 else 628 *addr_out = low_addr; 629 return 0; 630 } 631 632 /* RBT_NEXT, but skip subtrees that cannot possible fit. */ 633 next = RBT_RIGHT(uvm_map_addr, entry); 634 if (next != NULL && 635 next->fspace_augment >= before_gap + after_gap + sz) { 636 entry = next; 637 while ((next = RBT_LEFT(uvm_map_addr, entry)) != 638 NULL) 639 entry = next; 640 } else { 641 do_parent: 642 next = RBT_PARENT(uvm_map_addr, entry); 643 if (next == NULL) 644 entry = NULL; 645 else if (RBT_LEFT(uvm_map_addr, next) == entry) 646 entry = next; 647 else { 648 entry = next; 649 goto do_parent; 650 } 651 } 652 } 653 654 /* Lookup failed. */ 655 return ENOMEM; 656 } 657 658 /* 659 * Destroy a uaddr_rnd_state structure. 660 */ 661 void 662 uaddr_rnd_destroy(struct uvm_addr_state *uaddr) 663 { 664 pool_put(&uaddr_rnd_pool, uaddr); 665 } 666 667 /* 668 * Add entry to tailq. 669 */ 670 void 671 uaddr_rnd_insert(struct vm_map *map, struct uvm_addr_state *uaddr_p, 672 struct vm_map_entry *entry) 673 { 674 return; 675 } 676 677 /* 678 * Remove entry from tailq. 679 */ 680 void 681 uaddr_rnd_remove(struct vm_map *map, struct uvm_addr_state *uaddr_p, 682 struct vm_map_entry *entry) 683 { 684 return; 685 } 686 687 #if 0 688 #if defined(DEBUG) || defined(DDB) 689 void 690 uaddr_rnd_print(struct uvm_addr_state *uaddr_p, boolean_t full, 691 int (*pr)(const char*, ...)) 692 { 693 struct vm_map_entry *entry; 694 struct uaddr_rnd_state *uaddr; 695 vaddr_t addr; 696 size_t count; 697 vsize_t space; 698 699 uaddr = (struct uaddr_rnd_state *)uaddr_p; 700 addr = 0; 701 count = 0; 702 space = 0; 703 TAILQ_FOREACH(entry, &uaddr->ur_free, dfree.tailq) { 704 count++; 705 space += entry->fspace; 706 707 if (full) { 708 (*pr)("\tentry %p: 0x%lx-0x%lx G=0x%lx F=0x%lx\n", 709 entry, entry->start, entry->end, 710 entry->guard, entry->fspace); 711 (*pr)("\t\tfree: 0x%lx-0x%lx\n", 712 VMMAP_FREE_START(entry), VMMAP_FREE_END(entry)); 713 } 714 if (entry->start < addr) { 715 if (!full) 716 (*pr)("\tentry %p: 0x%lx-0x%lx " 717 "G=0x%lx F=0x%lx\n", 718 entry, entry->start, entry->end, 719 entry->guard, entry->fspace); 720 (*pr)("\t\tstart=0x%lx, expected at least 0x%lx\n", 721 entry->start, addr); 722 } 723 724 addr = VMMAP_FREE_END(entry); 725 } 726 (*pr)("\t0x%lu entries, 0x%lx free bytes\n", count, space); 727 } 728 #endif /* DEBUG || DDB */ 729 #endif 730 731 /* 732 * Kernel allocation bootstrap logic. 733 */ 734 735 const struct uvm_addr_functions uaddr_kernel_functions = { 736 .uaddr_select = &uaddr_kbootstrap_select, 737 .uaddr_destroy = &uaddr_kbootstrap_destroy, 738 .uaddr_name = "uaddr_kbootstrap" 739 }; 740 741 /* 742 * Select an address from the map. 743 * 744 * This function ignores the uaddr spec and instead uses the map directly. 745 * Because of that property, the uaddr algorithm can be shared across all 746 * kernel maps. 747 */ 748 int 749 uaddr_kbootstrap_select(struct vm_map *map, struct uvm_addr_state *uaddr, 750 struct vm_map_entry **entry_out, vaddr_t *addr_out, 751 vsize_t sz, vaddr_t align, vaddr_t offset, vm_prot_t prot, vaddr_t hint) 752 { 753 vaddr_t tmp; 754 755 RBT_FOREACH(*entry_out, uvm_map_addr, &map->addr) { 756 if (VMMAP_FREE_END(*entry_out) <= uvm_maxkaddr && 757 uvm_addr_fitspace(addr_out, &tmp, 758 VMMAP_FREE_START(*entry_out), VMMAP_FREE_END(*entry_out), 759 sz, align, offset, 0, 0) == 0) 760 return 0; 761 } 762 763 return ENOMEM; 764 } 765 766 /* 767 * Don't destroy the kernel bootstrap allocator. 768 */ 769 void 770 uaddr_kbootstrap_destroy(struct uvm_addr_state *uaddr) 771 { 772 KASSERT(uaddr == (struct uvm_addr_state *)&uaddr_kbootstrap); 773 } 774 775 #ifndef SMALL_KERNEL 776 /* 777 * Best fit algorithm. 778 */ 779 780 const struct uvm_addr_functions uaddr_bestfit_functions = { 781 .uaddr_select = &uaddr_bestfit_select, 782 .uaddr_free_insert = &uaddr_bestfit_insert, 783 .uaddr_free_remove = &uaddr_bestfit_remove, 784 .uaddr_destroy = &uaddr_bestfit_destroy, 785 .uaddr_name = "uaddr_bestfit" 786 }; 787 788 struct uvm_addr_state * 789 uaddr_bestfit_create(vaddr_t minaddr, vaddr_t maxaddr) 790 { 791 struct uaddr_bestfit_state *uaddr; 792 793 uaddr = pool_get(&uaddr_bestfit_pool, PR_WAITOK); 794 uaddr->ubf_uaddr.uaddr_minaddr = minaddr; 795 uaddr->ubf_uaddr.uaddr_maxaddr = maxaddr; 796 uaddr->ubf_uaddr.uaddr_functions = &uaddr_bestfit_functions; 797 RBT_INIT(uaddr_free_rbtree, &uaddr->ubf_free); 798 return &uaddr->ubf_uaddr; 799 } 800 801 void 802 uaddr_bestfit_destroy(struct uvm_addr_state *uaddr) 803 { 804 pool_put(&uaddr_bestfit_pool, uaddr); 805 } 806 807 void 808 uaddr_bestfit_insert(struct vm_map *map, struct uvm_addr_state *uaddr_p, 809 struct vm_map_entry *entry) 810 { 811 struct uaddr_bestfit_state *uaddr; 812 struct vm_map_entry *rb_rv; 813 814 uaddr = (struct uaddr_bestfit_state *)uaddr_p; 815 if ((rb_rv = RBT_INSERT(uaddr_free_rbtree, &uaddr->ubf_free, entry)) != 816 NULL) { 817 panic("%s: duplicate insertion: state %p " 818 "interting %p, colliding with %p", __func__, 819 uaddr, entry, rb_rv); 820 } 821 } 822 823 void 824 uaddr_bestfit_remove(struct vm_map *map, struct uvm_addr_state *uaddr_p, 825 struct vm_map_entry *entry) 826 { 827 struct uaddr_bestfit_state *uaddr; 828 829 uaddr = (struct uaddr_bestfit_state *)uaddr_p; 830 if (RBT_REMOVE(uaddr_free_rbtree, &uaddr->ubf_free, entry) != entry) 831 panic("%s: entry was not in tree", __func__); 832 } 833 834 int 835 uaddr_bestfit_select(struct vm_map *map, struct uvm_addr_state *uaddr_p, 836 struct vm_map_entry **entry_out, vaddr_t *addr_out, 837 vsize_t sz, vaddr_t align, vaddr_t offset, 838 vm_prot_t prot, vaddr_t hint) 839 { 840 vaddr_t min, max; 841 struct uaddr_bestfit_state *uaddr; 842 struct vm_map_entry *entry; 843 vsize_t guardsz; 844 845 uaddr = (struct uaddr_bestfit_state *)uaddr_p; 846 guardsz = ((map->flags & VM_MAP_GUARDPAGES) ? PAGE_SIZE : 0); 847 if (sz + guardsz < sz) 848 return ENOMEM; 849 850 /* 851 * Find smallest item on freelist capable of holding item. 852 * Deal with guardpages: search for space with one extra page. 853 */ 854 entry = uvm_addr_entrybyspace(&uaddr->ubf_free, sz + guardsz); 855 if (entry == NULL) 856 return ENOMEM; 857 858 /* 859 * Walk the tree until we find an entry that fits. 860 */ 861 while (uvm_addr_fitspace(&min, &max, 862 VMMAP_FREE_START(entry), VMMAP_FREE_END(entry), 863 sz, align, offset, 0, guardsz) != 0) { 864 entry = RBT_NEXT(uaddr_free_rbtree, entry); 865 if (entry == NULL) 866 return ENOMEM; 867 } 868 869 /* 870 * Return the address that generates the least fragmentation. 871 */ 872 *entry_out = entry; 873 *addr_out = (min - VMMAP_FREE_START(entry) <= 874 VMMAP_FREE_END(entry) - guardsz - sz - max ? 875 min : max); 876 return 0; 877 } 878 #endif /* !SMALL_KERNEL */ 879 880 881 #ifndef SMALL_KERNEL 882 /* 883 * A userspace allocator based on pivots. 884 */ 885 886 const struct uvm_addr_functions uaddr_pivot_functions = { 887 .uaddr_select = &uaddr_pivot_select, 888 .uaddr_free_insert = &uaddr_pivot_insert, 889 .uaddr_free_remove = &uaddr_pivot_remove, 890 .uaddr_destroy = &uaddr_pivot_destroy, 891 #if defined(DEBUG) || defined(DDB) 892 .uaddr_print = &uaddr_pivot_print, 893 #endif /* DEBUG || DDB */ 894 .uaddr_name = "uaddr_pivot" 895 }; 896 897 /* 898 * A special random function for pivots. 899 * 900 * This function will return: 901 * - a random number 902 * - a multiple of PAGE_SIZE 903 * - at least PAGE_SIZE 904 * 905 * The random function has a slightly higher change to return a small number. 906 */ 907 vsize_t 908 uaddr_pivot_random(void) 909 { 910 int r; 911 912 /* 913 * The sum of two six-sided dice will have a normal distribution. 914 * We map the highest probable number to 1, by folding the curve 915 * (think of a graph on a piece of paper, that you fold). 916 * 917 * Because the fold happens at PIVOT_RND - 1, the numbers 0 and 1 918 * have the same and highest probability of happening. 919 */ 920 r = arc4random_uniform(PIVOT_RND) + arc4random_uniform(PIVOT_RND) - 921 (PIVOT_RND - 1); 922 if (r < 0) 923 r = -r; 924 925 /* 926 * Make the returned value at least PAGE_SIZE and a multiple of 927 * PAGE_SIZE. 928 */ 929 return (vaddr_t)(1 + r) << PAGE_SHIFT; 930 } 931 932 /* 933 * Select a new pivot. 934 * 935 * A pivot must: 936 * - be chosen random 937 * - have a randomly chosen gap before it, where the uaddr_state starts 938 * - have a randomly chosen gap after it, before the uaddr_state ends 939 * 940 * Furthermore, the pivot must provide sufficient space for the allocation. 941 * The addr will be set to the selected address. 942 * 943 * Returns ENOMEM on failure. 944 */ 945 int 946 uaddr_pivot_newpivot(struct vm_map *map, struct uaddr_pivot_state *uaddr, 947 struct uaddr_pivot *pivot, 948 struct vm_map_entry **entry_out, vaddr_t *addr_out, 949 vsize_t sz, vaddr_t align, vaddr_t offset, 950 vsize_t before_gap, vsize_t after_gap) 951 { 952 struct vm_map_entry *entry, *found; 953 vaddr_t minaddr, maxaddr; 954 vsize_t dist; 955 vaddr_t found_minaddr, found_maxaddr; 956 vaddr_t min, max; 957 vsize_t arc4_arg; 958 int fit_error; 959 u_int32_t path; 960 961 minaddr = uaddr->up_uaddr.uaddr_minaddr; 962 maxaddr = uaddr->up_uaddr.uaddr_maxaddr; 963 KASSERT(minaddr < maxaddr); 964 #ifdef DIAGNOSTIC 965 if (minaddr + 2 * PAGE_SIZE > maxaddr) { 966 panic("uaddr_pivot_newpivot: cannot grant random pivot " 967 "in area less than 2 pages (size = 0x%lx)", 968 maxaddr - minaddr); 969 } 970 #endif /* DIAGNOSTIC */ 971 972 /* 973 * Gap calculation: 1/32 of the size of the managed area. 974 * 975 * At most: sufficient to not get truncated at arc4random. 976 * At least: 2 PAGE_SIZE 977 * 978 * minaddr and maxaddr will be changed according to arc4random. 979 */ 980 dist = MAX((maxaddr - minaddr) / 32, 2 * (vaddr_t)PAGE_SIZE); 981 if (dist >> PAGE_SHIFT > 0xffffffff) { 982 minaddr += (vsize_t)arc4random() << PAGE_SHIFT; 983 maxaddr -= (vsize_t)arc4random() << PAGE_SHIFT; 984 } else { 985 minaddr += (vsize_t)arc4random_uniform(dist >> PAGE_SHIFT) << 986 PAGE_SHIFT; 987 maxaddr -= (vsize_t)arc4random_uniform(dist >> PAGE_SHIFT) << 988 PAGE_SHIFT; 989 } 990 991 /* 992 * A very fast way to find an entry that will be large enough 993 * to hold the allocation, but still is found more or less 994 * randomly: the tree path selector has a 50% chance to go for 995 * a bigger or smaller entry. 996 * 997 * Note that the memory may actually be available, 998 * but the fragmentation may be so bad and the gaps chosen 999 * so unfortunately, that the allocation will not succeed. 1000 * Or the alignment can only be satisfied by an entry that 1001 * is not visited in the randomly selected path. 1002 * 1003 * This code finds an entry with sufficient space in O(log n) time. 1004 */ 1005 path = arc4random(); 1006 found = NULL; 1007 entry = RBT_ROOT(uaddr_free_rbtree, &uaddr->up_free); 1008 while (entry != NULL) { 1009 fit_error = uvm_addr_fitspace(&min, &max, 1010 MAX(VMMAP_FREE_START(entry), minaddr), 1011 MIN(VMMAP_FREE_END(entry), maxaddr), 1012 sz, align, offset, before_gap, after_gap); 1013 1014 /* It fits, save this entry. */ 1015 if (fit_error == 0) { 1016 found = entry; 1017 found_minaddr = min; 1018 found_maxaddr = max; 1019 } 1020 1021 /* Next. */ 1022 if (fit_error != 0) 1023 entry = RBT_RIGHT(uaddr_free_rbtree, entry); 1024 else if ((path & 0x1) == 0) { 1025 path >>= 1; 1026 entry = RBT_RIGHT(uaddr_free_rbtree, entry); 1027 } else { 1028 path >>= 1; 1029 entry = RBT_LEFT(uaddr_free_rbtree, entry); 1030 } 1031 } 1032 if (found == NULL) 1033 return ENOMEM; /* Not found a large enough region. */ 1034 1035 /* 1036 * Calculate a random address within found. 1037 * 1038 * found_minaddr and found_maxaddr are already aligned, so be sure 1039 * to select a multiple of align as the offset in the entry. 1040 * Preferably, arc4random_uniform is used to provide no bias within 1041 * the entry. 1042 * However if the size of the entry exceeds arc4random_uniforms 1043 * argument limit, we simply use arc4random (thus limiting ourselves 1044 * to 4G * PAGE_SIZE bytes offset). 1045 */ 1046 if (found_maxaddr == found_minaddr) 1047 *addr_out = found_minaddr; 1048 else { 1049 KASSERT(align >= PAGE_SIZE && (align & (align - 1)) == 0); 1050 arc4_arg = found_maxaddr - found_minaddr; 1051 if (arc4_arg > 0xffffffff) { 1052 *addr_out = found_minaddr + 1053 (arc4random() & ~(align - 1)); 1054 } else { 1055 *addr_out = found_minaddr + 1056 (arc4random_uniform(arc4_arg) & ~(align - 1)); 1057 } 1058 } 1059 /* Address was found in this entry. */ 1060 *entry_out = found; 1061 1062 /* 1063 * Set up new pivot and return selected address. 1064 * 1065 * Depending on the direction of the pivot, the pivot must be placed 1066 * at the bottom or the top of the allocation: 1067 * - if the pivot moves upwards, place the pivot at the top of the 1068 * allocation, 1069 * - if the pivot moves downwards, place the pivot at the bottom 1070 * of the allocation. 1071 */ 1072 pivot->entry = found; 1073 pivot->dir = (arc4random() & 0x1 ? 1 : -1); 1074 if (pivot->dir > 0) 1075 pivot->addr = *addr_out + sz; 1076 else 1077 pivot->addr = *addr_out; 1078 pivot->expire = PIVOT_EXPIRE - 1; /* First use is right now. */ 1079 return 0; 1080 } 1081 1082 /* 1083 * Pivot selector. 1084 * 1085 * Each time the selector is invoked, it will select a random pivot, which 1086 * it will use to select memory with. The memory will be placed at the pivot, 1087 * with a randomly sized gap between the allocation and the pivot. 1088 * The pivot will then move so it will never revisit this address. 1089 * 1090 * Each allocation, the pivot expiry timer ticks. Once the pivot becomes 1091 * expired, it will be replaced with a newly created pivot. Pivots also 1092 * automatically expire if they fail to provide memory for an allocation. 1093 * 1094 * Expired pivots are replaced using the uaddr_pivot_newpivot() function, 1095 * which will ensure the pivot points at memory in such a way that the 1096 * allocation will succeed. 1097 * As an added bonus, the uaddr_pivot_newpivot() function will perform the 1098 * allocation immediately and move the pivot as appropriate. 1099 * 1100 * If uaddr_pivot_newpivot() fails to find a new pivot that will allow the 1101 * allocation to succeed, it will not create a new pivot and the allocation 1102 * will fail. 1103 * 1104 * A pivot running into used memory will automatically expire (because it will 1105 * fail to allocate). 1106 * 1107 * Characteristics of the allocator: 1108 * - best case, an allocation is O(log N) 1109 * (it would be O(1), if it werent for the need to check if the memory is 1110 * free; although that can be avoided...) 1111 * - worst case, an allocation is O(log N) 1112 * (the uaddr_pivot_newpivot() function has that complexity) 1113 * - failed allocations always take O(log N) 1114 * (the uaddr_pivot_newpivot() function will walk that deep into the tree). 1115 */ 1116 int 1117 uaddr_pivot_select(struct vm_map *map, struct uvm_addr_state *uaddr_p, 1118 struct vm_map_entry **entry_out, vaddr_t *addr_out, 1119 vsize_t sz, vaddr_t align, vaddr_t offset, 1120 vm_prot_t prot, vaddr_t hint) 1121 { 1122 struct uaddr_pivot_state *uaddr; 1123 struct vm_map_entry *entry; 1124 struct uaddr_pivot *pivot; 1125 vaddr_t min, max; 1126 vsize_t before_gap, after_gap; 1127 int err; 1128 1129 /* 1130 * When we have a hint, use the rnd allocator that finds the 1131 * area that is closest to the hint, if there is such an area. 1132 */ 1133 if (hint != 0) { 1134 if (uaddr_rnd_select(map, uaddr_p, entry_out, addr_out, 1135 sz, align, offset, prot, hint) == 0) 1136 return 0; 1137 return ENOMEM; 1138 } 1139 1140 /* 1141 * Select a random pivot and a random gap sizes around the allocation. 1142 */ 1143 uaddr = (struct uaddr_pivot_state *)uaddr_p; 1144 pivot = &uaddr->up_pivots[ 1145 arc4random_uniform(nitems(uaddr->up_pivots))]; 1146 before_gap = uaddr_pivot_random(); 1147 after_gap = uaddr_pivot_random(); 1148 if (pivot->addr == 0 || pivot->entry == NULL || pivot->expire == 0) 1149 goto expired; /* Pivot is invalid (null or expired). */ 1150 1151 /* 1152 * Attempt to use the pivot to map the entry. 1153 */ 1154 entry = pivot->entry; 1155 if (pivot->dir > 0) { 1156 if (uvm_addr_fitspace(&min, &max, 1157 MAX(VMMAP_FREE_START(entry), pivot->addr), 1158 VMMAP_FREE_END(entry), sz, align, offset, 1159 before_gap, after_gap) == 0) { 1160 *addr_out = min; 1161 *entry_out = entry; 1162 pivot->addr = min + sz; 1163 pivot->expire--; 1164 return 0; 1165 } 1166 } else { 1167 if (uvm_addr_fitspace(&min, &max, 1168 VMMAP_FREE_START(entry), 1169 MIN(VMMAP_FREE_END(entry), pivot->addr), 1170 sz, align, offset, before_gap, after_gap) == 0) { 1171 *addr_out = max; 1172 *entry_out = entry; 1173 pivot->addr = max; 1174 pivot->expire--; 1175 return 0; 1176 } 1177 } 1178 1179 expired: 1180 /* 1181 * Pivot expired or allocation failed. 1182 * Use pivot selector to do the allocation and find a new pivot. 1183 */ 1184 err = uaddr_pivot_newpivot(map, uaddr, pivot, entry_out, addr_out, 1185 sz, align, offset, before_gap, after_gap); 1186 return err; 1187 } 1188 1189 /* 1190 * Free the pivot. 1191 */ 1192 void 1193 uaddr_pivot_destroy(struct uvm_addr_state *uaddr) 1194 { 1195 pool_put(&uaddr_pivot_pool, uaddr); 1196 } 1197 1198 /* 1199 * Insert an entry with free space in the space tree. 1200 */ 1201 void 1202 uaddr_pivot_insert(struct vm_map *map, struct uvm_addr_state *uaddr_p, 1203 struct vm_map_entry *entry) 1204 { 1205 struct uaddr_pivot_state *uaddr; 1206 struct vm_map_entry *rb_rv; 1207 struct uaddr_pivot *p; 1208 vaddr_t check_addr; 1209 vaddr_t start, end; 1210 1211 uaddr = (struct uaddr_pivot_state *)uaddr_p; 1212 if ((rb_rv = RBT_INSERT(uaddr_free_rbtree, &uaddr->up_free, entry)) != 1213 NULL) { 1214 panic("%s: duplicate insertion: state %p " 1215 "inserting entry %p which collides with %p", __func__, 1216 uaddr, entry, rb_rv); 1217 } 1218 1219 start = VMMAP_FREE_START(entry); 1220 end = VMMAP_FREE_END(entry); 1221 1222 /* 1223 * Update all pivots that are contained in this entry. 1224 */ 1225 for (p = &uaddr->up_pivots[0]; 1226 p != &uaddr->up_pivots[nitems(uaddr->up_pivots)]; p++) { 1227 check_addr = p->addr; 1228 if (check_addr == 0) 1229 continue; 1230 if (p->dir < 0) 1231 check_addr--; 1232 1233 if (start <= check_addr && 1234 check_addr < end) { 1235 KASSERT(p->entry == NULL); 1236 p->entry = entry; 1237 } 1238 } 1239 } 1240 1241 /* 1242 * Remove an entry with free space from the space tree. 1243 */ 1244 void 1245 uaddr_pivot_remove(struct vm_map *map, struct uvm_addr_state *uaddr_p, 1246 struct vm_map_entry *entry) 1247 { 1248 struct uaddr_pivot_state *uaddr; 1249 struct uaddr_pivot *p; 1250 1251 uaddr = (struct uaddr_pivot_state *)uaddr_p; 1252 if (RBT_REMOVE(uaddr_free_rbtree, &uaddr->up_free, entry) != entry) 1253 panic("%s: entry was not in tree", __func__); 1254 1255 /* 1256 * Inform any pivot with this entry that the entry is gone. 1257 * Note that this does not automatically invalidate the pivot. 1258 */ 1259 for (p = &uaddr->up_pivots[0]; 1260 p != &uaddr->up_pivots[nitems(uaddr->up_pivots)]; p++) { 1261 if (p->entry == entry) 1262 p->entry = NULL; 1263 } 1264 } 1265 1266 /* 1267 * Create a new pivot selector. 1268 * 1269 * Initially, all pivots are in the expired state. 1270 * Two reasons for this: 1271 * - it means this allocator will not take a huge amount of time 1272 * - pivots select better on demand, because the pivot selection will be 1273 * affected by preceding allocations: 1274 * the next pivots will likely end up in different segments of free memory, 1275 * that was segmented by an earlier allocation; better spread. 1276 */ 1277 struct uvm_addr_state * 1278 uaddr_pivot_create(vaddr_t minaddr, vaddr_t maxaddr) 1279 { 1280 struct uaddr_pivot_state *uaddr; 1281 1282 uaddr = pool_get(&uaddr_pivot_pool, PR_WAITOK); 1283 uaddr->up_uaddr.uaddr_minaddr = minaddr; 1284 uaddr->up_uaddr.uaddr_maxaddr = maxaddr; 1285 uaddr->up_uaddr.uaddr_functions = &uaddr_pivot_functions; 1286 RBT_INIT(uaddr_free_rbtree, &uaddr->up_free); 1287 memset(uaddr->up_pivots, 0, sizeof(uaddr->up_pivots)); 1288 1289 return &uaddr->up_uaddr; 1290 } 1291 1292 #if defined(DEBUG) || defined(DDB) 1293 /* 1294 * Print the uaddr_pivot_state. 1295 * 1296 * If full, a listing of all entries in the state will be provided. 1297 */ 1298 void 1299 uaddr_pivot_print(struct uvm_addr_state *uaddr_p, boolean_t full, 1300 int (*pr)(const char *, ...)) 1301 { 1302 struct uaddr_pivot_state *uaddr; 1303 struct uaddr_pivot *pivot; 1304 struct vm_map_entry *entry; 1305 int i; 1306 vaddr_t check_addr; 1307 1308 uaddr = (struct uaddr_pivot_state *)uaddr_p; 1309 1310 for (i = 0; i < NUM_PIVOTS; i++) { 1311 pivot = &uaddr->up_pivots[i]; 1312 1313 (*pr)("\tpivot 0x%lx, epires in %d, direction %d\n", 1314 pivot->addr, pivot->expire, pivot->dir); 1315 } 1316 if (!full) 1317 return; 1318 1319 if (RBT_EMPTY(uaddr_free_rbtree, &uaddr->up_free)) 1320 (*pr)("\tempty\n"); 1321 /* Print list of free space. */ 1322 RBT_FOREACH(entry, uaddr_free_rbtree, &uaddr->up_free) { 1323 (*pr)("\t0x%lx - 0x%lx free (0x%lx bytes)\n", 1324 VMMAP_FREE_START(entry), VMMAP_FREE_END(entry), 1325 VMMAP_FREE_END(entry) - VMMAP_FREE_START(entry)); 1326 1327 for (i = 0; i < NUM_PIVOTS; i++) { 1328 pivot = &uaddr->up_pivots[i]; 1329 check_addr = pivot->addr; 1330 if (check_addr == 0) 1331 continue; 1332 if (pivot->dir < 0) 1333 check_addr--; 1334 1335 if (VMMAP_FREE_START(entry) <= check_addr && 1336 check_addr < VMMAP_FREE_END(entry)) { 1337 (*pr)("\t\tcontains pivot %d (0x%lx)\n", 1338 i, pivot->addr); 1339 } 1340 } 1341 } 1342 } 1343 #endif /* DEBUG || DDB */ 1344 #endif /* !SMALL_KERNEL */ 1345 1346 #ifndef SMALL_KERNEL 1347 /* 1348 * Stack/break allocator. 1349 * 1350 * Stack area is grown into in the opposite direction of the stack growth, 1351 * brk area is grown downward (because sbrk() grows upward). 1352 * 1353 * Both areas are grown into proportially: a weighted chance is used to 1354 * select which one (stack or brk area) to try. If the allocation fails, 1355 * the other one is tested. 1356 */ 1357 const struct uvm_addr_functions uaddr_stack_brk_functions = { 1358 .uaddr_select = &uaddr_stack_brk_select, 1359 .uaddr_destroy = &uaddr_destroy, 1360 .uaddr_name = "uaddr_stckbrk" 1361 }; 1362 1363 /* 1364 * Stack/brk address selector. 1365 */ 1366 int 1367 uaddr_stack_brk_select(struct vm_map *map, struct uvm_addr_state *uaddr, 1368 struct vm_map_entry **entry_out, vaddr_t *addr_out, 1369 vsize_t sz, vaddr_t align, vaddr_t offset, 1370 vm_prot_t prot, vaddr_t hint) 1371 { 1372 vaddr_t start; 1373 vaddr_t end; 1374 vsize_t before_gap; 1375 vsize_t after_gap; 1376 int dir; 1377 1378 /* Set up brk search strategy. */ 1379 start = MAX(map->b_start, uaddr->uaddr_minaddr); 1380 end = MIN(map->b_end, uaddr->uaddr_maxaddr); 1381 before_gap = 0; 1382 after_gap = 0; 1383 dir = -1; /* Opposite of brk() growth. */ 1384 1385 if (end - start >= sz) { 1386 if (uvm_addr_linsearch(map, uaddr, entry_out, addr_out, 1387 0, sz, align, offset, dir, start, end - sz, 1388 before_gap, after_gap) == 0) 1389 return 0; 1390 } 1391 1392 /* Set up stack search strategy. */ 1393 start = MAX(map->s_start, uaddr->uaddr_minaddr); 1394 end = MIN(map->s_end, uaddr->uaddr_maxaddr); 1395 before_gap = ((arc4random() & 0x3) + 1) << PAGE_SHIFT; 1396 after_gap = ((arc4random() & 0x3) + 1) << PAGE_SHIFT; 1397 #ifdef MACHINE_STACK_GROWS_UP 1398 dir = -1; 1399 #else 1400 dir = 1; 1401 #endif 1402 if (end - start >= before_gap + after_gap && 1403 end - start - before_gap - after_gap >= sz) { 1404 if (uvm_addr_linsearch(map, uaddr, entry_out, addr_out, 1405 0, sz, align, offset, dir, start, end - sz, 1406 before_gap, after_gap) == 0) 1407 return 0; 1408 } 1409 1410 return ENOMEM; 1411 } 1412 1413 struct uvm_addr_state * 1414 uaddr_stack_brk_create(vaddr_t minaddr, vaddr_t maxaddr) 1415 { 1416 struct uvm_addr_state* uaddr; 1417 1418 uaddr = pool_get(&uaddr_pool, PR_WAITOK); 1419 uaddr->uaddr_minaddr = minaddr; 1420 uaddr->uaddr_maxaddr = maxaddr; 1421 uaddr->uaddr_functions = &uaddr_stack_brk_functions; 1422 return uaddr; 1423 } 1424 #endif /* !SMALL_KERNEL */ 1425 1426 1427 #ifndef SMALL_KERNEL 1428 /* 1429 * Free space comparison. 1430 * Compares smaller free-space before larger free-space. 1431 */ 1432 static inline int 1433 uvm_mapent_fspace_cmp(const struct vm_map_entry *e1, 1434 const struct vm_map_entry *e2) 1435 { 1436 if (e1->fspace != e2->fspace) 1437 return (e1->fspace < e2->fspace ? -1 : 1); 1438 return (e1->start < e2->start ? -1 : e1->start > e2->start); 1439 } 1440 1441 RBT_GENERATE(uaddr_free_rbtree, vm_map_entry, dfree.rbtree, 1442 uvm_mapent_fspace_cmp); 1443 #endif /* !SMALL_KERNEL */ 1444