|
|
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:
1.1.1.3 ! root 364: if (map != kmem_map && map != mb_map && map != buffer_map)
! 365: panic("kern_malloc_alloc: map != {kmem,mb,buffer}_map");
1.1 root 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);
1.1.1.2 root 501: thread_wakeup(&vm_pages_needed); /* XXX */
1.1 root 502: thread_block();
503: }
504: else {
505: vm_map_unlock(map);
506: }
507:
508: } while (result != KERN_SUCCESS);
509:
510: return(addr);
511: }
512:
513: /*
1.1.1.3 ! root 514: * kmem_alloc_wired_wait
! 515: *
! 516: * Allocates nonpageable memory from a sub-map of the kernel. If the submap
! 517: * has no room, the caller sleeps waiting for more memory in the submap.
! 518: *
! 519: */
! 520: vm_offset_t kmem_alloc_wired_wait(map, size)
! 521: vm_map_t map;
! 522: vm_size_t size;
! 523: {
! 524: vm_offset_t addr;
! 525: int result;
! 526:
! 527: size = round_page(size);
! 528:
! 529: do {
! 530: /*
! 531: * To make this work for more than one map,
! 532: * use the map's lock to lock out sleepers/wakers.
! 533: * Unfortunately, vm_map_find also grabs the map lock.
! 534: */
! 535: vm_map_lock(map);
! 536: lock_set_recursive(&map->lock);
! 537:
! 538: addr = vm_map_min(map);
! 539: result = vm_map_find(map, NULL, (vm_offset_t) 0,
! 540: &addr, size, FALSE);
! 541:
! 542: lock_clear_recursive(&map->lock);
! 543: if (result != KERN_SUCCESS) {
! 544:
! 545: if ( (vm_map_max(map) - vm_map_min(map)) < size ) {
! 546: vm_map_unlock(map);
! 547: return(0);
! 548: }
! 549:
! 550: assert_wait((int)map, TRUE);
! 551: vm_map_unlock(map);
! 552: thread_wakeup(&vm_pages_needed); /* XXX */
! 553: thread_block();
! 554: }
! 555: else {
! 556: vm_map_unlock(map);
! 557: }
! 558:
! 559: } while (result != KERN_SUCCESS);
! 560:
! 561: return(addr);
! 562: }
! 563:
! 564: /*
1.1 root 565: * kmem_free_wakeup
566: *
567: * Returns memory to a submap of the kernel, and wakes up any threads
568: * waiting for memory in that map.
569: */
570: void kmem_free_wakeup(map, addr, size)
571: vm_map_t map;
572: vm_offset_t addr;
573: vm_size_t size;
574: {
575: vm_map_lock(map);
576: (void) vm_map_delete(map, trunc_page(addr), round_page(addr + size));
577: thread_wakeup((int)map);
578: vm_map_unlock(map);
579: }
580:
581: /*
582: * kmem_init:
583: *
584: * Initialize the kernel's virtual memory map, taking
585: * into account all memory allocated up to this time.
586: */
587: void kmem_init(start, end)
588: vm_offset_t start;
589: vm_offset_t end;
590: {
591: vm_offset_t addr;
592: extern vm_map_t kernel_map;
593:
594: addr = VM_MIN_KERNEL_ADDRESS;
595: kernel_map = vm_map_create(pmap_kernel(), addr, end, FALSE);
596: (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
597: &addr, (start - VM_MIN_KERNEL_ADDRESS),
598: FALSE);
599: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.