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