|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: * File: vm/vm_kern.c
52: * Author: Avadis Tevanian, Jr., Michael Wayne Young
53: * Date: 1985
54: *
55: * Kernel memory management.
56: */
57:
58: #include <mach/kern_return.h>
59: #include <mach/vm_param.h>
60: #include <kern/assert.h>
61: #include <kern/lock.h>
62: #include <kern/thread.h>
63: #include <vm/vm_fault.h>
64: #include <vm/vm_kern.h>
65: #include <vm/vm_map.h>
66: #include <vm/vm_object.h>
67: #include <vm/vm_page.h>
68: #include <vm/vm_pageout.h>
69:
70: vm_map_t kernel_map;
71:
72: static boolean_t kmem_alloc_pages(
73: vm_object_t object,
74: vm_offset_t offset,
75: vm_offset_t start,
76: vm_offset_t end,
77: boolean_t canblock);
78: void kmem_remap_pages(
79: vm_object_t object,
80: vm_offset_t offset,
81: vm_offset_t start,
82: vm_offset_t end);
83:
84: /*
85: * Allocate wired-down memory in the kernel's address map
86: * or a submap.
87: */
88: static
89: kern_return_t
90: kmem_alloc_prim(
91: vm_map_t map,
92: vm_offset_t *addrp,
93: vm_size_t size,
94: vm_object_t object,
95: boolean_t canblock
96: )
97: {
98: kern_return_t result;
99: vm_offset_t addr, offset = 0;
100: vm_map_entry_t entry;
101:
102: size = round_page(size);
103: vm_map_lock(map);
104: if (result = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0,
105: (object != kernel_object)?
106: VM_OBJECT_NULL : object, &entry)
107: != KERN_SUCCESS) {
108: vm_map_unlock(map);
109: if (object != kernel_object)
110: vm_object_deallocate(object);
111: return (result);
112: }
113:
114: if (object == kernel_object)
115: offset = addr - VM_MIN_KERNEL_ADDRESS;
116:
117: if (entry->object.vm_object == VM_OBJECT_NULL) {
118: if (object == kernel_object)
119: vm_object_reference(kernel_object);
120:
121: entry->object.vm_object = object;
122: entry->offset = offset;
123: }
124:
125: /*
126: * Since we have not given out this address yet,
127: * it is safe to unlock the map.
128: */
129: vm_map_unlock(map);
130:
131: if (!kmem_alloc_pages(object, offset, addr, addr + size, canblock)) {
132: vm_map_remove(map, addr, addr + size);
133:
134: return (KERN_RESOURCE_SHORTAGE);
135: }
136:
137: *addrp = addr;
138:
139: return (KERN_SUCCESS);
140: }
141:
142: kern_return_t
143: kmem_alloc(
144: vm_map_t map,
145: vm_offset_t *addrp,
146: vm_size_t size)
147: {
148: vm_object_t object = vm_object_allocate(size);
149:
150: return kmem_alloc_prim(map, addrp, size, object, TRUE);
151: }
152:
153: /*
154: * kmem_realloc:
155: *
156: * Reallocate wired-down memory in the kernel's address map
157: * or a submap.
158: * This can only be used on regions allocated with kmem_alloc.
159: *
160: * If successful, the pages in the old region are mapped twice.
161: * The old region is unchanged. Use kmem_free to get rid of it.
162: */
163: kern_return_t kmem_realloc(
164: vm_map_t map,
165: vm_offset_t oldaddr,
166: vm_size_t oldsize,
167: vm_offset_t *newaddrp,
168: vm_size_t newsize)
169: {
170: vm_offset_t oldmin, oldmax;
171: vm_offset_t newaddr;
172: vm_object_t object;
173: vm_map_entry_t oldentry, newentry;
174: kern_return_t kr;
175:
176: oldmin = trunc_page(oldaddr);
177: oldmax = round_page(oldaddr + oldsize);
178: oldsize = oldmax - oldmin;
179: newsize = round_page(newsize);
180:
181: /*
182: * Find space for the new region.
183: */
184:
185: vm_map_lock(map);
186: kr = vm_map_find_entry(map, &newaddr, newsize, (vm_offset_t) 0,
187: VM_OBJECT_NULL, &newentry);
188: if (kr != KERN_SUCCESS) {
189: vm_map_unlock(map);
190: return kr;
191: }
192:
193: /*
194: * Find the VM object backing the old region.
195: */
196:
197: if (!vm_map_lookup_entry(map, oldmin, &oldentry))
198: panic("kmem_realloc");
199: object = oldentry->object.vm_object;
200:
201: /*
202: * Increase the size of the object and
203: * fill in the new region.
204: */
205:
206: vm_object_reference(object);
207: vm_object_lock(object);
208: if (object->size != oldsize)
209: panic("kmem_realloc");
210: object->size = newsize;
211: vm_object_unlock(object);
212:
213: newentry->object.vm_object = object;
214: newentry->offset = 0;
215:
216: /*
217: * Since we have not given out this address yet,
218: * it is safe to unlock the map. We are trusting
219: * that nobody will play with either region.
220: */
221:
222: vm_map_unlock(map);
223:
224: /*
225: * Remap the pages in the old region and
226: * allocate more pages for the new region.
227: */
228:
229: kmem_remap_pages(object, 0,
230: newaddr, newaddr + oldsize);
231: (void) kmem_alloc_pages(object, oldsize,
232: newaddr + oldsize, newaddr + newsize, TRUE);
233:
234: *newaddrp = newaddr;
235: return KERN_SUCCESS;
236: }
237:
238: kern_return_t
239: kmem_alloc_wired(
240: vm_map_t map,
241: vm_offset_t *addrp,
242: vm_size_t size)
243: {
244: return kmem_alloc_prim(map, addrp, size, kernel_object, TRUE);
245: }
246:
247:
248: /*
249: * kmem_alloc_pageable:
250: *
251: * Allocate pageable memory to the kernel's address map.
252: * map must be "kernel_map" below.
253: */
254:
255: kern_return_t
256: kmem_alloc_pageable(
257: vm_map_t map,
258: vm_offset_t *addrp,
259: vm_size_t size)
260: {
261: vm_offset_t addr;
262: kern_return_t kr;
263:
264: addr = vm_map_min(map);
265: kr = vm_map_find(map, VM_OBJECT_NULL, (vm_offset_t) 0,
266: &addr, round_page(size), TRUE);
267: if (kr != KERN_SUCCESS)
268: return kr;
269:
270: *addrp = addr;
271: return KERN_SUCCESS;
272: }
273:
274: /*
275: * kmem_free:
276: *
277: * Release a region of kernel virtual memory allocated
278: * with kmem_alloc, and return the physical pages
279: * associated with that region.
280: */
281: void
282: kmem_free(
283: vm_map_t map,
284: vm_offset_t addr,
285: vm_size_t size)
286: {
287: (void) vm_map_remove(map, trunc_page(addr), round_page(addr + size));
288: }
289:
290: /*
291: * Allocate new wired pages in an object.
292: * The object is assumed to be mapped into the kernel map or
293: * a submap.
294: */
295: static
296: boolean_t
297: kmem_alloc_pages(
298: vm_object_t object,
299: vm_offset_t offset,
300: vm_offset_t start,
301: vm_offset_t end,
302: boolean_t canblock)
303: {
304: /*
305: * Mark the pmap region as not pageable.
306: */
307: pmap_pageable(kernel_pmap, start, end, FALSE);
308:
309: while (start < end) {
310: register vm_page_t mem;
311:
312: vm_object_lock(object);
313:
314: /*
315: * Allocate a page
316: */
317: while ((mem = vm_page_alloc(object, offset)) == VM_PAGE_NULL) {
318: vm_object_unlock(object);
319: if (!canblock)
320: return FALSE;
321: VM_WAIT;
322: vm_object_lock(object);
323: }
324:
325: /*
326: * Wire it down
327: */
328: vm_page_lock_queues();
329: vm_page_wire(mem);
330: vm_page_unlock_queues();
331: vm_object_unlock(object);
332:
333: vm_page_zero_fill(mem);
334:
335: /*
336: * Enter it in the kernel pmap
337: */
338: PMAP_ENTER(kernel_pmap, start, mem,
339: VM_PROT_DEFAULT, TRUE);
340:
341: vm_object_lock(object);
342: PAGE_WAKEUP(mem);
343: vm_object_unlock(object);
344:
345: start += PAGE_SIZE;
346: offset += PAGE_SIZE;
347: }
348:
349: return TRUE;
350: }
351:
352: /*
353: * Remap wired pages in an object into a new region.
354: * The object is assumed to be mapped into the kernel map or
355: * a submap.
356: */
357: void
358: kmem_remap_pages(
359: vm_object_t object,
360: vm_offset_t offset,
361: vm_offset_t start,
362: vm_offset_t end)
363: {
364: /*
365: * Mark the pmap region as not pageable.
366: */
367: pmap_pageable(kernel_pmap, start, end, FALSE);
368:
369: while (start < end) {
370: register vm_page_t mem;
371:
372: vm_object_lock(object);
373:
374: /*
375: * Find a page
376: */
377: if ((mem = vm_page_lookup(object, offset)) == VM_PAGE_NULL)
378: panic("kmem_remap_pages");
379:
380: /*
381: * Wire it down (again)
382: */
383: vm_page_lock_queues();
384: vm_page_wire(mem);
385: vm_page_unlock_queues();
386: vm_object_unlock(object);
387:
388: /*
389: * Enter it in the kernel pmap. The page isn't busy,
390: * but this shouldn't be a problem because it is wired.
391: */
392: PMAP_ENTER(kernel_pmap, start, mem,
393: VM_PROT_DEFAULT, TRUE);
394:
395: start += PAGE_SIZE;
396: offset += PAGE_SIZE;
397: }
398: }
399:
400: /*
401: * kmem_suballoc:
402: *
403: * Allocates a map to manage a subrange
404: * of the kernel virtual address space.
405: *
406: * Arguments are as follows:
407: *
408: * parent Map to take range from
409: * size Size of range to find
410: * min, max Returned endpoints of map
411: * pageable Can the region be paged
412: */
413: vm_map_t
414: kmem_suballoc(
415: vm_map_t parent,
416: vm_offset_t *min,
417: vm_offset_t *max,
418: vm_size_t size,
419: boolean_t pageable)
420: {
421: vm_map_t map;
422: vm_offset_t addr;
423: kern_return_t kr;
424:
425: size = round_page(size);
426:
427: /*
428: * Need reference on submap object because it is internal
429: * to the vm_system. vm_object_enter will never be called
430: * on it (usual source of reference for vm_map_enter).
431: */
432: vm_object_reference(vm_submap_object);
433:
434: addr = (vm_offset_t) vm_map_min(parent);
435: kr = vm_map_find(parent, vm_submap_object, (vm_offset_t) 0,
436: &addr, size, TRUE);
437: if (kr != KERN_SUCCESS)
438: panic("kmem_suballoc 1");
439:
440: pmap_reference(vm_map_pmap(parent));
441: map = vm_map_create(vm_map_pmap(parent), addr, addr + size, pageable);
442: if (map == VM_MAP_NULL)
443: panic("kmem_suballoc 2");
444:
445: kr = vm_map_submap(parent, addr, addr + size, map);
446: if (kr != KERN_SUCCESS)
447: panic("kmem_suballoc 3");
448:
449: *min = addr;
450: *max = addr + size;
451: return map;
452: }
453:
454: /*
455: * kmem_init:
456: *
457: * Initialize the kernel's virtual memory map, taking
458: * into account all memory allocated up to this time.
459: */
460: void kmem_init(
461: vm_offset_t start,
462: vm_offset_t end)
463: {
464: kernel_map = vm_map_create(pmap_kernel(),
465: VM_MIN_KERNEL_ADDRESS, end,
466: FALSE);
467:
468: /*
469: * Reserve virtual memory allocated up to this time.
470: */
471:
472: if (start != VM_MIN_KERNEL_ADDRESS) {
473: vm_offset_t addr = VM_MIN_KERNEL_ADDRESS;
474: (void) vm_map_find(kernel_map, VM_OBJECT_NULL, (vm_offset_t) 0,
475: &addr, (start - VM_MIN_KERNEL_ADDRESS),
476: FALSE);
477: }
478: }
479:
480: /*
481: * Routine: copyinmap
482: * Purpose:
483: * Like copyin, except that fromaddr is an address
484: * in the specified VM map. This implementation
485: * is incomplete; it handles the current user map
486: * and the kernel map/submaps.
487: */
488:
489: int copyinmap(map, fromaddr, toaddr, length)
490: vm_map_t map;
491: char *fromaddr, *toaddr;
492: int length;
493: {
494: if (vm_map_pmap(map) == kernel_pmap) {
495: /* assume a correct copy */
496: bcopy(fromaddr, toaddr, length);
497: return 0;
498: }
499:
500: if (current_map() == map)
501: return copyin( fromaddr, toaddr, length);
502:
503: return 1;
504: }
505:
506: /*
507: * Routine: copyoutmap
508: * Purpose:
509: * Like copyout, except that toaddr is an address
510: * in the specified VM map. This implementation
511: * is incomplete; it handles the current user map
512: * and the kernel map/submaps.
513: */
514:
515: int copyoutmap(map, fromaddr, toaddr, length)
516: vm_map_t map;
517: char *fromaddr, *toaddr;
518: int length;
519: {
520: if (vm_map_pmap(map) == kernel_pmap) {
521: /* assume a correct copy */
522: bcopy(fromaddr, toaddr, length);
523: return 0;
524: }
525:
526: if (current_map() == map)
527: return copyout(fromaddr, toaddr, length);
528:
529: return 1;
530: }
531:
532: /*
533: * Allocate wired-down memory in the kernel's address map
534: * or a submap.
535: */
536: kern_return_t
537: kmem_alloc_zone(map, addrp, size, canblock)
538: vm_map_t map;
539: vm_offset_t *addrp;
540: register vm_size_t size;
541: boolean_t canblock;
542: {
543: return kmem_alloc_prim(map, addrp, size, kernel_object, canblock);
544: }
545:
546: /*
547: * Special hack for allocation in mb_map. Can never wait for pages
548: * (or anything else) in mb_map.
549: */
550: vm_offset_t kmem_mb_alloc(map, size)
551: register vm_map_t map;
552: vm_size_t size;
553: {
554: vm_object_t object;
555: register vm_map_entry_t entry;
556: vm_offset_t addr;
557: register int npgs;
558: register vm_page_t m;
559: register vm_offset_t vaddr, offset, cur_off;
560:
561: /*
562: * Only do this on the mb_map.
563: */
564: if (map != mb_map)
565: panic("You fool!");
566:
567: size = round_page(size);
568:
569: vm_map_lock(map);
570: entry = vm_map_first_entry(map);
571: if (entry == vm_map_to_entry(map)) {
572: /*
573: * Map is empty. Do things normally the first time...
574: * this will allocate the entry and the object to use.
575: */
576: vm_map_unlock(map);
577: addr = vm_map_min(map);
578: if (vm_map_find(map, VM_OBJECT_NULL, (vm_offset_t) 0,
579: &addr, size, TRUE) != KERN_SUCCESS)
580: return (0);
581: (void) vm_map_pageable(map, addr, addr + size, FALSE);
582:
583: return(addr);
584: }
585: /*
586: * Map already has an entry. We must be extending it.
587: */
588: if (!(entry == vm_map_last_entry(map) &&
589: entry->is_a_map == FALSE &&
590: entry->vme_start == vm_map_min(map) &&
591: entry->max_protection == VM_PROT_ALL &&
592: entry->protection == VM_PROT_DEFAULT &&
593: entry->inheritance == VM_INHERIT_DEFAULT &&
594: entry->wired_count != 0)) {
595: /*
596: * Someone's not playing by the rules...
597: */
598: panic("mb_map abused even more than usual");
599: }
600:
601: /*
602: * Make sure there's enough room in map to extend entry.
603: */
604:
605: if (vm_map_max(map) - size < entry->vme_end) {
606: vm_map_unlock(map);
607: return(0);
608: }
609:
610: /*
611: * extend the entry
612: */
613: object = entry->object.vm_object;
614: offset = (entry->vme_end - entry->vme_start) + entry->offset;
615: addr = entry->vme_end;
616: entry->vme_end += size;
617:
618: /*
619: * Since we may not have enough memory, and we may not
620: * block, we first allocate all the memory up front, pulling
621: * it off the active queue to prevent pageout. We then can
622: * either enter the pages, or free whatever we tried to get.
623: */
624:
625: vm_object_lock(object);
626: cur_off = offset;
627: npgs = atop(size);
628: while (npgs) {
629: m = vm_page_alloc_sequential(object, cur_off, FALSE);
630: if (m == VM_PAGE_NULL) {
631: /*
632: * Not enough pages, and we can't
633: * wait, so free everything up.
634: */
635: while (cur_off > offset) {
636: cur_off -= PAGE_SIZE;
637: m = vm_page_lookup(object, cur_off);
638: /*
639: * Don't have to lock the queues here
640: * because we know that the pages are
641: * not on any queues.
642: */
643: vm_page_free(m);
644: }
645: vm_object_unlock(object);
646:
647: /*
648: * Shrink the map entry back to its old size.
649: */
650: entry->vme_end -= size;
651: vm_map_unlock(map);
652: return(0);
653: }
654:
655: /*
656: * We want zero-filled memory
657: */
658:
659: vm_page_zero_fill(m);
660:
661: /*
662: * Since no other process can see these pages, we don't
663: * have to bother with the busy bit.
664: */
665:
666: m->busy = FALSE;
667:
668: npgs--;
669: cur_off += PAGE_SIZE;
670: }
671:
672: vm_object_unlock(object);
673:
674: /*
675: * Map entry is already marked non-pageable.
676: * Loop thru pages, entering them in the pmap.
677: * (We can't add them to the wired count without
678: * wrapping the vm_page_queue_lock in splimp...)
679: */
680: vaddr = addr;
681: cur_off = offset;
682: while (vaddr < entry->vme_end) {
683: vm_object_lock(object);
684: m = vm_page_lookup(object, cur_off);
685: vm_page_wire(m);
686: vm_object_unlock(object);
687: pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m),
688: entry->protection, TRUE);
689: vaddr += PAGE_SIZE;
690: cur_off += PAGE_SIZE;
691: }
692: vm_map_unlock(map);
693:
694: return(addr);
695: }
696:
697: /*
698: * kmem_alloc_wait
699: *
700: * Allocates pageable memory from a sub-map of the kernel. If the submap
701: * has no room, the caller sleeps waiting for more memory in the submap.
702: *
703: */
704: vm_offset_t kmem_alloc_wait(map, size)
705: vm_map_t map;
706: vm_size_t size;
707: {
708: vm_offset_t addr;
709: kern_return_t result;
710:
711: size = round_page(size);
712:
713: do {
714: /*
715: * To make this work for more than one map,
716: * use the map's lock to lock out sleepers/wakers.
717: * Unfortunately, vm_map_find also grabs the map lock.
718: */
719: vm_map_lock(map);
720: lock_set_recursive(&map->lock);
721:
722: addr = vm_map_min(map);
723: result = vm_map_find(map, VM_OBJECT_NULL, (vm_offset_t) 0,
724: &addr, size, TRUE);
725:
726: lock_clear_recursive(&map->lock);
727: if (result != KERN_SUCCESS) {
728:
729: if ( (vm_map_max(map) - vm_map_min(map)) < size ) {
730: vm_map_unlock(map);
731: return(0);
732: }
733:
734: assert_wait(map, TRUE);
735: vm_map_unlock(map);
736: thread_block();
737: }
738: else {
739: vm_map_unlock(map);
740: }
741:
742: } while (result != KERN_SUCCESS);
743:
744: return(addr);
745: }
746:
747: /*
748: * kmem_free_wakeup
749: *
750: * Returns memory to a submap of the kernel, and wakes up any threads
751: * waiting for memory in that map.
752: */
753: void kmem_free_wakeup(map, addr, size)
754: vm_map_t map;
755: vm_offset_t addr;
756: vm_size_t size;
757: {
758: vm_map_lock(map);
759: (void) vm_map_delete(map, trunc_page(addr), round_page(addr + size));
760: thread_wakeup(map);
761: vm_map_unlock(map);
762: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.