|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1991 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * The Mach Operating System project at Carnegie-Mellon University. ! 7: * ! 8: * Redistribution and use in source and binary forms, with or without ! 9: * modification, are permitted provided that the following conditions ! 10: * are met: ! 11: * 1. Redistributions of source code must retain the above copyright ! 12: * notice, this list of conditions and the following disclaimer. ! 13: * 2. Redistributions in binary form must reproduce the above copyright ! 14: * notice, this list of conditions and the following disclaimer in the ! 15: * documentation and/or other materials provided with the distribution. ! 16: * 3. All advertising materials mentioning features or use of this software ! 17: * must display the following acknowledgement: ! 18: * This product includes software developed by the University of ! 19: * California, Berkeley and its contributors. ! 20: * 4. Neither the name of the University nor the names of its contributors ! 21: * may be used to endorse or promote products derived from this software ! 22: * without specific prior written permission. ! 23: * ! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 34: * SUCH DAMAGE. ! 35: * ! 36: * @(#)vm_kern.c 7.4 (Berkeley) 5/7/91 ! 37: * ! 38: * ! 39: * Copyright (c) 1987, 1990 Carnegie-Mellon University. ! 40: * All rights reserved. ! 41: * ! 42: * Authors: Avadis Tevanian, Jr., Michael Wayne Young ! 43: * ! 44: * Permission to use, copy, modify and distribute this software and ! 45: * its documentation is hereby granted, provided that both the copyright ! 46: * notice and this permission notice appear in all copies of the ! 47: * software, derivative works or modified versions, and any portions ! 48: * thereof, and that both notices appear in supporting documentation. ! 49: * ! 50: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 51: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND ! 52: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 53: * ! 54: * Carnegie Mellon requests users of this software to return to ! 55: * ! 56: * Software Distribution Coordinator or [email protected] ! 57: * School of Computer Science ! 58: * Carnegie Mellon University ! 59: * Pittsburgh PA 15213-3890 ! 60: * ! 61: * any improvements or extensions that they make and grant Carnegie the ! 62: * rights to redistribute these changes. ! 63: */ ! 64: ! 65: /* ! 66: * Kernel memory management. ! 67: */ ! 68: ! 69: #include "param.h" ! 70: ! 71: #include "vm.h" ! 72: #include "vm_page.h" ! 73: #include "vm_pageout.h" ! 74: #include "vm_kern.h" ! 75: ! 76: /* ! 77: * kmem_alloc_pageable: ! 78: * ! 79: * Allocate pageable memory to the kernel's address map. ! 80: * map must be "kernel_map" below. ! 81: */ ! 82: ! 83: vm_offset_t kmem_alloc_pageable(map, size) ! 84: vm_map_t map; ! 85: register vm_size_t size; ! 86: { ! 87: vm_offset_t addr; ! 88: register int result; ! 89: ! 90: #if 0 ! 91: if (map != kernel_map) ! 92: panic("kmem_alloc_pageable: not called with kernel_map"); ! 93: #endif 0 ! 94: ! 95: size = round_page(size); ! 96: ! 97: addr = vm_map_min(map); ! 98: result = vm_map_find(map, NULL, (vm_offset_t) 0, ! 99: &addr, size, TRUE); ! 100: if (result != KERN_SUCCESS) { ! 101: return(0); ! 102: } ! 103: ! 104: return(addr); ! 105: } ! 106: ! 107: /* ! 108: * Allocate wired-down memory in the kernel's address map ! 109: * or a submap. ! 110: */ ! 111: vm_offset_t kmem_alloc(map, size) ! 112: register vm_map_t map; ! 113: register vm_size_t size; ! 114: { ! 115: vm_offset_t addr; ! 116: register int result; ! 117: register vm_offset_t offset; ! 118: extern vm_object_t kernel_object; ! 119: vm_offset_t i; ! 120: ! 121: size = round_page(size); ! 122: ! 123: /* ! 124: * Use the kernel object for wired-down kernel pages. ! 125: * Assume that no region of the kernel object is ! 126: * referenced more than once. ! 127: */ ! 128: ! 129: addr = vm_map_min(map); ! 130: result = vm_map_find(map, NULL, (vm_offset_t) 0, ! 131: &addr, size, TRUE); ! 132: if (result != KERN_SUCCESS) { ! 133: return(0); ! 134: } ! 135: ! 136: /* ! 137: * Since we didn't know where the new region would ! 138: * start, we couldn't supply the correct offset into ! 139: * the kernel object. Re-allocate that address ! 140: * region with the correct offset. ! 141: */ ! 142: ! 143: offset = addr - VM_MIN_KERNEL_ADDRESS; ! 144: vm_object_reference(kernel_object); ! 145: ! 146: vm_map_lock(map); ! 147: vm_map_delete(map, addr, addr + size); ! 148: vm_map_insert(map, kernel_object, offset, addr, addr + size); ! 149: vm_map_unlock(map); ! 150: ! 151: /* ! 152: * Guarantee that there are pages already in this object ! 153: * before calling vm_map_pageable. This is to prevent the ! 154: * following scenario: ! 155: * ! 156: * 1) Threads have swapped out, so that there is a ! 157: * pager for the kernel_object. ! 158: * 2) The kmsg zone is empty, and so we are kmem_allocing ! 159: * a new page for it. ! 160: * 3) vm_map_pageable calls vm_fault; there is no page, ! 161: * but there is a pager, so we call ! 162: * pager_data_request. But the kmsg zone is empty, ! 163: * so we must kmem_alloc. ! 164: * 4) goto 1 ! 165: * 5) Even if the kmsg zone is not empty: when we get ! 166: * the data back from the pager, it will be (very ! 167: * stale) non-zero data. kmem_alloc is defined to ! 168: * return zero-filled memory. ! 169: * ! 170: * We're intentionally not activating the pages we allocate ! 171: * to prevent a race with page-out. vm_map_pageable will wire ! 172: * the pages. ! 173: */ ! 174: ! 175: vm_object_lock(kernel_object); ! 176: for (i = 0 ; i < size; i+= PAGE_SIZE) { ! 177: vm_page_t mem; ! 178: ! 179: while ((mem = vm_page_alloc(kernel_object, offset+i)) == NULL) { ! 180: vm_object_unlock(kernel_object); ! 181: VM_WAIT; ! 182: vm_object_lock(kernel_object); ! 183: } ! 184: vm_page_zero_fill(mem); ! 185: mem->busy = FALSE; ! 186: } ! 187: vm_object_unlock(kernel_object); ! 188: ! 189: /* ! 190: * And finally, mark the data as non-pageable. ! 191: */ ! 192: ! 193: (void) vm_map_pageable(map, (vm_offset_t) addr, addr + size, FALSE); ! 194: ! 195: /* ! 196: * Try to coalesce the map ! 197: */ ! 198: ! 199: vm_map_simplify(map, addr); ! 200: ! 201: return(addr); ! 202: } ! 203: ! 204: /* ! 205: * kmem_free: ! 206: * ! 207: * Release a region of kernel virtual memory allocated ! 208: * with kmem_alloc, and return the physical pages ! 209: * associated with that region. ! 210: */ ! 211: void kmem_free(map, addr, size) ! 212: vm_map_t map; ! 213: register vm_offset_t addr; ! 214: vm_size_t size; ! 215: { ! 216: (void) vm_map_remove(map, trunc_page(addr), round_page(addr + size)); ! 217: } ! 218: ! 219: /* ! 220: * kmem_suballoc: ! 221: * ! 222: * Allocates a map to manage a subrange ! 223: * of the kernel virtual address space. ! 224: * ! 225: * Arguments are as follows: ! 226: * ! 227: * parent Map to take range from ! 228: * size Size of range to find ! 229: * min, max Returned endpoints of map ! 230: * pageable Can the region be paged ! 231: */ ! 232: vm_map_t kmem_suballoc(parent, min, max, size, pageable) ! 233: register vm_map_t parent; ! 234: vm_offset_t *min, *max; ! 235: register vm_size_t size; ! 236: boolean_t pageable; ! 237: { ! 238: register int ret; ! 239: vm_map_t result; ! 240: ! 241: size = round_page(size); ! 242: ! 243: *min = (vm_offset_t) vm_map_min(parent); ! 244: ret = vm_map_find(parent, NULL, (vm_offset_t) 0, ! 245: min, size, TRUE); ! 246: if (ret != KERN_SUCCESS) { ! 247: printf("kmem_suballoc: bad status return of %d.\n", ret); ! 248: panic("kmem_suballoc"); ! 249: } ! 250: *max = *min + size; ! 251: pmap_reference(vm_map_pmap(parent)); ! 252: result = vm_map_create(vm_map_pmap(parent), *min, *max, pageable); ! 253: if (result == NULL) ! 254: panic("kmem_suballoc: cannot create submap"); ! 255: if ((ret = vm_map_submap(parent, *min, *max, result)) != KERN_SUCCESS) ! 256: panic("kmem_suballoc: unable to change range to submap"); ! 257: return(result); ! 258: } ! 259: ! 260: /* ! 261: * vm_move: ! 262: * ! 263: * Move memory from source to destination map, possibly deallocating ! 264: * the source map reference to the memory. ! 265: * ! 266: * Parameters are as follows: ! 267: * ! 268: * src_map Source address map ! 269: * src_addr Address within source map ! 270: * dst_map Destination address map ! 271: * num_bytes Amount of data (in bytes) to copy/move ! 272: * src_dealloc Should source be removed after copy? ! 273: * ! 274: * Assumes the src and dst maps are not already locked. ! 275: * ! 276: * Returns new destination address or 0 (if a failure occurs). ! 277: */ ! 278: vm_offset_t vm_move(src_map,src_addr,dst_map,num_bytes,src_dealloc) ! 279: vm_map_t src_map; ! 280: register vm_offset_t src_addr; ! 281: register vm_map_t dst_map; ! 282: vm_offset_t num_bytes; ! 283: boolean_t src_dealloc; ! 284: { ! 285: register vm_offset_t src_start; /* Beginning of region */ ! 286: register vm_size_t src_size; /* Size of rounded region */ ! 287: vm_offset_t dst_start; /* destination address */ ! 288: register int result; ! 289: ! 290: /* ! 291: * Page-align the source region ! 292: */ ! 293: ! 294: src_start = trunc_page(src_addr); ! 295: src_size = round_page(src_addr + num_bytes) - src_start; ! 296: ! 297: /* ! 298: * If there's no destination, we can be at most deallocating ! 299: * the source range. ! 300: */ ! 301: if (dst_map == NULL) { ! 302: if (src_dealloc) ! 303: if (vm_deallocate(src_map, src_start, src_size) ! 304: != KERN_SUCCESS) { ! 305: printf("vm_move: deallocate of source"); ! 306: printf(" failed, dealloc_only clause\n"); ! 307: } ! 308: return(0); ! 309: } ! 310: ! 311: /* ! 312: * Allocate a place to put the copy ! 313: */ ! 314: ! 315: dst_start = (vm_offset_t) 0; ! 316: if ((result = vm_allocate(dst_map, &dst_start, src_size, TRUE)) ! 317: == KERN_SUCCESS) { ! 318: /* ! 319: * Perform the copy, asking for deallocation if desired ! 320: */ ! 321: result = vm_map_copy(dst_map, src_map, dst_start, src_size, ! 322: src_start, FALSE, src_dealloc); ! 323: } ! 324: ! 325: /* ! 326: * Return the destination address corresponding to ! 327: * the source address given (rather than the front ! 328: * of the newly-allocated page). ! 329: */ ! 330: ! 331: if (result == KERN_SUCCESS) ! 332: return(dst_start + (src_addr - src_start)); ! 333: return(0); ! 334: } ! 335: ! 336: /* ! 337: * Allocate wired-down memory in the kernel's address map for the higher ! 338: * level kernel memory allocator (kern/kern_malloc.c). We cannot use ! 339: * kmem_alloc() because we may need to allocate memory at interrupt ! 340: * level where we cannot block (canwait == FALSE). ! 341: * ! 342: * This routine has its own private kernel submap (kmem_map) and object ! 343: * (kmem_object). This, combined with the fact that only malloc uses ! 344: * this routine, ensures that we will never block in map or object waits. ! 345: * ! 346: * Note that this still only works in a uni-processor environment and ! 347: * when called at splhigh(). ! 348: * ! 349: * We don't worry about expanding the map (adding entries) since entries ! 350: * for wired maps are statically allocated. ! 351: */ ! 352: vm_offset_t ! 353: kmem_malloc(map, size, canwait) ! 354: register vm_map_t map; ! 355: register vm_size_t size; ! 356: boolean_t canwait; ! 357: { ! 358: register vm_offset_t offset, i; ! 359: vm_map_entry_t entry; ! 360: vm_offset_t addr; ! 361: vm_page_t m; ! 362: extern vm_object_t kmem_object; ! 363: ! 364: if (map != kmem_map && map != mb_map) ! 365: panic("kern_malloc_alloc: map != {kmem,mb}_map"); ! 366: ! 367: size = round_page(size); ! 368: addr = vm_map_min(map); ! 369: ! 370: if (vm_map_find(map, NULL, (vm_offset_t)0, ! 371: &addr, size, TRUE) != KERN_SUCCESS) { ! 372: if (canwait) ! 373: panic("kmem_malloc: kmem_map too small"); ! 374: return(0); ! 375: } ! 376: ! 377: /* ! 378: * Since we didn't know where the new region would start, ! 379: * we couldn't supply the correct offset into the kmem object. ! 380: * Re-allocate that address region with the correct offset. ! 381: */ ! 382: offset = addr - vm_map_min(kmem_map); ! 383: vm_object_reference(kmem_object); ! 384: ! 385: vm_map_lock(map); ! 386: vm_map_delete(map, addr, addr + size); ! 387: vm_map_insert(map, kmem_object, offset, addr, addr + size); ! 388: ! 389: /* ! 390: * If we can wait, just mark the range as wired ! 391: * (will fault pages as necessary). ! 392: */ ! 393: if (canwait) { ! 394: vm_map_unlock(map); ! 395: (void) vm_map_pageable(map, (vm_offset_t) addr, addr + size, ! 396: FALSE); ! 397: vm_map_simplify(map, addr); ! 398: return(addr); ! 399: } ! 400: ! 401: /* ! 402: * If we cannot wait then we must allocate all memory up front, ! 403: * pulling it off the active queue to prevent pageout. ! 404: */ ! 405: vm_object_lock(kmem_object); ! 406: for (i = 0; i < size; i += PAGE_SIZE) { ! 407: m = vm_page_alloc(kmem_object, offset + i); ! 408: ! 409: /* ! 410: * Ran out of space, free everything up and return. ! 411: * Don't need to lock page queues here as we know ! 412: * that the pages we got aren't on any queues. ! 413: */ ! 414: if (m == NULL) { ! 415: while (i != 0) { ! 416: i -= PAGE_SIZE; ! 417: m = vm_page_lookup(kmem_object, offset + i); ! 418: vm_page_free(m); ! 419: } ! 420: vm_object_unlock(kmem_object); ! 421: vm_map_delete(map, addr, addr + size); ! 422: vm_map_unlock(map); ! 423: return(0); ! 424: } ! 425: #if 0 ! 426: vm_page_zero_fill(m); ! 427: #endif ! 428: m->busy = FALSE; ! 429: } ! 430: vm_object_unlock(kmem_object); ! 431: ! 432: /* ! 433: * Mark map entry as non-pageable. ! 434: * Assert: vm_map_insert() will never be able to extend the previous ! 435: * entry so there will be a new entry exactly corresponding to this ! 436: * address range and it will have wired_count == 0. ! 437: */ ! 438: if (!vm_map_lookup_entry(map, addr, &entry) || ! 439: entry->start != addr || entry->end != addr + size || ! 440: entry->wired_count) ! 441: panic("kmem_malloc: entry not found or misaligned"); ! 442: entry->wired_count++; ! 443: ! 444: /* ! 445: * Loop thru pages, entering them in the pmap. ! 446: * (We cannot add them to the wired count without ! 447: * wrapping the vm_page_queue_lock in splimp...) ! 448: */ ! 449: for (i = 0; i < size; i += PAGE_SIZE) { ! 450: vm_object_lock(kmem_object); ! 451: m = vm_page_lookup(kmem_object, offset + i); ! 452: vm_object_unlock(kmem_object); ! 453: pmap_enter(map->pmap, addr + i, VM_PAGE_TO_PHYS(m), ! 454: VM_PROT_DEFAULT, TRUE); ! 455: } ! 456: vm_map_unlock(map); ! 457: ! 458: vm_map_simplify(map, addr); ! 459: return(addr); ! 460: } ! 461: ! 462: /* ! 463: * kmem_alloc_wait ! 464: * ! 465: * Allocates pageable memory from a sub-map of the kernel. If the submap ! 466: * has no room, the caller sleeps waiting for more memory in the submap. ! 467: * ! 468: */ ! 469: vm_offset_t kmem_alloc_wait(map, size) ! 470: vm_map_t map; ! 471: vm_size_t size; ! 472: { ! 473: vm_offset_t addr; ! 474: int result; ! 475: ! 476: size = round_page(size); ! 477: ! 478: do { ! 479: /* ! 480: * To make this work for more than one map, ! 481: * use the map's lock to lock out sleepers/wakers. ! 482: * Unfortunately, vm_map_find also grabs the map lock. ! 483: */ ! 484: vm_map_lock(map); ! 485: lock_set_recursive(&map->lock); ! 486: ! 487: addr = vm_map_min(map); ! 488: result = vm_map_find(map, NULL, (vm_offset_t) 0, ! 489: &addr, size, TRUE); ! 490: ! 491: lock_clear_recursive(&map->lock); ! 492: if (result != KERN_SUCCESS) { ! 493: ! 494: if ( (vm_map_max(map) - vm_map_min(map)) < size ) { ! 495: vm_map_unlock(map); ! 496: return(0); ! 497: } ! 498: ! 499: assert_wait((int)map, TRUE); ! 500: vm_map_unlock(map); ! 501: thread_block(); ! 502: } ! 503: else { ! 504: vm_map_unlock(map); ! 505: } ! 506: ! 507: } while (result != KERN_SUCCESS); ! 508: ! 509: return(addr); ! 510: } ! 511: ! 512: /* ! 513: * kmem_free_wakeup ! 514: * ! 515: * Returns memory to a submap of the kernel, and wakes up any threads ! 516: * waiting for memory in that map. ! 517: */ ! 518: void kmem_free_wakeup(map, addr, size) ! 519: vm_map_t map; ! 520: vm_offset_t addr; ! 521: vm_size_t size; ! 522: { ! 523: vm_map_lock(map); ! 524: (void) vm_map_delete(map, trunc_page(addr), round_page(addr + size)); ! 525: thread_wakeup((int)map); ! 526: vm_map_unlock(map); ! 527: } ! 528: ! 529: /* ! 530: * kmem_init: ! 531: * ! 532: * Initialize the kernel's virtual memory map, taking ! 533: * into account all memory allocated up to this time. ! 534: */ ! 535: void kmem_init(start, end) ! 536: vm_offset_t start; ! 537: vm_offset_t end; ! 538: { ! 539: vm_offset_t addr; ! 540: extern vm_map_t kernel_map; ! 541: ! 542: addr = VM_MIN_KERNEL_ADDRESS; ! 543: kernel_map = vm_map_create(pmap_kernel(), addr, end, FALSE); ! 544: (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0, ! 545: &addr, (start - VM_MIN_KERNEL_ADDRESS), ! 546: FALSE); ! 547: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.