|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: vm/vm_kern.c ! 31: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 32: * Date: 1985 ! 33: * ! 34: * Kernel memory management. ! 35: */ ! 36: ! 37: #include <mach/kern_return.h> ! 38: #include "vm_param.h" ! 39: #include <kern/assert.h> ! 40: #include <kern/lock.h> ! 41: #include <kern/thread.h> ! 42: #include <vm/vm_fault.h> ! 43: #include <vm/vm_kern.h> ! 44: #include <vm/vm_map.h> ! 45: #include <vm/vm_object.h> ! 46: #include <vm/vm_page.h> ! 47: #include <vm/vm_pageout.h> ! 48: ! 49: ! 50: ! 51: /* ! 52: * Variables exported by this module. ! 53: */ ! 54: ! 55: vm_map_t kernel_map; ! 56: vm_map_t kernel_pageable_map; ! 57: ! 58: extern void kmem_alloc_pages(); ! 59: extern void kmem_remap_pages(); ! 60: ! 61: /* ! 62: * projected_buffer_allocate ! 63: * ! 64: * Allocate a wired-down buffer shared between kernel and user task. ! 65: * Fresh, zero-filled memory is allocated. ! 66: * If persistence is false, this buffer can only be deallocated from ! 67: * user task using projected_buffer_deallocate, and deallocation ! 68: * from user task also deallocates the buffer from the kernel map. ! 69: * projected_buffer_collect is called from vm_map_deallocate to ! 70: * automatically deallocate projected buffers on task_deallocate. ! 71: * Sharing with more than one user task is achieved by using ! 72: * projected_buffer_map for the second and subsequent tasks. ! 73: * The user is precluded from manipulating the VM entry of this buffer ! 74: * (i.e. changing protection, inheritance or machine attributes). ! 75: */ ! 76: ! 77: kern_return_t ! 78: projected_buffer_allocate(map, size, persistence, kernel_p, ! 79: user_p, protection, inheritance) ! 80: vm_map_t map; ! 81: vm_size_t size; ! 82: int persistence; ! 83: vm_offset_t *kernel_p; ! 84: vm_offset_t *user_p; ! 85: vm_prot_t protection; ! 86: vm_inherit_t inheritance; /*Currently only VM_INHERIT_NONE supported*/ ! 87: { ! 88: vm_object_t object; ! 89: vm_map_entry_t u_entry, k_entry; ! 90: vm_offset_t addr; ! 91: vm_size_t r_size; ! 92: kern_return_t kr; ! 93: ! 94: if (map == VM_MAP_NULL || map == kernel_map) ! 95: return(KERN_INVALID_ARGUMENT); ! 96: ! 97: /* ! 98: * Allocate a new object. ! 99: */ ! 100: ! 101: size = round_page(size); ! 102: object = vm_object_allocate(size); ! 103: ! 104: vm_map_lock(kernel_map); ! 105: kr = vm_map_find_entry(kernel_map, &addr, size, (vm_offset_t) 0, ! 106: VM_OBJECT_NULL, &k_entry); ! 107: if (kr != KERN_SUCCESS) { ! 108: vm_map_unlock(kernel_map); ! 109: vm_object_deallocate(object); ! 110: return kr; ! 111: } ! 112: ! 113: k_entry->object.vm_object = object; ! 114: if (!persistence) ! 115: k_entry->projected_on = (vm_map_entry_t) -1; ! 116: /*Mark entry so as to automatically deallocate it when ! 117: last corresponding user entry is deallocated*/ ! 118: vm_map_unlock(kernel_map); ! 119: *kernel_p = addr; ! 120: ! 121: vm_map_lock(map); ! 122: kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0, ! 123: VM_OBJECT_NULL, &u_entry); ! 124: if (kr != KERN_SUCCESS) { ! 125: vm_map_unlock(map); ! 126: vm_map_lock(kernel_map); ! 127: vm_map_entry_delete(kernel_map, k_entry); ! 128: vm_map_unlock(kernel_map); ! 129: vm_object_deallocate(object); ! 130: return kr; ! 131: } ! 132: ! 133: u_entry->object.vm_object = object; ! 134: vm_object_reference(object); ! 135: u_entry->projected_on = k_entry; ! 136: /*Creates coupling with kernel mapping of the buffer, and ! 137: also guarantees that user cannot directly manipulate ! 138: buffer VM entry*/ ! 139: u_entry->protection = protection; ! 140: u_entry->max_protection = protection; ! 141: u_entry->inheritance = inheritance; ! 142: vm_map_unlock(map); ! 143: *user_p = addr; ! 144: ! 145: /* ! 146: * Allocate wired-down memory in the object, ! 147: * and enter it in the kernel pmap. ! 148: */ ! 149: kmem_alloc_pages(object, 0, ! 150: *kernel_p, *kernel_p + size, ! 151: VM_PROT_READ | VM_PROT_WRITE); ! 152: bzero(*kernel_p, size); /*Zero fill*/ ! 153: ! 154: /* Set up physical mappings for user pmap */ ! 155: ! 156: pmap_pageable(map->pmap, *user_p, *user_p + size, FALSE); ! 157: for (r_size = 0; r_size < size; r_size += PAGE_SIZE) { ! 158: addr = pmap_extract(kernel_pmap, *kernel_p + r_size); ! 159: pmap_enter(map->pmap, *user_p + r_size, addr, ! 160: protection, TRUE); ! 161: } ! 162: ! 163: return(KERN_SUCCESS); ! 164: } ! 165: ! 166: ! 167: /* ! 168: * projected_buffer_map ! 169: * ! 170: * Map an area of kernel memory onto a task's address space. ! 171: * No new memory is allocated; the area must previously exist in the ! 172: * kernel memory map. ! 173: */ ! 174: ! 175: kern_return_t ! 176: projected_buffer_map(map, kernel_addr, size, user_p, protection, inheritance) ! 177: vm_map_t map; ! 178: vm_offset_t kernel_addr; ! 179: vm_size_t size; ! 180: vm_offset_t *user_p; ! 181: vm_prot_t protection; ! 182: vm_inherit_t inheritance; /*Currently only VM_INHERIT_NONE supported*/ ! 183: { ! 184: vm_object_t object; ! 185: vm_map_entry_t u_entry, k_entry; ! 186: vm_offset_t physical_addr, user_addr; ! 187: vm_size_t r_size; ! 188: kern_return_t kr; ! 189: ! 190: /* ! 191: * Find entry in kernel map ! 192: */ ! 193: ! 194: size = round_page(size); ! 195: if (map == VM_MAP_NULL || map == kernel_map || ! 196: !vm_map_lookup_entry(kernel_map, kernel_addr, &k_entry) || ! 197: kernel_addr + size > k_entry->vme_end) ! 198: return(KERN_INVALID_ARGUMENT); ! 199: ! 200: ! 201: /* ! 202: * Create entry in user task ! 203: */ ! 204: ! 205: vm_map_lock(map); ! 206: kr = vm_map_find_entry(map, &user_addr, size, (vm_offset_t) 0, ! 207: VM_OBJECT_NULL, &u_entry); ! 208: if (kr != KERN_SUCCESS) { ! 209: vm_map_unlock(map); ! 210: return kr; ! 211: } ! 212: ! 213: u_entry->object.vm_object = k_entry->object.vm_object; ! 214: vm_object_reference(k_entry->object.vm_object); ! 215: u_entry->offset = kernel_addr - k_entry->vme_start + k_entry->offset; ! 216: u_entry->projected_on = k_entry; ! 217: /*Creates coupling with kernel mapping of the buffer, and ! 218: also guarantees that user cannot directly manipulate ! 219: buffer VM entry*/ ! 220: u_entry->protection = protection; ! 221: u_entry->max_protection = protection; ! 222: u_entry->inheritance = inheritance; ! 223: u_entry->wired_count = k_entry->wired_count; ! 224: vm_map_unlock(map); ! 225: *user_p = user_addr; ! 226: ! 227: /* Set up physical mappings for user pmap */ ! 228: ! 229: pmap_pageable(map->pmap, user_addr, user_addr + size, ! 230: !k_entry->wired_count); ! 231: for (r_size = 0; r_size < size; r_size += PAGE_SIZE) { ! 232: physical_addr = pmap_extract(kernel_pmap, kernel_addr + r_size); ! 233: pmap_enter(map->pmap, user_addr + r_size, physical_addr, ! 234: protection, k_entry->wired_count); ! 235: } ! 236: ! 237: return(KERN_SUCCESS); ! 238: } ! 239: ! 240: ! 241: /* ! 242: * projected_buffer_deallocate ! 243: * ! 244: * Unmap projected buffer from task's address space. ! 245: * May also unmap buffer from kernel map, if buffer is not ! 246: * persistent and only the kernel reference remains. ! 247: */ ! 248: ! 249: kern_return_t ! 250: projected_buffer_deallocate(map, start, end) ! 251: vm_map_t map; ! 252: vm_offset_t start, end; ! 253: { ! 254: vm_map_entry_t entry, k_entry; ! 255: ! 256: vm_map_lock(map); ! 257: if (map == VM_MAP_NULL || map == kernel_map || ! 258: !vm_map_lookup_entry(map, start, &entry) || ! 259: end > entry->vme_end || ! 260: /*Check corresponding kernel entry*/ ! 261: (k_entry = entry->projected_on) == 0) { ! 262: vm_map_unlock(map); ! 263: return(KERN_INVALID_ARGUMENT); ! 264: } ! 265: ! 266: /*Prepare for deallocation*/ ! 267: if (entry->vme_start < start) ! 268: _vm_map_clip_start(map, entry, start); ! 269: if (entry->vme_end > end) ! 270: _vm_map_clip_end(map, entry, end); ! 271: if (map->first_free == entry) /*Adjust first_free hint*/ ! 272: map->first_free = entry->vme_prev; ! 273: entry->projected_on = 0; /*Needed to allow deletion*/ ! 274: entry->wired_count = 0; /*Avoid unwire fault*/ ! 275: vm_map_entry_delete(map, entry); ! 276: vm_map_unlock(map); ! 277: ! 278: /*Check if the buffer is not persistent and only the ! 279: kernel mapping remains, and if so delete it*/ ! 280: vm_map_lock(kernel_map); ! 281: if (k_entry->projected_on == (vm_map_entry_t) -1 && ! 282: k_entry->object.vm_object->ref_count == 1) { ! 283: if (kernel_map->first_free == k_entry) ! 284: kernel_map->first_free = k_entry->vme_prev; ! 285: k_entry->projected_on = 0; /*Allow unwire fault*/ ! 286: vm_map_entry_delete(kernel_map, k_entry); ! 287: } ! 288: vm_map_unlock(kernel_map); ! 289: return(KERN_SUCCESS); ! 290: } ! 291: ! 292: ! 293: /* ! 294: * projected_buffer_collect ! 295: * ! 296: * Unmap all projected buffers from task's address space. ! 297: */ ! 298: ! 299: kern_return_t ! 300: projected_buffer_collect(map) ! 301: vm_map_t map; ! 302: { ! 303: vm_map_entry_t entry, next; ! 304: ! 305: if (map == VM_MAP_NULL || map == kernel_map) ! 306: return(KERN_INVALID_ARGUMENT); ! 307: ! 308: for (entry = vm_map_first_entry(map); ! 309: entry != vm_map_to_entry(map); ! 310: entry = next) { ! 311: next = entry->vme_next; ! 312: if (entry->projected_on != 0) ! 313: projected_buffer_deallocate(map, entry->vme_start, entry->vme_end); ! 314: } ! 315: return(KERN_SUCCESS); ! 316: } ! 317: ! 318: ! 319: /* ! 320: * projected_buffer_in_range ! 321: * ! 322: * Verifies whether a projected buffer exists in the address range ! 323: * given. ! 324: */ ! 325: ! 326: boolean_t ! 327: projected_buffer_in_range(map, start, end) ! 328: vm_map_t map; ! 329: vm_offset_t start, end; ! 330: { ! 331: vm_map_entry_t entry; ! 332: ! 333: if (map == VM_MAP_NULL || map == kernel_map) ! 334: return(FALSE); ! 335: ! 336: /*Find first entry*/ ! 337: if (!vm_map_lookup_entry(map, start, &entry)) ! 338: entry = entry->vme_next; ! 339: ! 340: while (entry != vm_map_to_entry(map) && entry->projected_on == 0 && ! 341: entry->vme_start <= end) { ! 342: entry = entry->vme_next; ! 343: } ! 344: return(entry != vm_map_to_entry(map) && entry->vme_start <= end); ! 345: } ! 346: ! 347: ! 348: /* ! 349: * kmem_alloc: ! 350: * ! 351: * Allocate wired-down memory in the kernel's address map ! 352: * or a submap. The memory is not zero-filled. ! 353: */ ! 354: ! 355: kern_return_t ! 356: kmem_alloc(map, addrp, size) ! 357: vm_map_t map; ! 358: vm_offset_t *addrp; ! 359: vm_size_t size; ! 360: { ! 361: vm_object_t object; ! 362: vm_map_entry_t entry; ! 363: vm_offset_t addr; ! 364: kern_return_t kr; ! 365: ! 366: /* ! 367: * Allocate a new object. We must do this before locking ! 368: * the map, lest we risk deadlock with the default pager: ! 369: * device_read_alloc uses kmem_alloc, ! 370: * which tries to allocate an object, ! 371: * which uses kmem_alloc_wired to get memory, ! 372: * which blocks for pages. ! 373: * then the default pager needs to read a block ! 374: * to process a memory_object_data_write, ! 375: * and device_read_alloc calls kmem_alloc ! 376: * and deadlocks on the map lock. ! 377: */ ! 378: ! 379: size = round_page(size); ! 380: object = vm_object_allocate(size); ! 381: ! 382: vm_map_lock(map); ! 383: kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0, ! 384: VM_OBJECT_NULL, &entry); ! 385: if (kr != KERN_SUCCESS) { ! 386: vm_map_unlock(map); ! 387: vm_object_deallocate(object); ! 388: return kr; ! 389: } ! 390: ! 391: entry->object.vm_object = object; ! 392: entry->offset = 0; ! 393: ! 394: /* ! 395: * Since we have not given out this address yet, ! 396: * it is safe to unlock the map. ! 397: */ ! 398: vm_map_unlock(map); ! 399: ! 400: /* ! 401: * Allocate wired-down memory in the kernel_object, ! 402: * for this entry, and enter it in the kernel pmap. ! 403: */ ! 404: kmem_alloc_pages(object, 0, ! 405: addr, addr + size, ! 406: VM_PROT_DEFAULT); ! 407: ! 408: /* ! 409: * Return the memory, not zeroed. ! 410: */ ! 411: *addrp = addr; ! 412: return KERN_SUCCESS; ! 413: } ! 414: ! 415: /* ! 416: * kmem_realloc: ! 417: * ! 418: * Reallocate wired-down memory in the kernel's address map ! 419: * or a submap. Newly allocated pages are not zeroed. ! 420: * This can only be used on regions allocated with kmem_alloc. ! 421: * ! 422: * If successful, the pages in the old region are mapped twice. ! 423: * The old region is unchanged. Use kmem_free to get rid of it. ! 424: */ ! 425: kern_return_t kmem_realloc(map, oldaddr, oldsize, newaddrp, newsize) ! 426: vm_map_t map; ! 427: vm_offset_t oldaddr; ! 428: vm_size_t oldsize; ! 429: vm_offset_t *newaddrp; ! 430: vm_size_t newsize; ! 431: { ! 432: vm_offset_t oldmin, oldmax; ! 433: vm_offset_t newaddr; ! 434: vm_object_t object; ! 435: vm_map_entry_t oldentry, newentry; ! 436: kern_return_t kr; ! 437: ! 438: oldmin = trunc_page(oldaddr); ! 439: oldmax = round_page(oldaddr + oldsize); ! 440: oldsize = oldmax - oldmin; ! 441: newsize = round_page(newsize); ! 442: ! 443: /* ! 444: * Find space for the new region. ! 445: */ ! 446: ! 447: vm_map_lock(map); ! 448: kr = vm_map_find_entry(map, &newaddr, newsize, (vm_offset_t) 0, ! 449: VM_OBJECT_NULL, &newentry); ! 450: if (kr != KERN_SUCCESS) { ! 451: vm_map_unlock(map); ! 452: return kr; ! 453: } ! 454: ! 455: /* ! 456: * Find the VM object backing the old region. ! 457: */ ! 458: ! 459: if (!vm_map_lookup_entry(map, oldmin, &oldentry)) ! 460: panic("kmem_realloc"); ! 461: object = oldentry->object.vm_object; ! 462: ! 463: /* ! 464: * Increase the size of the object and ! 465: * fill in the new region. ! 466: */ ! 467: ! 468: vm_object_reference(object); ! 469: vm_object_lock(object); ! 470: if (object->size != oldsize) ! 471: panic("kmem_realloc"); ! 472: object->size = newsize; ! 473: vm_object_unlock(object); ! 474: ! 475: newentry->object.vm_object = object; ! 476: newentry->offset = 0; ! 477: ! 478: /* ! 479: * Since we have not given out this address yet, ! 480: * it is safe to unlock the map. We are trusting ! 481: * that nobody will play with either region. ! 482: */ ! 483: ! 484: vm_map_unlock(map); ! 485: ! 486: /* ! 487: * Remap the pages in the old region and ! 488: * allocate more pages for the new region. ! 489: */ ! 490: ! 491: kmem_remap_pages(object, 0, ! 492: newaddr, newaddr + oldsize, ! 493: VM_PROT_DEFAULT); ! 494: kmem_alloc_pages(object, oldsize, ! 495: newaddr + oldsize, newaddr + newsize, ! 496: VM_PROT_DEFAULT); ! 497: ! 498: *newaddrp = newaddr; ! 499: return KERN_SUCCESS; ! 500: } ! 501: ! 502: /* ! 503: * kmem_alloc_wired: ! 504: * ! 505: * Allocate wired-down memory in the kernel's address map ! 506: * or a submap. The memory is not zero-filled. ! 507: * ! 508: * The memory is allocated in the kernel_object. ! 509: * It may not be copied with vm_map_copy, and ! 510: * it may not be reallocated with kmem_realloc. ! 511: */ ! 512: ! 513: kern_return_t ! 514: kmem_alloc_wired(map, addrp, size) ! 515: vm_map_t map; ! 516: vm_offset_t *addrp; ! 517: vm_size_t size; ! 518: { ! 519: vm_map_entry_t entry; ! 520: vm_offset_t offset; ! 521: vm_offset_t addr; ! 522: kern_return_t kr; ! 523: ! 524: /* ! 525: * Use the kernel object for wired-down kernel pages. ! 526: * Assume that no region of the kernel object is ! 527: * referenced more than once. We want vm_map_find_entry ! 528: * to extend an existing entry if possible. ! 529: */ ! 530: ! 531: size = round_page(size); ! 532: vm_map_lock(map); ! 533: kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0, ! 534: kernel_object, &entry); ! 535: if (kr != KERN_SUCCESS) { ! 536: vm_map_unlock(map); ! 537: return kr; ! 538: } ! 539: ! 540: /* ! 541: * Since we didn't know where the new region would ! 542: * start, we couldn't supply the correct offset into ! 543: * the kernel object. We only initialize the entry ! 544: * if we aren't extending an existing entry. ! 545: */ ! 546: ! 547: offset = addr - VM_MIN_KERNEL_ADDRESS; ! 548: ! 549: if (entry->object.vm_object == VM_OBJECT_NULL) { ! 550: vm_object_reference(kernel_object); ! 551: ! 552: entry->object.vm_object = kernel_object; ! 553: entry->offset = offset; ! 554: } ! 555: ! 556: /* ! 557: * Since we have not given out this address yet, ! 558: * it is safe to unlock the map. ! 559: */ ! 560: vm_map_unlock(map); ! 561: ! 562: /* ! 563: * Allocate wired-down memory in the kernel_object, ! 564: * for this entry, and enter it in the kernel pmap. ! 565: */ ! 566: kmem_alloc_pages(kernel_object, offset, ! 567: addr, addr + size, ! 568: VM_PROT_DEFAULT); ! 569: ! 570: /* ! 571: * Return the memory, not zeroed. ! 572: */ ! 573: *addrp = addr; ! 574: return KERN_SUCCESS; ! 575: } ! 576: ! 577: /* ! 578: * kmem_alloc_aligned: ! 579: * ! 580: * Like kmem_alloc_wired, except that the memory is aligned. ! 581: * The size should be a power-of-2. ! 582: */ ! 583: ! 584: kern_return_t ! 585: kmem_alloc_aligned(map, addrp, size) ! 586: vm_map_t map; ! 587: vm_offset_t *addrp; ! 588: vm_size_t size; ! 589: { ! 590: vm_map_entry_t entry; ! 591: vm_offset_t offset; ! 592: vm_offset_t addr; ! 593: kern_return_t kr; ! 594: ! 595: if ((size & (size - 1)) != 0) ! 596: panic("kmem_alloc_aligned"); ! 597: ! 598: /* ! 599: * Use the kernel object for wired-down kernel pages. ! 600: * Assume that no region of the kernel object is ! 601: * referenced more than once. We want vm_map_find_entry ! 602: * to extend an existing entry if possible. ! 603: */ ! 604: ! 605: size = round_page(size); ! 606: vm_map_lock(map); ! 607: kr = vm_map_find_entry(map, &addr, size, size - 1, ! 608: kernel_object, &entry); ! 609: if (kr != KERN_SUCCESS) { ! 610: vm_map_unlock(map); ! 611: return kr; ! 612: } ! 613: ! 614: /* ! 615: * Since we didn't know where the new region would ! 616: * start, we couldn't supply the correct offset into ! 617: * the kernel object. We only initialize the entry ! 618: * if we aren't extending an existing entry. ! 619: */ ! 620: ! 621: offset = addr - VM_MIN_KERNEL_ADDRESS; ! 622: ! 623: if (entry->object.vm_object == VM_OBJECT_NULL) { ! 624: vm_object_reference(kernel_object); ! 625: ! 626: entry->object.vm_object = kernel_object; ! 627: entry->offset = offset; ! 628: } ! 629: ! 630: /* ! 631: * Since we have not given out this address yet, ! 632: * it is safe to unlock the map. ! 633: */ ! 634: vm_map_unlock(map); ! 635: ! 636: /* ! 637: * Allocate wired-down memory in the kernel_object, ! 638: * for this entry, and enter it in the kernel pmap. ! 639: */ ! 640: kmem_alloc_pages(kernel_object, offset, ! 641: addr, addr + size, ! 642: VM_PROT_DEFAULT); ! 643: ! 644: /* ! 645: * Return the memory, not zeroed. ! 646: */ ! 647: *addrp = addr; ! 648: return KERN_SUCCESS; ! 649: } ! 650: ! 651: /* ! 652: * kmem_alloc_pageable: ! 653: * ! 654: * Allocate pageable memory in the kernel's address map. ! 655: */ ! 656: ! 657: kern_return_t ! 658: kmem_alloc_pageable(map, addrp, size) ! 659: vm_map_t map; ! 660: vm_offset_t *addrp; ! 661: vm_size_t size; ! 662: { ! 663: vm_offset_t addr; ! 664: kern_return_t kr; ! 665: ! 666: addr = vm_map_min(map); ! 667: kr = vm_map_enter(map, &addr, round_page(size), ! 668: (vm_offset_t) 0, TRUE, ! 669: VM_OBJECT_NULL, (vm_offset_t) 0, FALSE, ! 670: VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT); ! 671: if (kr != KERN_SUCCESS) ! 672: return kr; ! 673: ! 674: *addrp = addr; ! 675: return KERN_SUCCESS; ! 676: } ! 677: ! 678: /* ! 679: * kmem_free: ! 680: * ! 681: * Release a region of kernel virtual memory allocated ! 682: * with kmem_alloc, kmem_alloc_wired, or kmem_alloc_pageable, ! 683: * and return the physical pages associated with that region. ! 684: */ ! 685: ! 686: void ! 687: kmem_free(map, addr, size) ! 688: vm_map_t map; ! 689: vm_offset_t addr; ! 690: vm_size_t size; ! 691: { ! 692: kern_return_t kr; ! 693: ! 694: kr = vm_map_remove(map, trunc_page(addr), round_page(addr + size)); ! 695: if (kr != KERN_SUCCESS) ! 696: panic("kmem_free"); ! 697: } ! 698: ! 699: /* ! 700: * Allocate new wired pages in an object. ! 701: * The object is assumed to be mapped into the kernel map or ! 702: * a submap. ! 703: */ ! 704: void ! 705: kmem_alloc_pages(object, offset, start, end, protection) ! 706: register vm_object_t object; ! 707: register vm_offset_t offset; ! 708: register vm_offset_t start, end; ! 709: vm_prot_t protection; ! 710: { ! 711: /* ! 712: * Mark the pmap region as not pageable. ! 713: */ ! 714: pmap_pageable(kernel_pmap, start, end, FALSE); ! 715: ! 716: while (start < end) { ! 717: register vm_page_t mem; ! 718: ! 719: vm_object_lock(object); ! 720: ! 721: /* ! 722: * Allocate a page ! 723: */ ! 724: while ((mem = vm_page_alloc(object, offset)) ! 725: == VM_PAGE_NULL) { ! 726: vm_object_unlock(object); ! 727: VM_PAGE_WAIT((void (*)()) 0); ! 728: vm_object_lock(object); ! 729: } ! 730: ! 731: /* ! 732: * Wire it down ! 733: */ ! 734: vm_page_lock_queues(); ! 735: vm_page_wire(mem); ! 736: vm_page_unlock_queues(); ! 737: vm_object_unlock(object); ! 738: ! 739: /* ! 740: * Enter it in the kernel pmap ! 741: */ ! 742: PMAP_ENTER(kernel_pmap, start, mem, ! 743: protection, TRUE); ! 744: ! 745: vm_object_lock(object); ! 746: PAGE_WAKEUP_DONE(mem); ! 747: vm_object_unlock(object); ! 748: ! 749: start += PAGE_SIZE; ! 750: offset += PAGE_SIZE; ! 751: } ! 752: } ! 753: ! 754: /* ! 755: * Remap wired pages in an object into a new region. ! 756: * The object is assumed to be mapped into the kernel map or ! 757: * a submap. ! 758: */ ! 759: void ! 760: kmem_remap_pages(object, offset, start, end, protection) ! 761: register vm_object_t object; ! 762: register vm_offset_t offset; ! 763: register vm_offset_t start, end; ! 764: vm_prot_t protection; ! 765: { ! 766: /* ! 767: * Mark the pmap region as not pageable. ! 768: */ ! 769: pmap_pageable(kernel_pmap, start, end, FALSE); ! 770: ! 771: while (start < end) { ! 772: register vm_page_t mem; ! 773: ! 774: vm_object_lock(object); ! 775: ! 776: /* ! 777: * Find a page ! 778: */ ! 779: if ((mem = vm_page_lookup(object, offset)) == VM_PAGE_NULL) ! 780: panic("kmem_remap_pages"); ! 781: ! 782: /* ! 783: * Wire it down (again) ! 784: */ ! 785: vm_page_lock_queues(); ! 786: vm_page_wire(mem); ! 787: vm_page_unlock_queues(); ! 788: vm_object_unlock(object); ! 789: ! 790: /* ! 791: * Enter it in the kernel pmap. The page isn't busy, ! 792: * but this shouldn't be a problem because it is wired. ! 793: */ ! 794: PMAP_ENTER(kernel_pmap, start, mem, ! 795: protection, TRUE); ! 796: ! 797: start += PAGE_SIZE; ! 798: offset += PAGE_SIZE; ! 799: } ! 800: } ! 801: ! 802: /* ! 803: * kmem_suballoc: ! 804: * ! 805: * Allocates a map to manage a subrange ! 806: * of the kernel virtual address space. ! 807: * ! 808: * Arguments are as follows: ! 809: * ! 810: * parent Map to take range from ! 811: * size Size of range to find ! 812: * min, max Returned endpoints of map ! 813: * pageable Can the region be paged ! 814: */ ! 815: ! 816: vm_map_t ! 817: kmem_suballoc(parent, min, max, size, pageable) ! 818: vm_map_t parent; ! 819: vm_offset_t *min, *max; ! 820: vm_size_t size; ! 821: boolean_t pageable; ! 822: { ! 823: vm_map_t map; ! 824: vm_offset_t addr; ! 825: kern_return_t kr; ! 826: ! 827: size = round_page(size); ! 828: ! 829: /* ! 830: * Need reference on submap object because it is internal ! 831: * to the vm_system. vm_object_enter will never be called ! 832: * on it (usual source of reference for vm_map_enter). ! 833: */ ! 834: vm_object_reference(vm_submap_object); ! 835: ! 836: addr = (vm_offset_t) vm_map_min(parent); ! 837: kr = vm_map_enter(parent, &addr, size, ! 838: (vm_offset_t) 0, TRUE, ! 839: vm_submap_object, (vm_offset_t) 0, FALSE, ! 840: VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT); ! 841: if (kr != KERN_SUCCESS) ! 842: panic("kmem_suballoc"); ! 843: ! 844: pmap_reference(vm_map_pmap(parent)); ! 845: map = vm_map_create(vm_map_pmap(parent), addr, addr + size, pageable); ! 846: if (map == VM_MAP_NULL) ! 847: panic("kmem_suballoc"); ! 848: ! 849: kr = vm_map_submap(parent, addr, addr + size, map); ! 850: if (kr != KERN_SUCCESS) ! 851: panic("kmem_suballoc"); ! 852: ! 853: *min = addr; ! 854: *max = addr + size; ! 855: return map; ! 856: } ! 857: ! 858: /* ! 859: * kmem_init: ! 860: * ! 861: * Initialize the kernel's virtual memory map, taking ! 862: * into account all memory allocated up to this time. ! 863: */ ! 864: void kmem_init(start, end) ! 865: vm_offset_t start; ! 866: vm_offset_t end; ! 867: { ! 868: kernel_map = vm_map_create(pmap_kernel(), ! 869: VM_MIN_KERNEL_ADDRESS, end, ! 870: FALSE); ! 871: ! 872: /* ! 873: * Reserve virtual memory allocated up to this time. ! 874: */ ! 875: ! 876: if (start != VM_MIN_KERNEL_ADDRESS) { ! 877: kern_return_t rc; ! 878: vm_offset_t addr = VM_MIN_KERNEL_ADDRESS; ! 879: rc = vm_map_enter(kernel_map, ! 880: &addr, start - VM_MIN_KERNEL_ADDRESS, ! 881: (vm_offset_t) 0, TRUE, ! 882: VM_OBJECT_NULL, (vm_offset_t) 0, FALSE, ! 883: VM_PROT_DEFAULT, VM_PROT_ALL, ! 884: VM_INHERIT_DEFAULT); ! 885: if (rc) ! 886: panic("%s:%d: vm_map_enter failed (%d)\n", rc); ! 887: } ! 888: } ! 889: ! 890: /* ! 891: * New and improved IO wiring support. ! 892: */ ! 893: ! 894: /* ! 895: * kmem_io_map_copyout: ! 896: * ! 897: * Establish temporary mapping in designated map for the memory ! 898: * passed in. Memory format must be a page_list vm_map_copy. ! 899: * Mapping is READ-ONLY. ! 900: */ ! 901: ! 902: kern_return_t ! 903: kmem_io_map_copyout(map, addr, alloc_addr, alloc_size, copy, min_size) ! 904: vm_map_t map; ! 905: vm_offset_t *addr; /* actual addr of data */ ! 906: vm_offset_t *alloc_addr; /* page aligned addr */ ! 907: vm_size_t *alloc_size; /* size allocated */ ! 908: vm_map_copy_t copy; ! 909: vm_size_t min_size; /* Do at least this much */ ! 910: { ! 911: vm_offset_t myaddr, offset; ! 912: vm_size_t mysize, copy_size; ! 913: kern_return_t ret; ! 914: register ! 915: vm_page_t *page_list; ! 916: vm_map_copy_t new_copy; ! 917: register ! 918: int i; ! 919: ! 920: assert(copy->type == VM_MAP_COPY_PAGE_LIST); ! 921: assert(min_size != 0); ! 922: ! 923: /* ! 924: * Figure out the size in vm pages. ! 925: */ ! 926: min_size += copy->offset - trunc_page(copy->offset); ! 927: min_size = round_page(min_size); ! 928: mysize = round_page(copy->offset + copy->size) - ! 929: trunc_page(copy->offset); ! 930: ! 931: /* ! 932: * If total size is larger than one page list and ! 933: * we don't have to do more than one page list, then ! 934: * only do one page list. ! 935: * ! 936: * XXX Could be much smarter about this ... like trimming length ! 937: * XXX if we need more than one page list but not all of them. ! 938: */ ! 939: ! 940: copy_size = ptoa(copy->cpy_npages); ! 941: if (mysize > copy_size && copy_size > min_size) ! 942: mysize = copy_size; ! 943: ! 944: /* ! 945: * Allocate some address space in the map (must be kernel ! 946: * space). ! 947: */ ! 948: myaddr = vm_map_min(map); ! 949: ret = vm_map_enter(map, &myaddr, mysize, ! 950: (vm_offset_t) 0, TRUE, ! 951: VM_OBJECT_NULL, (vm_offset_t) 0, FALSE, ! 952: VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT); ! 953: ! 954: if (ret != KERN_SUCCESS) ! 955: return(ret); ! 956: ! 957: /* ! 958: * Tell the pmap module that this will be wired, and ! 959: * enter the mappings. ! 960: */ ! 961: pmap_pageable(vm_map_pmap(map), myaddr, myaddr + mysize, TRUE); ! 962: ! 963: *addr = myaddr + (copy->offset - trunc_page(copy->offset)); ! 964: *alloc_addr = myaddr; ! 965: *alloc_size = mysize; ! 966: ! 967: offset = myaddr; ! 968: page_list = ©->cpy_page_list[0]; ! 969: while (TRUE) { ! 970: for ( i = 0; i < copy->cpy_npages; i++, offset += PAGE_SIZE) { ! 971: PMAP_ENTER(vm_map_pmap(map), offset, *page_list, ! 972: VM_PROT_READ, TRUE); ! 973: page_list++; ! 974: } ! 975: ! 976: if (offset == (myaddr + mysize)) ! 977: break; ! 978: ! 979: /* ! 980: * Onward to the next page_list. The extend_cont ! 981: * leaves the current page list's pages alone; ! 982: * they'll be cleaned up at discard. Reset this ! 983: * copy's continuation to discard the next one. ! 984: */ ! 985: vm_map_copy_invoke_extend_cont(copy, &new_copy, &ret); ! 986: ! 987: if (ret != KERN_SUCCESS) { ! 988: kmem_io_map_deallocate(map, myaddr, mysize); ! 989: return(ret); ! 990: } ! 991: copy->cpy_cont = vm_map_copy_discard_cont; ! 992: copy->cpy_cont_args = (char *) new_copy; ! 993: copy = new_copy; ! 994: page_list = ©->cpy_page_list[0]; ! 995: } ! 996: ! 997: return(ret); ! 998: } ! 999: ! 1000: /* ! 1001: * kmem_io_map_deallocate: ! 1002: * ! 1003: * Get rid of the mapping established by kmem_io_map_copyout. ! 1004: * Assumes that addr and size have been rounded to page boundaries. ! 1005: * (e.g., the alloc_addr and alloc_size returned by kmem_io_map_copyout) ! 1006: */ ! 1007: ! 1008: void ! 1009: kmem_io_map_deallocate(map, addr, size) ! 1010: vm_map_t map; ! 1011: vm_offset_t addr; ! 1012: vm_size_t size; ! 1013: { ! 1014: /* ! 1015: * Remove the mappings. The pmap_remove is needed. ! 1016: */ ! 1017: ! 1018: pmap_remove(vm_map_pmap(map), addr, addr + size); ! 1019: vm_map_remove(map, addr, addr + size); ! 1020: } ! 1021: ! 1022: /* ! 1023: * Routine: copyinmap ! 1024: * Purpose: ! 1025: * Like copyin, except that fromaddr is an address ! 1026: * in the specified VM map. This implementation ! 1027: * is incomplete; it handles the current user map ! 1028: * and the kernel map/submaps. ! 1029: */ ! 1030: ! 1031: int copyinmap(map, fromaddr, toaddr, length) ! 1032: vm_map_t map; ! 1033: char *fromaddr, *toaddr; ! 1034: int length; ! 1035: { ! 1036: if (vm_map_pmap(map) == kernel_pmap) { ! 1037: /* assume a correct copy */ ! 1038: bcopy(fromaddr, toaddr, length); ! 1039: return 0; ! 1040: } ! 1041: ! 1042: if (current_map() == map) ! 1043: return copyin( fromaddr, toaddr, length); ! 1044: ! 1045: return 1; ! 1046: } ! 1047: ! 1048: /* ! 1049: * Routine: copyoutmap ! 1050: * Purpose: ! 1051: * Like copyout, except that toaddr is an address ! 1052: * in the specified VM map. This implementation ! 1053: * is incomplete; it handles the current user map ! 1054: * and the kernel map/submaps. ! 1055: */ ! 1056: ! 1057: int copyoutmap(map, fromaddr, toaddr, length) ! 1058: vm_map_t map; ! 1059: char *fromaddr, *toaddr; ! 1060: int length; ! 1061: { ! 1062: if (vm_map_pmap(map) == kernel_pmap) { ! 1063: /* assume a correct copy */ ! 1064: bcopy(fromaddr, toaddr, length); ! 1065: return 0; ! 1066: } ! 1067: ! 1068: if (current_map() == map) ! 1069: return copyout(fromaddr, toaddr, length); ! 1070: ! 1071: return 1; ! 1072: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.