|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
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: */
52: /*
53: * File: vm/vm_map.c
54: * Author: Avadis Tevanian, Jr., Michael Wayne Young
55: * Date: 1985
56: *
57: * Virtual memory mapping module.
58: */
59:
60: #include <cpus.h>
61: #include <task_swapper.h>
62: #include <mach_assert.h>
63: #include <dipc.h>
64:
65: #include <mach/kern_return.h>
66: #include <mach/port.h>
67: #include <mach/vm_attributes.h>
68: #include <mach/vm_param.h>
69: #include <mach/vm_behavior.h>
70: #include <kern/assert.h>
71: #include <kern/counters.h>
72: #include <kern/zalloc.h>
73: #include <vm/vm_init.h>
74: #include <vm/vm_fault.h>
75: #include <vm/vm_map.h>
76: #include <vm/vm_object.h>
77: #include <vm/vm_page.h>
78: #include <vm/vm_kern.h>
79: #include <ipc/ipc_port.h>
80: #include <kern/sched_prim.h>
81: #include <kern/misc_protos.h>
82: #include <mach/vm_task_server.h>
83: #include <mach/mach_host_server.h>
84: #include <ddb/tr.h>
85: #include <kern/xpr.h>
86:
87: /* Internal prototypes
88: */
89: extern boolean_t vm_map_range_check(
90: vm_map_t map,
91: vm_offset_t start,
92: vm_offset_t end,
93: vm_map_entry_t *entry);
94:
95: extern vm_map_entry_t _vm_map_entry_create(
96: struct vm_map_header *map_header);
97:
98: extern void _vm_map_entry_dispose(
99: struct vm_map_header *map_header,
100: vm_map_entry_t entry);
101:
102: extern void vm_map_pmap_enter(
103: vm_map_t map,
104: vm_offset_t addr,
105: vm_offset_t end_addr,
106: vm_object_t object,
107: vm_offset_t offset,
108: vm_prot_t protection);
109:
110: extern void _vm_map_clip_end(
111: struct vm_map_header *map_header,
112: vm_map_entry_t entry,
113: vm_offset_t end);
114:
115: extern void vm_map_entry_delete(
116: vm_map_t map,
117: vm_map_entry_t entry);
118:
119: extern kern_return_t vm_map_delete(
120: vm_map_t map,
121: vm_offset_t start,
122: vm_offset_t end,
123: int flags);
124:
125: extern void vm_map_copy_steal_pages(
126: vm_map_copy_t copy);
127:
128: extern kern_return_t vm_map_copy_overwrite_unaligned(
129: vm_map_t dst_map,
130: vm_map_entry_t entry,
131: vm_map_copy_t copy,
132: vm_offset_t start);
133:
134: extern kern_return_t vm_map_copy_overwrite_aligned(
135: vm_map_t dst_map,
136: vm_map_entry_t tmp_entry,
137: vm_map_copy_t copy,
138: vm_offset_t start);
139:
140: extern kern_return_t vm_map_copyout_kernel_buffer(
141: vm_map_t map,
142: vm_offset_t *addr, /* IN/OUT */
143: vm_map_copy_t copy,
144: boolean_t overwrite);
145:
146: extern kern_return_t vm_map_copyin_page_list_cont(
147: vm_map_copyin_args_t cont_args,
148: vm_map_copy_t *copy_result); /* OUT */
149:
150: extern void vm_map_fork_share(
151: vm_map_t old_map,
152: vm_map_entry_t old_entry,
153: vm_map_t new_map);
154:
155: extern boolean_t vm_map_fork_copy(
156: vm_map_t old_map,
157: vm_map_entry_t *old_entry_p,
158: vm_map_t new_map);
159:
160: extern kern_return_t vm_remap_range_allocate(
161: vm_map_t map,
162: vm_offset_t *address, /* IN/OUT */
163: vm_size_t size,
164: vm_offset_t mask,
165: boolean_t anywhere,
166: vm_map_entry_t *map_entry); /* OUT */
167:
168: extern void _vm_map_clip_start(
169: struct vm_map_header *map_header,
170: vm_map_entry_t entry,
171: vm_offset_t start);
172:
173: /*
174: * Macros to copy a vm_map_entry. We must be careful to correctly
175: * manage the wired page count. vm_map_entry_copy() creates a new
176: * map entry to the same memory - the wired count in the new entry
177: * must be set to zero. vm_map_entry_copy_full() creates a new
178: * entry that is identical to the old entry. This preserves the
179: * wire count; it's used for map splitting and zone changing in
180: * vm_map_copyout.
181: */
182: #define vm_map_entry_copy(NEW,OLD) \
183: MACRO_BEGIN \
184: *(NEW) = *(OLD); \
185: (NEW)->is_shared = FALSE; \
186: (NEW)->needs_wakeup = FALSE; \
187: (NEW)->in_transition = FALSE; \
188: (NEW)->wired_count = 0; \
189: (NEW)->user_wired_count = 0; \
190: MACRO_END
191:
192: #define vm_map_entry_copy_full(NEW,OLD) (*(NEW) = *(OLD))
193:
194: /*
195: * Virtual memory maps provide for the mapping, protection,
196: * and sharing of virtual memory objects. In addition,
197: * this module provides for an efficient virtual copy of
198: * memory from one map to another.
199: *
200: * Synchronization is required prior to most operations.
201: *
202: * Maps consist of an ordered doubly-linked list of simple
203: * entries; a single hint is used to speed up lookups.
204: *
205: * Sharing maps have been deleted from this version of Mach.
206: * All shared objects are now mapped directly into the respective
207: * maps. This requires a change in the copy on write strategy;
208: * the asymmetric (delayed) strategy is used for shared temporary
209: * objects instead of the symmetric (shadow) strategy. All maps
210: * are now "top level" maps (either task map, kernel map or submap
211: * of the kernel map).
212: *
213: * Since portions of maps are specified by start/end addreses,
214: * which may not align with existing map entries, all
215: * routines merely "clip" entries to these start/end values.
216: * [That is, an entry is split into two, bordering at a
217: * start or end value.] Note that these clippings may not
218: * always be necessary (as the two resulting entries are then
219: * not changed); however, the clipping is done for convenience.
220: * No attempt is currently made to "glue back together" two
221: * abutting entries.
222: *
223: * The symmetric (shadow) copy strategy implements virtual copy
224: * by copying VM object references from one map to
225: * another, and then marking both regions as copy-on-write.
226: * It is important to note that only one writeable reference
227: * to a VM object region exists in any map when this strategy
228: * is used -- this means that shadow object creation can be
229: * delayed until a write operation occurs. The symmetric (delayed)
230: * strategy allows multiple maps to have writeable references to
231: * the same region of a vm object, and hence cannot delay creating
232: * its copy objects. See vm_object_copy_quickly() in vm_object.c.
233: * Copying of permanent objects is completely different; see
234: * vm_object_copy_strategically() in vm_object.c.
235: */
236:
237: zone_t vm_map_zone; /* zone for vm_map structures */
238: zone_t vm_map_entry_zone; /* zone for vm_map_entry structures */
239: zone_t vm_map_kentry_zone; /* zone for kernel entry structures */
240: zone_t vm_map_copy_zone; /* zone for vm_map_copy structures */
241:
242:
243: /*
244: * Placeholder object for submap operations. This object is dropped
245: * into the range by a call to vm_map_find, and removed when
246: * vm_map_submap creates the submap.
247: */
248:
249: vm_object_t vm_submap_object;
250:
251: /*
252: * vm_map_init:
253: *
254: * Initialize the vm_map module. Must be called before
255: * any other vm_map routines.
256: *
257: * Map and entry structures are allocated from zones -- we must
258: * initialize those zones.
259: *
260: * There are three zones of interest:
261: *
262: * vm_map_zone: used to allocate maps.
263: * vm_map_entry_zone: used to allocate map entries.
264: * vm_map_kentry_zone: used to allocate map entries for the kernel.
265: *
266: * The kernel allocates map entries from a special zone that is initially
267: * "crammed" with memory. It would be difficult (perhaps impossible) for
268: * the kernel to allocate more memory to a entry zone when it became
269: * empty since the very act of allocating memory implies the creation
270: * of a new entry.
271: */
272:
273: vm_offset_t map_data;
274: vm_size_t map_data_size;
275: vm_offset_t kentry_data;
276: vm_size_t kentry_data_size;
277: int kentry_count = 2048; /* to init kentry_data_size */
278:
279: /*
280: * Threshold for aggressive (eager) page map entering for vm copyout
281: * operations. Any copyout larger will NOT be aggressively entered.
282: */
283: vm_size_t vm_map_aggressive_enter_max; /* set by bootstrap */
284:
285: void
286: vm_map_init(
287: void)
288: {
289: vm_map_zone = zinit((vm_size_t) sizeof(struct vm_map), 40*1024,
290: PAGE_SIZE, "maps");
291:
292: vm_map_entry_zone = zinit((vm_size_t) sizeof(struct vm_map_entry),
293: 1024*1024, PAGE_SIZE*5,
294: "non-kernel map entries");
295:
296: vm_map_kentry_zone = zinit((vm_size_t) sizeof(struct vm_map_entry),
297: kentry_data_size, kentry_data_size,
298: "kernel map entries");
299:
300: vm_map_copy_zone = zinit((vm_size_t) sizeof(struct vm_map_copy),
301: 16*1024, PAGE_SIZE, "map copies");
302:
303: /*
304: * Cram the map and kentry zones with initial data.
305: * Set kentry_zone non-collectible to aid zone_gc().
306: */
307: zone_change(vm_map_zone, Z_COLLECT, FALSE);
308: zone_change(vm_map_kentry_zone, Z_COLLECT, FALSE);
309: zone_change(vm_map_kentry_zone, Z_EXPAND, FALSE);
310: zcram(vm_map_zone, map_data, map_data_size);
311: zcram(vm_map_kentry_zone, kentry_data, kentry_data_size);
312: }
313:
314: void
315: vm_map_steal_memory(
316: void)
317: {
318: map_data_size = round_page(10 * sizeof(struct vm_map));
319: map_data = pmap_steal_memory(map_data_size);
320:
321: /*
322: * Limiting worst case: vm_map_kentry_zone needs to map each "available"
323: * physical page (i.e. that beyond the kernel image and page tables)
324: * individually; we fudge this slightly and guess at most one entry per
325: * two pages. This works out to roughly .4 of 1% of physical memory,
326: * or roughly 1800 entries (56K) for a 16M machine with 4K pages.
327: */
328:
329: kentry_count = pmap_free_pages() / 2;
330:
331: kentry_data_size =
332: round_page(kentry_count * sizeof(struct vm_map_entry));
333: kentry_data = pmap_steal_memory(kentry_data_size);
334: }
335:
336: /*
337: * vm_map_create:
338: *
339: * Creates and returns a new empty VM map with
340: * the given physical map structure, and having
341: * the given lower and upper address bounds.
342: */
343: vm_map_t
344: vm_map_create(
345: pmap_t pmap,
346: vm_offset_t min,
347: vm_offset_t max,
348: boolean_t pageable)
349: {
350: register vm_map_t result;
351:
352: result = (vm_map_t) zalloc(vm_map_zone);
353: if (result == VM_MAP_NULL)
354: panic("vm_map_create");
355:
356: vm_map_first_entry(result) = vm_map_to_entry(result);
357: vm_map_last_entry(result) = vm_map_to_entry(result);
358: result->hdr.nentries = 0;
359: result->hdr.entries_pageable = pageable;
360:
361: result->size = 0;
362: result->ref_count = 1;
363: #if TASK_SWAPPER
364: result->res_count = 1;
365: result->sw_state = MAP_SW_IN;
366: #endif /* TASK_SWAPPER */
367: result->pmap = pmap;
368: result->min_offset = min;
369: result->max_offset = max;
370: result->wiring_required = FALSE;
371: result->no_zero_fill = FALSE;
372: result->wait_for_space = FALSE;
373: result->first_free = vm_map_to_entry(result);
374: result->hint = vm_map_to_entry(result);
375: vm_map_lock_init(result);
376: mutex_init(&result->s_lock, ETAP_VM_RESULT);
377:
378: return(result);
379: }
380:
381: /*
382: * vm_map_entry_create: [ internal use only ]
383: *
384: * Allocates a VM map entry for insertion in the
385: * given map (or map copy). No fields are filled.
386: */
387: #define vm_map_entry_create(map) \
388: _vm_map_entry_create(&(map)->hdr)
389:
390: #define vm_map_copy_entry_create(copy) \
391: _vm_map_entry_create(&(copy)->cpy_hdr)
392:
393: vm_map_entry_t
394: _vm_map_entry_create(
395: register struct vm_map_header *map_header)
396: {
397: register zone_t zone;
398: register vm_map_entry_t entry;
399:
400: if (map_header->entries_pageable)
401: zone = vm_map_entry_zone;
402: else
403: zone = vm_map_kentry_zone;
404:
405: entry = (vm_map_entry_t) zalloc(zone);
406: if (entry == VM_MAP_ENTRY_NULL)
407: panic("vm_map_entry_create");
408:
409: return(entry);
410: }
411:
412: /*
413: * vm_map_entry_dispose: [ internal use only ]
414: *
415: * Inverse of vm_map_entry_create.
416: */
417: #define vm_map_entry_dispose(map, entry) \
418: MACRO_BEGIN \
419: assert((entry) != (map)->first_free && \
420: (entry) != (map)->hint); \
421: _vm_map_entry_dispose(&(map)->hdr, (entry)); \
422: MACRO_END
423:
424: #define vm_map_copy_entry_dispose(map, entry) \
425: _vm_map_entry_dispose(&(copy)->cpy_hdr, (entry))
426:
427: void
428: _vm_map_entry_dispose(
429: register struct vm_map_header *map_header,
430: register vm_map_entry_t entry)
431: {
432: register zone_t zone;
433:
434: if (map_header->entries_pageable)
435: zone = vm_map_entry_zone;
436: else
437: zone = vm_map_kentry_zone;
438:
439: zfree(zone, (vm_offset_t) entry);
440: }
441:
442: boolean_t first_free_is_valid(vm_map_t map); /* forward */
443: boolean_t first_free_check = FALSE;
444: boolean_t
445: first_free_is_valid(
446: vm_map_t map)
447: {
448: vm_map_entry_t entry, next;
449:
450: if (!first_free_check)
451: return TRUE;
452:
453: entry = vm_map_to_entry(map);
454: next = entry->vme_next;
455: while (trunc_page(next->vme_start) == trunc_page(entry->vme_end) ||
456: (trunc_page(next->vme_start) == trunc_page(entry->vme_start) &&
457: next != vm_map_to_entry(map))) {
458: entry = next;
459: next = entry->vme_next;
460: if (entry == vm_map_to_entry(map))
461: break;
462: }
463: if (map->first_free != entry) {
464: printf("Bad first_free for map 0x%x: 0x%x should be 0x%x\n",
465: map, map->first_free, entry);
466: return FALSE;
467: }
468: return TRUE;
469: }
470:
471: /*
472: * UPDATE_FIRST_FREE:
473: *
474: * Updates the map->first_free pointer to the
475: * entry immediately before the first hole in the map.
476: * The map should be locked.
477: */
478: #define UPDATE_FIRST_FREE(map, new_first_free) \
479: MACRO_BEGIN \
480: vm_map_t UFF_map; \
481: vm_map_entry_t UFF_first_free; \
482: vm_map_entry_t UFF_next_entry; \
483: UFF_map = (map); \
484: UFF_first_free = (new_first_free); \
485: UFF_next_entry = UFF_first_free->vme_next; \
486: while (trunc_page(UFF_next_entry->vme_start) == \
487: trunc_page(UFF_first_free->vme_end) || \
488: (trunc_page(UFF_next_entry->vme_start) == \
489: trunc_page(UFF_first_free->vme_start) && \
490: UFF_next_entry != vm_map_to_entry(UFF_map))) { \
491: UFF_first_free = UFF_next_entry; \
492: UFF_next_entry = UFF_first_free->vme_next; \
493: if (UFF_first_free == vm_map_to_entry(UFF_map)) \
494: break; \
495: } \
496: UFF_map->first_free = UFF_first_free; \
497: assert(first_free_is_valid(UFF_map)); \
498: MACRO_END
499:
500: /*
501: * vm_map_entry_{un,}link:
502: *
503: * Insert/remove entries from maps (or map copies).
504: */
505: #define vm_map_entry_link(map, after_where, entry) \
506: MACRO_BEGIN \
507: vm_map_t VMEL_map; \
508: vm_map_entry_t VMEL_entry; \
509: VMEL_map = (map); \
510: VMEL_entry = (entry); \
511: _vm_map_entry_link(&VMEL_map->hdr, after_where, VMEL_entry); \
512: UPDATE_FIRST_FREE(VMEL_map, VMEL_map->first_free); \
513: MACRO_END
514:
515:
516: #define vm_map_copy_entry_link(copy, after_where, entry) \
517: _vm_map_entry_link(&(copy)->cpy_hdr, after_where, (entry))
518:
519: #define _vm_map_entry_link(hdr, after_where, entry) \
520: MACRO_BEGIN \
521: (hdr)->nentries++; \
522: (entry)->vme_prev = (after_where); \
523: (entry)->vme_next = (after_where)->vme_next; \
524: (entry)->vme_prev->vme_next = (entry)->vme_next->vme_prev = (entry); \
525: MACRO_END
526:
527: #define vm_map_entry_unlink(map, entry) \
528: MACRO_BEGIN \
529: vm_map_t VMEU_map; \
530: vm_map_entry_t VMEU_entry; \
531: vm_map_entry_t VMEU_first_free; \
532: VMEU_map = (map); \
533: VMEU_entry = (entry); \
534: if (VMEU_entry->vme_start <= VMEU_map->first_free->vme_start) \
535: VMEU_first_free = VMEU_entry->vme_prev; \
536: else \
537: VMEU_first_free = VMEU_map->first_free; \
538: _vm_map_entry_unlink(&VMEU_map->hdr, VMEU_entry); \
539: UPDATE_FIRST_FREE(VMEU_map, VMEU_first_free); \
540: MACRO_END
541:
542: #define vm_map_copy_entry_unlink(copy, entry) \
543: _vm_map_entry_unlink(&(copy)->cpy_hdr, (entry))
544:
545: #define _vm_map_entry_unlink(hdr, entry) \
546: MACRO_BEGIN \
547: (hdr)->nentries--; \
548: (entry)->vme_next->vme_prev = (entry)->vme_prev; \
549: (entry)->vme_prev->vme_next = (entry)->vme_next; \
550: MACRO_END
551:
552: #if MACH_ASSERT && TASK_SWAPPER
553: /*
554: * vm_map_reference:
555: *
556: * Adds valid reference and residence counts to the given map.
557: * The map must be in memory (i.e. non-zero residence count).
558: *
559: */
560: void
561: vm_map_reference(
562: register vm_map_t map)
563: {
564: if (map == VM_MAP_NULL)
565: return;
566:
567: mutex_lock(&map->s_lock);
568: assert(map->res_count > 0);
569: assert(map->ref_count >= map->res_count);
570: map->ref_count++;
571: map->res_count++;
572: mutex_unlock(&map->s_lock);
573: }
574:
575: /*
576: * vm_map_res_reference:
577: *
578: * Adds another valid residence count to the given map.
579: *
580: * Map is locked so this function can be called from
581: * vm_map_swapin.
582: *
583: */
584: void vm_map_res_reference(register vm_map_t map)
585: {
586: /* assert map is locked */
587: assert(map->res_count >= 0);
588: assert(map->ref_count >= map->res_count);
589: if (map->res_count == 0) {
590: mutex_unlock(&map->s_lock);
591: vm_map_lock(map);
592: vm_map_swapin(map);
593: mutex_lock(&map->s_lock);
594: ++map->res_count;
595: vm_map_unlock(map);
596: } else
597: ++map->res_count;
598: }
599:
600: /*
601: * vm_map_reference_swap:
602: *
603: * Adds valid reference and residence counts to the given map.
604: *
605: * The map may not be in memory (i.e. zero residence count).
606: *
607: */
608: void vm_map_reference_swap(register vm_map_t map)
609: {
610: assert(map != VM_MAP_NULL);
611: mutex_lock(&map->s_lock);
612: assert(map->res_count >= 0);
613: assert(map->ref_count >= map->res_count);
614: map->ref_count++;
615: vm_map_res_reference(map);
616: mutex_unlock(&map->s_lock);
617: }
618:
619: /*
620: * vm_map_res_deallocate:
621: *
622: * Decrement residence count on a map; possibly causing swapout.
623: *
624: * The map must be in memory (i.e. non-zero residence count).
625: *
626: * The map is locked, so this function is callable from vm_map_deallocate.
627: *
628: */
629: void vm_map_res_deallocate(register vm_map_t map)
630: {
631: assert(map->res_count > 0);
632: if (--map->res_count == 0) {
633: mutex_unlock(&map->s_lock);
634: vm_map_lock(map);
635: vm_map_swapout(map);
636: vm_map_unlock(map);
637: mutex_lock(&map->s_lock);
638: }
639: assert(map->ref_count >= map->res_count);
640: }
641: #endif /* MACH_ASSERT && TASK_SWAPPER */
642:
643: /*
644: * vm_map_deallocate:
645: *
646: * Removes a reference from the specified map,
647: * destroying it if no references remain.
648: * The map should not be locked.
649: */
650: void
651: vm_map_deallocate(
652: register vm_map_t map)
653: {
654: unsigned int ref;
655:
656: if (map == VM_MAP_NULL)
657: return;
658:
659: mutex_lock(&map->s_lock);
660: ref = --map->ref_count;
661: if (ref > 0) {
662: vm_map_res_deallocate(map);
663: mutex_unlock(&map->s_lock);
664: /*
665: * Someone may be waiting in task_halt_wait. They
666: * wait there for the map reference count to reach
667: * two (one for the task and one for their act). Wake
668: * them up if need be.
669: */
670: if (ref == 2)
671: thread_wakeup(&map->ref_count);
672: return;
673: }
674: assert(map->ref_count == 0);
675: mutex_unlock(&map->s_lock);
676:
677: #if TASK_SWAPPER
678: /*
679: * The map residence count isn't decremented here because
680: * the vm_map_delete below will traverse the entire map,
681: * deleting entries, and the residence counts on objects
682: * and sharing maps will go away then.
683: */
684: #endif
685:
686: vm_map_destroy(map);
687: }
688:
689: /*
690: * vm_map_destroy:
691: *
692: * Actually destroy a map.
693: */
694: void
695: vm_map_destroy(
696: register vm_map_t map)
697: {
698: vm_map_lock(map);
699: (void) vm_map_delete(map, map->min_offset,
700: map->max_offset, VM_MAP_NO_FLAGS);
701: vm_map_unlock(map);
702:
703: pmap_destroy(map->pmap);
704:
705: zfree(vm_map_zone, (vm_offset_t) map);
706: }
707:
708: #if TASK_SWAPPER
709: /*
710: * vm_map_swapin/vm_map_swapout
711: *
712: * Swap a map in and out, either referencing or releasing its resources.
713: * These functions are internal use only; however, they must be exported
714: * because they may be called from macros, which are exported.
715: *
716: * In the case of swapout, there could be races on the residence count,
717: * so if the residence count is up, we return, assuming that a
718: * vm_map_deallocate() call in the near future will bring us back.
719: *
720: * Locking:
721: * -- We use the map write lock for synchronization among races.
722: * -- The map write lock, and not the simple s_lock, protects the
723: * swap state of the map.
724: * -- If a map entry is a share map, then we hold both locks, in
725: * hierarchical order.
726: *
727: * Synchronization Notes:
728: * 1) If a vm_map_swapin() call happens while swapout in progress, it
729: * will block on the map lock and proceed when swapout is through.
730: * 2) A vm_map_reference() call at this time is illegal, and will
731: * cause a panic. vm_map_reference() is only allowed on resident
732: * maps, since it refuses to block.
733: * 3) A vm_map_swapin() call during a swapin will block, and
734: * proceeed when the first swapin is done, turning into a nop.
735: * This is the reason the res_count is not incremented until
736: * after the swapin is complete.
737: * 4) There is a timing hole after the checks of the res_count, before
738: * the map lock is taken, during which a swapin may get the lock
739: * before a swapout about to happen. If this happens, the swapin
740: * will detect the state and increment the reference count, causing
741: * the swapout to be a nop, thereby delaying it until a later
742: * vm_map_deallocate. If the swapout gets the lock first, then
743: * the swapin will simply block until the swapout is done, and
744: * then proceed.
745: *
746: * Because vm_map_swapin() is potentially an expensive operation, it
747: * should be used with caution.
748: *
749: * Invariants:
750: * 1) A map with a residence count of zero is either swapped, or
751: * being swapped.
752: * 2) A map with a non-zero residence count is either resident,
753: * or being swapped in.
754: */
755:
756: int vm_map_swap_enable = 1;
757:
758: void vm_map_swapin (vm_map_t map)
759: {
760: register vm_map_entry_t entry;
761:
762: if (!vm_map_swap_enable) /* debug */
763: return;
764:
765: /*
766: * Map is locked
767: * First deal with various races.
768: */
769: if (map->sw_state == MAP_SW_IN)
770: /*
771: * we raced with swapout and won. Returning will incr.
772: * the res_count, turning the swapout into a nop.
773: */
774: return;
775:
776: /*
777: * The residence count must be zero. If we raced with another
778: * swapin, the state would have been IN; if we raced with a
779: * swapout (after another competing swapin), we must have lost
780: * the race to get here (see above comment), in which case
781: * res_count is still 0.
782: */
783: assert(map->res_count == 0);
784:
785: /*
786: * There are no intermediate states of a map going out or
787: * coming in, since the map is locked during the transition.
788: */
789: assert(map->sw_state == MAP_SW_OUT);
790:
791: /*
792: * We now operate upon each map entry. If the entry is a sub-
793: * or share-map, we call vm_map_res_reference upon it.
794: * If the entry is an object, we call vm_object_res_reference
795: * (this may iterate through the shadow chain).
796: * Note that we hold the map locked the entire time,
797: * even if we get back here via a recursive call in
798: * vm_map_res_reference.
799: */
800: entry = vm_map_first_entry(map);
801:
802: while (entry != vm_map_to_entry(map)) {
803: if (entry->object.vm_object != VM_OBJECT_NULL) {
804: if (entry->is_sub_map) {
805: vm_map_t lmap = entry->object.sub_map;
806: mutex_lock(&lmap->s_lock);
807: vm_map_res_reference(lmap);
808: mutex_unlock(&lmap->s_lock);
809: } else {
810: vm_object_t object = entry->object.vm_object;
811: vm_object_lock(object);
812: /*
813: * This call may iterate through the
814: * shadow chain.
815: */
816: vm_object_res_reference(object);
817: vm_object_unlock(object);
818: }
819: }
820: entry = entry->vme_next;
821: }
822: assert(map->sw_state == MAP_SW_OUT);
823: map->sw_state = MAP_SW_IN;
824: }
825:
826: void vm_map_swapout(vm_map_t map)
827: {
828: register vm_map_entry_t entry;
829:
830: /*
831: * Map is locked
832: * First deal with various races.
833: * If we raced with a swapin and lost, the residence count
834: * will have been incremented to 1, and we simply return.
835: */
836: mutex_lock(&map->s_lock);
837: if (map->res_count != 0) {
838: mutex_unlock(&map->s_lock);
839: return;
840: }
841: mutex_unlock(&map->s_lock);
842:
843: /*
844: * There are no intermediate states of a map going out or
845: * coming in, since the map is locked during the transition.
846: */
847: assert(map->sw_state == MAP_SW_IN);
848:
849: if (!vm_map_swap_enable)
850: return;
851:
852: /*
853: * We now operate upon each map entry. If the entry is a sub-
854: * or share-map, we call vm_map_res_deallocate upon it.
855: * If the entry is an object, we call vm_object_res_deallocate
856: * (this may iterate through the shadow chain).
857: * Note that we hold the map locked the entire time,
858: * even if we get back here via a recursive call in
859: * vm_map_res_deallocate.
860: */
861: entry = vm_map_first_entry(map);
862:
863: while (entry != vm_map_to_entry(map)) {
864: if (entry->object.vm_object != VM_OBJECT_NULL) {
865: if (entry->is_sub_map) {
866: vm_map_t lmap = entry->object.sub_map;
867: mutex_lock(&lmap->s_lock);
868: vm_map_res_deallocate(lmap);
869: mutex_unlock(&lmap->s_lock);
870: } else {
871: vm_object_t object = entry->object.vm_object;
872: vm_object_lock(object);
873: /*
874: * This call may take a long time,
875: * since it could actively push
876: * out pages (if we implement it
877: * that way).
878: */
879: vm_object_res_deallocate(object);
880: vm_object_unlock(object);
881: }
882: }
883: entry = entry->vme_next;
884: }
885: assert(map->sw_state == MAP_SW_IN);
886: map->sw_state = MAP_SW_OUT;
887: }
888:
889: #endif /* TASK_SWAPPER */
890:
891:
892: /*
893: * SAVE_HINT:
894: *
895: * Saves the specified entry as the hint for
896: * future lookups. Performs necessary interlocks.
897: */
898: #define SAVE_HINT(map,value) \
899: mutex_lock(&(map)->s_lock); \
900: (map)->hint = (value); \
901: mutex_unlock(&(map)->s_lock);
902:
903: /*
904: * vm_map_lookup_entry: [ internal use only ]
905: *
906: * Finds the map entry containing (or
907: * immediately preceding) the specified address
908: * in the given map; the entry is returned
909: * in the "entry" parameter. The boolean
910: * result indicates whether the address is
911: * actually contained in the map.
912: */
913: boolean_t
914: vm_map_lookup_entry(
915: register vm_map_t map,
916: register vm_offset_t address,
917: vm_map_entry_t *entry) /* OUT */
918: {
919: register vm_map_entry_t cur;
920: register vm_map_entry_t last;
921:
922: /*
923: * Start looking either from the head of the
924: * list, or from the hint.
925: */
926:
927: mutex_lock(&map->s_lock);
928: cur = map->hint;
929: mutex_unlock(&map->s_lock);
930:
931: if (cur == vm_map_to_entry(map))
932: cur = cur->vme_next;
933:
934: if (address >= cur->vme_start) {
935: /*
936: * Go from hint to end of list.
937: *
938: * But first, make a quick check to see if
939: * we are already looking at the entry we
940: * want (which is usually the case).
941: * Note also that we don't need to save the hint
942: * here... it is the same hint (unless we are
943: * at the header, in which case the hint didn't
944: * buy us anything anyway).
945: */
946: last = vm_map_to_entry(map);
947: if ((cur != last) && (cur->vme_end > address)) {
948: *entry = cur;
949: return(TRUE);
950: }
951: }
952: else {
953: /*
954: * Go from start to hint, *inclusively*
955: */
956: last = cur->vme_next;
957: cur = vm_map_first_entry(map);
958: }
959:
960: /*
961: * Search linearly
962: */
963:
964: while (cur != last) {
965: if (cur->vme_end > address) {
966: if (address >= cur->vme_start) {
967: /*
968: * Save this lookup for future
969: * hints, and return
970: */
971:
972: *entry = cur;
973: SAVE_HINT(map, cur);
974: return(TRUE);
975: }
976: break;
977: }
978: cur = cur->vme_next;
979: }
980: *entry = cur->vme_prev;
981: SAVE_HINT(map, *entry);
982: return(FALSE);
983: }
984:
985: /*
986: * Routine: vm_map_find_space
987: * Purpose:
988: * Allocate a range in the specified virtual address map,
989: * returning the entry allocated for that range.
990: * Used by kmem_alloc, etc.
991: *
992: * The map must be NOT be locked. It will be returned locked
993: * on KERN_SUCCESS, unlocked on failure.
994: *
995: * If an entry is allocated, the object/offset fields
996: * are initialized to zero.
997: */
998: kern_return_t
999: vm_map_find_space(
1000: register vm_map_t map,
1001: vm_offset_t *address, /* OUT */
1002: vm_size_t size,
1003: vm_offset_t mask,
1004: vm_map_entry_t *o_entry) /* OUT */
1005: {
1006: register vm_map_entry_t entry, new_entry;
1007: register vm_offset_t start;
1008: register vm_offset_t end;
1009:
1010: new_entry = vm_map_entry_create(map);
1011:
1012: /*
1013: * Look for the first possible address; if there's already
1014: * something at this address, we have to start after it.
1015: */
1016:
1017: vm_map_lock(map);
1018:
1019: assert(first_free_is_valid(map));
1020: if ((entry = map->first_free) == vm_map_to_entry(map))
1021: start = map->min_offset;
1022: else
1023: start = entry->vme_end;
1024:
1025: /*
1026: * In any case, the "entry" always precedes
1027: * the proposed new region throughout the loop:
1028: */
1029:
1030: while (TRUE) {
1031: register vm_map_entry_t next;
1032:
1033: /*
1034: * Find the end of the proposed new region.
1035: * Be sure we didn't go beyond the end, or
1036: * wrap around the address.
1037: */
1038:
1039: end = ((start + mask) & ~mask);
1040: if (end < start) {
1041: vm_map_entry_dispose(map, new_entry);
1042: vm_map_unlock(map);
1043: return(KERN_NO_SPACE);
1044: }
1045: start = end;
1046: end += size;
1047:
1048: if ((end > map->max_offset) || (end < start)) {
1049: vm_map_entry_dispose(map, new_entry);
1050: vm_map_unlock(map);
1051: return(KERN_NO_SPACE);
1052: }
1053:
1054: /*
1055: * If there are no more entries, we must win.
1056: */
1057:
1058: next = entry->vme_next;
1059: if (next == vm_map_to_entry(map))
1060: break;
1061:
1062: /*
1063: * If there is another entry, it must be
1064: * after the end of the potential new region.
1065: */
1066:
1067: if (next->vme_start >= end)
1068: break;
1069:
1070: /*
1071: * Didn't fit -- move to the next entry.
1072: */
1073:
1074: entry = next;
1075: start = entry->vme_end;
1076: }
1077:
1078: /*
1079: * At this point,
1080: * "start" and "end" should define the endpoints of the
1081: * available new range, and
1082: * "entry" should refer to the region before the new
1083: * range, and
1084: *
1085: * the map should be locked.
1086: */
1087:
1088: *address = start;
1089:
1090: new_entry->vme_start = start;
1091: new_entry->vme_end = end;
1092: assert(page_aligned(new_entry->vme_start));
1093: assert(page_aligned(new_entry->vme_end));
1094:
1095: new_entry->is_shared = FALSE;
1096: new_entry->is_sub_map = FALSE;
1097: new_entry->object.vm_object = VM_OBJECT_NULL;
1098: new_entry->offset = (vm_offset_t) 0;
1099:
1100: new_entry->needs_copy = FALSE;
1101:
1102: new_entry->inheritance = VM_INHERIT_DEFAULT;
1103: new_entry->protection = VM_PROT_DEFAULT;
1104: new_entry->max_protection = VM_PROT_ALL;
1105: new_entry->behavior = VM_BEHAVIOR_DEFAULT;
1106: new_entry->wired_count = 0;
1107: new_entry->user_wired_count = 0;
1108:
1109: new_entry->in_transition = FALSE;
1110: new_entry->needs_wakeup = FALSE;
1111:
1112: /*
1113: * Insert the new entry into the list
1114: */
1115:
1116: vm_map_entry_link(map, entry, new_entry);
1117:
1118: map->size += size;
1119:
1120: /*
1121: * Update the lookup hint
1122: */
1123: SAVE_HINT(map, new_entry);
1124:
1125: *o_entry = new_entry;
1126: return(KERN_SUCCESS);
1127: }
1128:
1129: int vm_map_pmap_enter_print = FALSE;
1130: int vm_map_pmap_enter_enable = FALSE;
1131:
1132: /*
1133: * Routine: vm_map_pmap_enter
1134: *
1135: * Description:
1136: * Force pages from the specified object to be entered into
1137: * the pmap at the specified address if they are present.
1138: * As soon as a page not found in the object the scan ends.
1139: *
1140: * Returns:
1141: * Nothing.
1142: *
1143: * In/out conditions:
1144: * The source map should not be locked on entry.
1145: */
1146: void
1147: vm_map_pmap_enter(
1148: vm_map_t map,
1149: register vm_offset_t addr,
1150: register vm_offset_t end_addr,
1151: register vm_object_t object,
1152: vm_offset_t offset,
1153: vm_prot_t protection)
1154: {
1155: while (addr < end_addr) {
1156: register vm_page_t m;
1157:
1158: vm_object_lock(object);
1159: vm_object_paging_begin(object);
1160:
1161: m = vm_page_lookup(object, offset);
1162: if (m == VM_PAGE_NULL || m->busy ||
1163: (m->unusual && ( m->error || m->restart || m->absent ||
1164: protection & m->page_lock))) {
1165:
1166: vm_object_paging_end(object);
1167: vm_object_unlock(object);
1168: return;
1169: }
1170:
1171: assert(!m->fictitious); /* XXX is this possible ??? */
1172:
1173: if (vm_map_pmap_enter_print) {
1174: printf("vm_map_pmap_enter:");
1175: printf("map: %x, addr: %x, object: %x, offset: %x\n",
1176: map, addr, object, offset);
1177: }
1178:
1179: m->busy = TRUE;
1180: vm_object_unlock(object);
1181:
1182: PMAP_ENTER(map->pmap, addr, m,
1183: protection, FALSE);
1184:
1185: vm_object_lock(object);
1186: PAGE_WAKEUP_DONE(m);
1187: vm_page_lock_queues();
1188: if (!m->active && !m->inactive)
1189: vm_page_activate(m);
1190: vm_page_unlock_queues();
1191: vm_object_paging_end(object);
1192: vm_object_unlock(object);
1193:
1194: offset += PAGE_SIZE;
1195: addr += PAGE_SIZE;
1196: }
1197: }
1198:
1199: /*
1200: * Routine: vm_map_enter
1201: *
1202: * Description:
1203: * Allocate a range in the specified virtual address map.
1204: * The resulting range will refer to memory defined by
1205: * the given memory object and offset into that object.
1206: *
1207: * Arguments are as defined in the vm_map call.
1208: */
1209: kern_return_t
1210: vm_map_enter(
1211: register vm_map_t map,
1212: vm_offset_t *address, /* IN/OUT */
1213: vm_size_t size,
1214: vm_offset_t mask,
1215: int flags,
1216: vm_object_t object,
1217: vm_offset_t offset,
1218: boolean_t needs_copy,
1219: vm_prot_t cur_protection,
1220: vm_prot_t max_protection,
1221: vm_inherit_t inheritance)
1222: {
1223: vm_map_entry_t entry;
1224: register vm_offset_t start;
1225: register vm_offset_t end;
1226: kern_return_t result = KERN_SUCCESS;
1227:
1228: boolean_t anywhere = VM_FLAGS_ANYWHERE & flags;
1229: char alias;
1230:
1231: VM_GET_FLAGS_ALIAS(flags, alias);
1232:
1233: #define RETURN(value) { result = value; goto BailOut; }
1234:
1235: assert(page_aligned(*address));
1236: assert(page_aligned(size));
1237: StartAgain: ;
1238:
1239: start = *address;
1240:
1241: if (anywhere) {
1242: vm_map_lock(map);
1243:
1244: /*
1245: * Calculate the first possible address.
1246: */
1247:
1248: if (start < map->min_offset)
1249: start = map->min_offset;
1250: if (start > map->max_offset)
1251: RETURN(KERN_NO_SPACE);
1252:
1253: /*
1254: * Look for the first possible address;
1255: * if there's already something at this
1256: * address, we have to start after it.
1257: */
1258:
1259: assert(first_free_is_valid(map));
1260: if (start == map->min_offset) {
1261: if ((entry = map->first_free) != vm_map_to_entry(map))
1262: start = entry->vme_end;
1263: } else {
1264: vm_map_entry_t tmp_entry;
1265: if (vm_map_lookup_entry(map, start, &tmp_entry))
1266: start = tmp_entry->vme_end;
1267: entry = tmp_entry;
1268: }
1269:
1270: /*
1271: * In any case, the "entry" always precedes
1272: * the proposed new region throughout the
1273: * loop:
1274: */
1275:
1276: while (TRUE) {
1277: register vm_map_entry_t next;
1278:
1279: /*
1280: * Find the end of the proposed new region.
1281: * Be sure we didn't go beyond the end, or
1282: * wrap around the address.
1283: */
1284:
1285: end = ((start + mask) & ~mask);
1286: if (end < start)
1287: RETURN(KERN_NO_SPACE);
1288: start = end;
1289: end += size;
1290:
1291: if ((end > map->max_offset) || (end < start)) {
1292: if (map->wait_for_space) {
1293: if (size <= (map->max_offset -
1294: map->min_offset)) {
1295: assert_wait((event_t)map,
1296: THREAD_ABORTSAFE);
1297: vm_map_unlock(map);
1298: thread_block((void (*)(void))0);
1299: goto StartAgain;
1300: }
1301: }
1302: RETURN(KERN_NO_SPACE);
1303: }
1304:
1305: /*
1306: * If there are no more entries, we must win.
1307: */
1308:
1309: next = entry->vme_next;
1310: if (next == vm_map_to_entry(map))
1311: break;
1312:
1313: /*
1314: * If there is another entry, it must be
1315: * after the end of the potential new region.
1316: */
1317:
1318: if (next->vme_start >= end)
1319: break;
1320:
1321: /*
1322: * Didn't fit -- move to the next entry.
1323: */
1324:
1325: entry = next;
1326: start = entry->vme_end;
1327: }
1328: *address = start;
1329: } else {
1330: vm_map_entry_t temp_entry;
1331:
1332: /*
1333: * Verify that:
1334: * the address doesn't itself violate
1335: * the mask requirement.
1336: */
1337:
1338: vm_map_lock(map);
1339: if ((start & mask) != 0)
1340: RETURN(KERN_NO_SPACE);
1341:
1342: /*
1343: * ... the address is within bounds
1344: */
1345:
1346: end = start + size;
1347:
1348: if ((start < map->min_offset) ||
1349: (end > map->max_offset) ||
1350: (start >= end)) {
1351: RETURN(KERN_INVALID_ADDRESS);
1352: }
1353:
1354: /*
1355: * ... the starting address isn't allocated
1356: */
1357:
1358: if (vm_map_lookup_entry(map, start, &temp_entry))
1359: RETURN(KERN_NO_SPACE);
1360:
1361: entry = temp_entry;
1362:
1363: /*
1364: * ... the next region doesn't overlap the
1365: * end point.
1366: */
1367:
1368: if ((entry->vme_next != vm_map_to_entry(map)) &&
1369: (entry->vme_next->vme_start < end))
1370: RETURN(KERN_NO_SPACE);
1371: }
1372:
1373: /*
1374: * At this point,
1375: * "start" and "end" should define the endpoints of the
1376: * available new range, and
1377: * "entry" should refer to the region before the new
1378: * range, and
1379: *
1380: * the map should be locked.
1381: */
1382:
1383: /*
1384: * See whether we can avoid creating a new entry (and object) by
1385: * extending one of our neighbors. [So far, we only attempt to
1386: * extend from below.]
1387: */
1388:
1389: if ((object == VM_OBJECT_NULL) &&
1390: (entry != vm_map_to_entry(map)) &&
1391: (entry->vme_end == start) &&
1392: (!entry->is_shared) &&
1393: (!entry->is_sub_map) &&
1394: (entry->alias == alias) &&
1395: (entry->inheritance == inheritance) &&
1396: (entry->protection == cur_protection) &&
1397: (entry->max_protection == max_protection) &&
1398: (entry->behavior == VM_BEHAVIOR_DEFAULT) &&
1399: (entry->in_transition == 0) &&
1400: (entry->wired_count == 0)) { /* implies user_wired_count == 0 */
1401: if (vm_object_coalesce(entry->object.vm_object,
1402: VM_OBJECT_NULL,
1403: entry->offset,
1404: (vm_offset_t) 0,
1405: (vm_size_t)(entry->vme_end - entry->vme_start),
1406: (vm_size_t)(end - entry->vme_end))) {
1407:
1408: /*
1409: * Coalesced the two objects - can extend
1410: * the previous map entry to include the
1411: * new range.
1412: */
1413: map->size += (end - entry->vme_end);
1414: entry->vme_end = end;
1415: UPDATE_FIRST_FREE(map, map->first_free);
1416: RETURN(KERN_SUCCESS);
1417: }
1418: }
1419:
1420: /*
1421: * Create a new entry
1422: */
1423:
1424: { /**/
1425: register vm_map_entry_t new_entry;
1426:
1427: new_entry = vm_map_entry_insert(map, entry, start, end, object,
1428: offset, needs_copy, FALSE, FALSE,
1429: cur_protection, max_protection,
1430: VM_BEHAVIOR_DEFAULT, inheritance, 0);
1431: new_entry->alias = alias;
1432: vm_map_unlock(map);
1433:
1434: /* Wire down the new entry if the user
1435: * requested all new map entries be wired.
1436: */
1437: if (map->wiring_required) {
1438: result = vm_map_wire(map, start, end,
1439: new_entry->protection, TRUE);
1440: return(result);
1441: }
1442:
1443: if ((object != VM_OBJECT_NULL) &&
1444: (vm_map_pmap_enter_enable) &&
1445: (!anywhere) &&
1446: (!needs_copy) &&
1447: (size < (128*1024))) {
1448: vm_map_pmap_enter(map, start, end,
1449: object, offset, cur_protection);
1450: }
1451:
1452: return(result);
1453: } /**/
1454:
1455: BailOut: ;
1456: vm_map_unlock(map);
1457: return(result);
1458:
1459: #undef RETURN
1460: }
1461:
1462: /*
1463: * vm_map_clip_start: [ internal use only ]
1464: *
1465: * Asserts that the given entry begins at or after
1466: * the specified address; if necessary,
1467: * it splits the entry into two.
1468: */
1469: #define vm_map_clip_start(map, entry, startaddr) \
1470: MACRO_BEGIN \
1471: vm_map_t VMCS_map; \
1472: vm_map_entry_t VMCS_entry; \
1473: vm_offset_t VMCS_startaddr; \
1474: VMCS_map = (map); \
1475: VMCS_entry = (entry); \
1476: VMCS_startaddr = (startaddr); \
1477: if (VMCS_startaddr > VMCS_entry->vme_start) \
1478: _vm_map_clip_start(&VMCS_map->hdr,VMCS_entry,VMCS_startaddr);\
1479: UPDATE_FIRST_FREE(VMCS_map, VMCS_map->first_free); \
1480: MACRO_END
1481:
1482: #define vm_map_copy_clip_start(copy, entry, startaddr) \
1483: MACRO_BEGIN \
1484: if ((startaddr) > (entry)->vme_start) \
1485: _vm_map_clip_start(&(copy)->cpy_hdr,(entry),(startaddr)); \
1486: MACRO_END
1487:
1488: /*
1489: * This routine is called only when it is known that
1490: * the entry must be split.
1491: */
1492: void
1493: _vm_map_clip_start(
1494: register struct vm_map_header *map_header,
1495: register vm_map_entry_t entry,
1496: register vm_offset_t start)
1497: {
1498: register vm_map_entry_t new_entry;
1499:
1500: /*
1501: * Split off the front portion --
1502: * note that we must insert the new
1503: * entry BEFORE this one, so that
1504: * this entry has the specified starting
1505: * address.
1506: */
1507:
1508: new_entry = _vm_map_entry_create(map_header);
1509: vm_map_entry_copy_full(new_entry, entry);
1510:
1511: new_entry->vme_end = start;
1512: entry->offset += (start - entry->vme_start);
1513: entry->vme_start = start;
1514:
1515: _vm_map_entry_link(map_header, entry->vme_prev, new_entry);
1516:
1517: if (entry->is_sub_map)
1518: vm_map_reference(new_entry->object.sub_map);
1519: else
1520: vm_object_reference(new_entry->object.vm_object);
1521: }
1522:
1523: /*
1524: * vm_map_clip_end: [ internal use only ]
1525: *
1526: * Asserts that the given entry ends at or before
1527: * the specified address; if necessary,
1528: * it splits the entry into two.
1529: */
1530: #define vm_map_clip_end(map, entry, endaddr) \
1531: MACRO_BEGIN \
1532: vm_map_t VMCE_map; \
1533: vm_map_entry_t VMCE_entry; \
1534: vm_offset_t VMCE_endaddr; \
1535: VMCE_map = (map); \
1536: VMCE_entry = (entry); \
1537: VMCE_endaddr = (endaddr); \
1538: if (VMCE_endaddr < VMCE_entry->vme_end) \
1539: _vm_map_clip_end(&VMCE_map->hdr,VMCE_entry,VMCE_endaddr); \
1540: UPDATE_FIRST_FREE(VMCE_map, VMCE_map->first_free); \
1541: MACRO_END
1542:
1543: #define vm_map_copy_clip_end(copy, entry, endaddr) \
1544: MACRO_BEGIN \
1545: if ((endaddr) < (entry)->vme_end) \
1546: _vm_map_clip_end(&(copy)->cpy_hdr,(entry),(endaddr)); \
1547: MACRO_END
1548:
1549: /*
1550: * This routine is called only when it is known that
1551: * the entry must be split.
1552: */
1553: void
1554: _vm_map_clip_end(
1555: register struct vm_map_header *map_header,
1556: register vm_map_entry_t entry,
1557: register vm_offset_t end)
1558: {
1559: register vm_map_entry_t new_entry;
1560:
1561: /*
1562: * Create a new entry and insert it
1563: * AFTER the specified entry
1564: */
1565:
1566: new_entry = _vm_map_entry_create(map_header);
1567: vm_map_entry_copy_full(new_entry, entry);
1568:
1569: new_entry->vme_start = entry->vme_end = end;
1570: new_entry->offset += (end - entry->vme_start);
1571:
1572: _vm_map_entry_link(map_header, entry, new_entry);
1573:
1574: if (entry->is_sub_map)
1575: vm_map_reference(new_entry->object.sub_map);
1576: else
1577: vm_object_reference(new_entry->object.vm_object);
1578: }
1579:
1580:
1581: /*
1582: * VM_MAP_RANGE_CHECK: [ internal use only ]
1583: *
1584: * Asserts that the starting and ending region
1585: * addresses fall within the valid range of the map.
1586: */
1587: #define VM_MAP_RANGE_CHECK(map, start, end) \
1588: { \
1589: if (start < vm_map_min(map)) \
1590: start = vm_map_min(map); \
1591: if (end > vm_map_max(map)) \
1592: end = vm_map_max(map); \
1593: if (start > end) \
1594: start = end; \
1595: }
1596:
1597: /*
1598: * vm_map_range_check: [ internal use only ]
1599: *
1600: * Check that the region defined by the specified start and
1601: * end addresses are wholly contained within a single map
1602: * entry or set of adjacent map entries of the spacified map,
1603: * i.e. the specified region contains no unmapped space.
1604: * If any or all of the region is unmapped, FALSE is returned.
1605: * Otherwise, TRUE is returned and if the output argument 'entry'
1606: * is not NULL it points to the map entry containing the start
1607: * of the region.
1608: *
1609: * The map is locked for reading on entry and is left locked.
1610: */
1611: boolean_t
1612: vm_map_range_check(
1613: register vm_map_t map,
1614: register vm_offset_t start,
1615: register vm_offset_t end,
1616: vm_map_entry_t *entry)
1617: {
1618: vm_map_entry_t cur;
1619: register vm_offset_t prev;
1620:
1621: /*
1622: * Basic sanity checks first
1623: */
1624: if (start < vm_map_min(map) || end > vm_map_max(map) || start > end)
1625: return (FALSE);
1626:
1627: /*
1628: * Check first if the region starts within a valid
1629: * mapping for the map.
1630: */
1631: if (!vm_map_lookup_entry(map, start, &cur))
1632: return (FALSE);
1633:
1634: /*
1635: * Optimize for the case that the region is contained
1636: * in a single map entry.
1637: */
1638: if (entry != (vm_map_entry_t *) NULL)
1639: *entry = cur;
1640: if (end <= cur->vme_end)
1641: return (TRUE);
1642:
1643: /*
1644: * If the region is not wholly contained within a
1645: * single entry, walk the entries looking for holes.
1646: */
1647: prev = cur->vme_end;
1648: cur = cur->vme_next;
1649: while ((cur != vm_map_to_entry(map)) && (prev == cur->vme_start)) {
1650: if (end <= cur->vme_end)
1651: return (TRUE);
1652: prev = cur->vme_end;
1653: cur = cur->vme_next;
1654: }
1655: return (FALSE);
1656: }
1657:
1658: /*
1659: * vm_map_submap: [ kernel use only ]
1660: *
1661: * Mark the given range as handled by a subordinate map.
1662: *
1663: * This range must have been created with vm_map_find using
1664: * the vm_submap_object, and no other operations may have been
1665: * performed on this range prior to calling vm_map_submap.
1666: *
1667: * Only a limited number of operations can be performed
1668: * within this rage after calling vm_map_submap:
1669: * vm_fault
1670: * [Don't try vm_map_copyin!]
1671: *
1672: * To remove a submapping, one must first remove the
1673: * range from the superior map, and then destroy the
1674: * submap (if desired). [Better yet, don't try it.]
1675: */
1676: kern_return_t
1677: vm_map_submap(
1678: register vm_map_t map,
1679: register vm_offset_t start,
1680: register vm_offset_t end,
1681: vm_map_t submap,
1682: vm_offset_t offset)
1683: {
1684: vm_map_entry_t entry;
1685: register kern_return_t result = KERN_INVALID_ARGUMENT;
1686: register vm_object_t object;
1687:
1688: vm_map_lock(map);
1689:
1690: VM_MAP_RANGE_CHECK(map, start, end);
1691:
1692: if (vm_map_lookup_entry(map, start, &entry)) {
1693: vm_map_clip_start(map, entry, start);
1694: }
1695: else
1696: entry = entry->vme_next;
1697:
1698: vm_map_clip_end(map, entry, end);
1699:
1700: if ((entry->vme_start == start) && (entry->vme_end == end) &&
1701: (!entry->is_sub_map) &&
1702: ((object = entry->object.vm_object) == vm_submap_object) &&
1703: (object->resident_page_count == 0) &&
1704: (object->copy == VM_OBJECT_NULL) &&
1705: (object->shadow == VM_OBJECT_NULL) &&
1706: (!object->pager_created)) {
1707: entry->offset = offset;
1708: entry->object.vm_object = VM_OBJECT_NULL;
1709: vm_object_deallocate(object);
1710: entry->is_sub_map = TRUE;
1711: vm_map_reference(entry->object.sub_map = submap);
1712: result = KERN_SUCCESS;
1713: }
1714: vm_map_unlock(map);
1715:
1716: return(result);
1717: }
1718:
1719: /*
1720: * vm_map_protect:
1721: *
1722: * Sets the protection of the specified address
1723: * region in the target map. If "set_max" is
1724: * specified, the maximum protection is to be set;
1725: * otherwise, only the current protection is affected.
1726: */
1727: kern_return_t
1728: vm_map_protect(
1729: register vm_map_t map,
1730: register vm_offset_t start,
1731: register vm_offset_t end,
1732: register vm_prot_t new_prot,
1733: register boolean_t set_max)
1734: {
1735: register vm_map_entry_t current;
1736: register vm_offset_t prev;
1737: vm_map_entry_t entry;
1738: vm_prot_t new_max;
1739: boolean_t clip;
1740:
1741: XPR(XPR_VM_MAP,
1742: "vm_map_protect, 0x%X start 0x%X end 0x%X, new 0x%X %d",
1743: (integer_t)map, start, end, new_prot, set_max);
1744:
1745: vm_map_lock(map);
1746:
1747: /*
1748: * Lookup the entry. If it doesn't start in a valid
1749: * entry, return an error. Remember if we need to
1750: * clip the entry. We don't do it here because we don't
1751: * want to make any changes until we've scanned the
1752: * entire range below for address and protection
1753: * violations.
1754: */
1755: if (!(clip = vm_map_lookup_entry(map, start, &entry))) {
1756: vm_map_unlock(map);
1757: return(KERN_INVALID_ADDRESS);
1758: }
1759:
1760: /*
1761: * Make a first pass to check for protection and address
1762: * violations.
1763: */
1764:
1765: current = entry;
1766: prev = current->vme_start;
1767: while ((current != vm_map_to_entry(map)) &&
1768: (current->vme_start < end)) {
1769:
1770: /*
1771: * If there is a hole, return an error.
1772: */
1773: if (current->vme_start != prev) {
1774: vm_map_unlock(map);
1775: return(KERN_INVALID_ADDRESS);
1776: }
1777:
1778: new_max = current->max_protection;
1779: if(new_prot & VM_PROT_COPY) {
1780: new_max |= VM_PROT_WRITE;
1781: }
1782: if ((new_prot & new_max) != new_prot) {
1783: vm_map_unlock(map);
1784: return(KERN_PROTECTION_FAILURE);
1785: }
1786:
1787: prev = current->vme_end;
1788: current = current->vme_next;
1789: }
1790: if (end > prev) {
1791: vm_map_unlock(map);
1792: return(KERN_INVALID_ADDRESS);
1793: }
1794:
1795: /*
1796: * Go back and fix up protections.
1797: * Clip to start here if the range starts within
1798: * the entry.
1799: */
1800:
1801: current = entry;
1802: if (clip) {
1803: vm_map_clip_start(map, entry, start);
1804: }
1805: while ((current != vm_map_to_entry(map)) &&
1806: (current->vme_start < end)) {
1807:
1808: vm_prot_t old_prot;
1809:
1810: vm_map_clip_end(map, current, end);
1811:
1812: old_prot = current->protection;
1813:
1814: if(new_prot & VM_PROT_COPY) {
1815: /* caller is asking specifically to copy the */
1816: /* mapped data, this implies that max protection */
1817: /* will include write. Caller must be prepared */
1818: /* for loss of shared memory communication in the */
1819: /* target area after taking this step */
1820: current->needs_copy = TRUE;
1821: current->max_protection |= VM_PROT_WRITE;
1822: }
1823:
1824: if (set_max)
1825: current->protection =
1826: (current->max_protection = new_prot) &
1827: old_prot;
1828: else
1829: current->protection = new_prot;
1830:
1831: /*
1832: * Update physical map if necessary.
1833: * If the request is to turn off write protection,
1834: * we won't do it for real (in pmap). This is because
1835: * it would cause copy-on-write to fail. We've already
1836: * set, the new protection in the map, so if a
1837: * write-protect fault occurred, it will be fixed up
1838: * properly, COW or not.
1839: */
1840:
1841: if ((current->protection != old_prot) && !(current->protection & VM_PROT_WRITE)) {
1842: pmap_protect(map->pmap, current->vme_start,
1843: current->vme_end,
1844: current->protection);
1845: }
1846: current = current->vme_next;
1847: }
1848:
1849: vm_map_unlock(map);
1850: return(KERN_SUCCESS);
1851: }
1852:
1853:
1854: /*
1855: * vm_map_inherit:
1856: *
1857: * Sets the inheritance of the specified address
1858: * range in the target map. Inheritance
1859: * affects how the map will be shared with
1860: * child maps at the time of vm_map_fork.
1861: */
1862: kern_return_t
1863: vm_map_inherit(
1864: register vm_map_t map,
1865: register vm_offset_t start,
1866: register vm_offset_t end,
1867: register vm_inherit_t new_inheritance)
1868: {
1869: register vm_map_entry_t entry;
1870: vm_map_entry_t temp_entry;
1871:
1872: vm_map_lock(map);
1873:
1874: VM_MAP_RANGE_CHECK(map, start, end);
1875:
1876: if (vm_map_lookup_entry(map, start, &temp_entry)) {
1877: entry = temp_entry;
1878: vm_map_clip_start(map, entry, start);
1879: }
1880: else {
1881: temp_entry = temp_entry->vme_next;
1882: entry = temp_entry;
1883: }
1884:
1885: /* first check entire range for submaps which can't support the */
1886: /* given inheritance. */
1887: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
1888: if(entry->is_sub_map) {
1889: if(new_inheritance == VM_INHERIT_COPY)
1890: return(KERN_INVALID_ARGUMENT);
1891: }
1892:
1893: entry = entry->vme_next;
1894: }
1895:
1896: entry = temp_entry;
1897:
1898: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
1899: vm_map_clip_end(map, entry, end);
1900:
1901: entry->inheritance = new_inheritance;
1902:
1903: entry = entry->vme_next;
1904: }
1905:
1906: vm_map_unlock(map);
1907: return(KERN_SUCCESS);
1908: }
1909:
1910: /*
1911: * vm_map_wire:
1912: *
1913: * Sets the pageability of the specified address range in the
1914: * target map as wired. Regions specified as not pageable require
1915: * locked-down physical memory and physical page maps. The
1916: * access_type variable indicates types of accesses that must not
1917: * generate page faults. This is checked against protection of
1918: * memory being locked-down.
1919: *
1920: * The map must not be locked, but a reference must remain to the
1921: * map throughout the call.
1922: */
1923: kern_return_t
1924: vm_map_wire(
1925: register vm_map_t map,
1926: register vm_offset_t start,
1927: register vm_offset_t end,
1928: register vm_prot_t access_type,
1929: boolean_t user_wire)
1930: {
1931: register vm_map_entry_t entry;
1932: struct vm_map_entry *first_entry, tmp_entry;
1933: register vm_offset_t s,e;
1934: kern_return_t rc;
1935: boolean_t need_wakeup;
1936: unsigned int last_timestamp;
1937: vm_size_t size;
1938:
1939: vm_map_lock(map);
1940: last_timestamp = map->timestamp;
1941:
1942: VM_MAP_RANGE_CHECK(map, start, end);
1943: assert(page_aligned(start));
1944: assert(page_aligned(end));
1945:
1946: if (vm_map_lookup_entry(map, start, &first_entry)) {
1947: entry = first_entry;
1948: /* vm_map_clip_start will be done later. */
1949: } else {
1950: /* Start address is not in map */
1951: vm_map_unlock(map);
1952: return(KERN_INVALID_ADDRESS);
1953: }
1954:
1955: s=start;
1956: need_wakeup = FALSE;
1957: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
1958: if(entry->is_sub_map) {
1959: vm_offset_t sub_start;
1960: vm_offset_t sub_end;
1961: vm_offset_t local_end;
1962:
1963: if(entry->vme_start < start)
1964: sub_start = start;
1965: else
1966: sub_start = entry->vme_start;
1967: sub_start -= entry->vme_start;
1968: sub_start += entry->offset;
1969:
1970: if(entry->vme_end < end)
1971: sub_end = entry->vme_end;
1972: else
1973: sub_end = end;
1974: sub_end -= entry->vme_start;
1975: sub_end += entry->offset;
1976: local_end = entry->vme_end;
1977: vm_map_unlock(map);
1978: if (vm_map_wire(entry->object.sub_map,
1979: sub_start, sub_end,
1980: access_type, user_wire)
1981: != KERN_SUCCESS) {
1982: vm_map_unwire(map, start, s, user_wire);
1983: return(KERN_FAILURE);
1984: }
1985: vm_map_lock(map);
1986: if (last_timestamp+1 != map->timestamp) {
1987: /*
1988: * Find the entry again. It could have been clipped
1989: * after we unlocked the map.
1990: */
1991: if (!vm_map_lookup_entry(map, local_end,
1992: &first_entry))
1993: panic("vm_map_wire: re-lookup failed");
1994:
1995: entry = first_entry;
1996: } else
1997: entry = entry->vme_next;
1998:
1999: last_timestamp = map->timestamp;
2000: continue;
2001: }
2002:
2003: /*
2004: * If another thread is wiring/unwiring this entry then
2005: * block after informing other thread to wake us up.
2006: */
2007: if (entry->in_transition) {
2008: /*
2009: * We have not clipped the entry. Make sure that
2010: * the start address is in range so that the lookup
2011: * below will succeed.
2012: */
2013: s = entry->vme_start < start? start: entry->vme_start;
2014:
2015: entry->needs_wakeup = TRUE;
2016:
2017: /*
2018: * wake up anybody waiting on entries that we have
2019: * already wired.
2020: */
2021: if (need_wakeup) {
2022: vm_map_entry_wakeup(map);
2023: need_wakeup = FALSE;
2024: }
2025: /*
2026: * User wiring is interruptible
2027: */
2028: vm_map_entry_wait(map,
2029: (user_wire) ? THREAD_ABORTSAFE :
2030: THREAD_UNINT);
2031: if (user_wire && current_thread()->wait_result ==
2032: THREAD_INTERRUPTED) {
2033: /*
2034: * undo the wirings we have done so far
2035: * We do not clear the needs_wakeup flag,
2036: * because we cannot tell if we were the
2037: * only one waiting.
2038: */
2039: vm_map_unwire(map, start, s, user_wire);
2040: return(KERN_FAILURE);
2041: }
2042:
2043: vm_map_lock(map);
2044: /*
2045: * Cannot avoid a lookup here. reset timestamp.
2046: */
2047: last_timestamp = map->timestamp;
2048:
2049: /*
2050: * The entry could have been clipped, look it up again.
2051: * Worse that can happen is, it may not exist anymore.
2052: */
2053: if (!vm_map_lookup_entry(map, s, &first_entry)) {
2054: if (!user_wire)
2055: panic("vm_map_wire: re-lookup failed");
2056:
2057: /*
2058: * User: undo everything upto the previous
2059: * entry. let vm_map_unwire worry about
2060: * checking the validity of the range.
2061: */
2062: vm_map_unlock(map);
2063: vm_map_unwire(map, start, s, user_wire);
2064: return(KERN_FAILURE);
2065: }
2066: entry = first_entry;
2067: continue;
2068: }
2069:
2070: /*
2071: * If this entry is already wired then increment
2072: * the appropriate wire reference count.
2073: */
2074: if (entry->wired_count) {
2075: /* sanity check: wired_count is a short */
2076: if (entry->wired_count >= MAX_WIRE_COUNT)
2077: panic("vm_map_wire: too many wirings");
2078:
2079: if (user_wire &&
2080: entry->user_wired_count >= MAX_WIRE_COUNT) {
2081: vm_map_unlock(map);
2082: vm_map_unwire(map, start,
2083: entry->vme_start, user_wire);
2084: return(KERN_FAILURE);
2085: }
2086: /*
2087: * entry is already wired down, get our reference
2088: * after clipping to our range.
2089: */
2090: vm_map_clip_start(map, entry, start);
2091: vm_map_clip_end(map, entry, end);
2092: if (!user_wire || (entry->user_wired_count++ == 0))
2093: entry->wired_count++;
2094:
2095: entry = entry->vme_next;
2096: continue;
2097: }
2098:
2099: /*
2100: * Unwired entry
2101: */
2102:
2103:
2104: /*
2105: * Perform actions of vm_map_lookup that need the write
2106: * lock on the map: create a shadow object for a
2107: * copy-on-write region, or an object for a zero-fill
2108: * region.
2109: */
2110: size = entry->vme_end - entry->vme_start;
2111: /*
2112: * If wiring a copy-on-write page, we need to copy it now
2113: * even if we're only (currently) requesting read access.
2114: * This is aggressive, but once it's wired we can't move it.
2115: */
2116: if (entry->needs_copy) {
2117: vm_object_shadow(&entry->object.vm_object,
2118: &entry->offset, size);
2119: entry->needs_copy = FALSE;
2120: } else if (entry->object.vm_object == VM_OBJECT_NULL) {
2121: entry->object.vm_object = vm_object_allocate(size);
2122: entry->offset = (vm_offset_t)0;
2123: }
2124:
2125: vm_map_clip_start(map, entry, start);
2126: vm_map_clip_end(map, entry, end);
2127:
2128: s = entry->vme_start;
2129: e = entry->vme_end;
2130:
2131: /*
2132: * Check for holes and protection mismatch.
2133: * Holes: Next entry should be contiguous unless this
2134: * is the end of the region.
2135: * Protection: Access requested must be allowed, unless
2136: * wiring is by protection class
2137: */
2138: if ((((entry->vme_end < end) &&
2139: ((entry->vme_next == vm_map_to_entry(map)) ||
2140: (entry->vme_next->vme_start > entry->vme_end))) ||
2141: ((entry->protection & access_type) != access_type))) {
2142: /*
2143: * Found a hole or protection problem.
2144: * Unwire the region we wired so far.
2145: */
2146: if (start != entry->vme_start) {
2147: vm_map_unlock(map);
2148: vm_map_unwire(map, start, s, user_wire);
2149: } else {
2150: vm_map_unlock(map);
2151: }
2152: return((entry->protection&access_type) != access_type?
2153: KERN_PROTECTION_FAILURE: KERN_INVALID_ADDRESS);
2154: }
2155:
2156: assert(entry->wired_count == 0 && entry->user_wired_count == 0);
2157:
2158: if (user_wire)
2159: entry->user_wired_count++;
2160: entry->wired_count++;
2161:
2162: entry->in_transition = TRUE;
2163:
2164: /*
2165: * This entry might get split once we unlock the map.
2166: * In vm_fault_wire(), we need the current range as
2167: * defined by this entry. In order for this to work
2168: * along with a simultaneous clip operation, we make a
2169: * temporary copy of this entry and use that for the
2170: * wiring. Note that the underlying objects do not
2171: * change during a clip.
2172: */
2173: tmp_entry = *entry;
2174:
2175: /*
2176: * The in_transition state guarentees that the entry
2177: * (or entries for this range, if split occured) will be
2178: * there when the map lock is acquired for the second time.
2179: */
2180: vm_map_unlock(map);
2181: rc = vm_fault_wire(map, &tmp_entry);
2182: vm_map_lock(map);
2183:
2184: if (last_timestamp+1 != map->timestamp) {
2185: /*
2186: * Find the entry again. It could have been clipped
2187: * after we unlocked the map.
2188: */
2189: if (!vm_map_lookup_entry(map, tmp_entry.vme_start,
2190: &first_entry))
2191: panic("vm_map_wire: re-lookup failed");
2192:
2193: entry = first_entry;
2194: }
2195:
2196: last_timestamp = map->timestamp;
2197:
2198: while ((entry != vm_map_to_entry(map)) &&
2199: (entry->vme_start < tmp_entry.vme_end)) {
2200: assert(entry->in_transition);
2201: entry->in_transition = FALSE;
2202: if (entry->needs_wakeup) {
2203: entry->needs_wakeup = FALSE;
2204: need_wakeup = TRUE;
2205: }
2206: if (rc != KERN_SUCCESS) { /* from vm_*_wire */
2207: if (user_wire)
2208: entry->user_wired_count--;
2209: entry->wired_count--;
2210: }
2211: entry = entry->vme_next;
2212: }
2213:
2214: if (rc != KERN_SUCCESS) { /* from vm_*_wire */
2215: vm_map_unlock(map);
2216: if (need_wakeup)
2217: vm_map_entry_wakeup(map);
2218: /*
2219: * undo everything upto the previous entry.
2220: */
2221: (void)vm_map_unwire(map, start, s, user_wire);
2222: return rc;
2223: }
2224: } /* end while loop through map entries */
2225: vm_map_unlock(map);
2226:
2227: /*
2228: * wake up anybody waiting on entries we wired.
2229: */
2230: if (need_wakeup)
2231: vm_map_entry_wakeup(map);
2232:
2233: return(KERN_SUCCESS);
2234:
2235: }
2236:
2237:
2238: /*
2239: * vm_map_unwire:
2240: *
2241: * Sets the pageability of the specified address range in the target
2242: * as pageable. Regions specified must have been wired previously.
2243: *
2244: * The map must not be locked, but a reference must remain to the map
2245: * throughout the call.
2246: *
2247: * Kernel will panic on failures. User unwire ignores holes and
2248: * unwired and intransition entries to avoid losing memory by leaving
2249: * it unwired.
2250: */
2251: kern_return_t
2252: vm_map_unwire(
2253: register vm_map_t map,
2254: register vm_offset_t start,
2255: register vm_offset_t end,
2256: boolean_t user_wire)
2257: {
2258: register vm_map_entry_t entry;
2259: struct vm_map_entry *first_entry, tmp_entry;
2260: boolean_t need_wakeup;
2261: unsigned int last_timestamp;
2262:
2263: vm_map_lock(map);
2264: last_timestamp = map->timestamp;
2265:
2266: VM_MAP_RANGE_CHECK(map, start, end);
2267: assert(page_aligned(start));
2268: assert(page_aligned(end));
2269:
2270: if (vm_map_lookup_entry(map, start, &first_entry)) {
2271: entry = first_entry;
2272: /* vm_map_clip_start will be done later. */
2273: }
2274: else {
2275: /* Start address is not in map. */
2276: vm_map_unlock(map);
2277: return(KERN_INVALID_ADDRESS);
2278: }
2279:
2280: need_wakeup = FALSE;
2281: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
2282: if(entry->is_sub_map) {
2283: vm_offset_t sub_start;
2284: vm_offset_t sub_end;
2285: vm_offset_t local_end;
2286:
2287: if(entry->vme_start < start)
2288: sub_start = start;
2289: else
2290: sub_start = entry->vme_start;
2291: sub_start -= entry->vme_start;
2292: sub_start += entry->offset;
2293:
2294: if(entry->vme_end < end)
2295: sub_end = entry->vme_end;
2296: else
2297: sub_end = end;
2298: sub_end -= entry->vme_start;
2299: sub_end += entry->offset;
2300: local_end = entry->vme_end;
2301: vm_map_unlock(map);
2302: vm_map_unwire(entry->object.sub_map,
2303: sub_start, sub_end,
2304: user_wire);
2305:
2306: vm_map_lock(map);
2307: if (last_timestamp+1 != map->timestamp) {
2308: /*
2309: * Find the entry again. It could have been clipped
2310: * after we unlocked the map.
2311: */
2312: if (!vm_map_lookup_entry(map, local_end,
2313: &first_entry))
2314: panic("vm_map_unwire: re-lookup failed");
2315:
2316: entry = first_entry;
2317: } else
2318: entry = entry->vme_next;
2319:
2320: last_timestamp = map->timestamp;
2321: continue;
2322: }
2323:
2324:
2325: if (entry->in_transition) {
2326: /*
2327: * 1)
2328: * Another thread is wiring down this entry. Note
2329: * that if it is not for the other thread we would
2330: * be unwiring an unwired entry. This is not
2331: * permitted. If we wait, we will be unwiring memory
2332: * we did not wire.
2333: *
2334: * 2)
2335: * Another thread is unwiring this entry. We did not
2336: * have a reference to it, because if we did, this
2337: * entry will not be getting unwired now.
2338: */
2339: if (!user_wire)
2340: panic("vm_map_unwire: in_transition entry");
2341:
2342: entry = entry->vme_next;
2343: continue;
2344: }
2345:
2346: if (entry->wired_count == 0 ||
2347: (user_wire && entry->user_wired_count == 0)) {
2348: if (!user_wire)
2349: panic("vm_map_unwire: entry is unwired");
2350:
2351: entry = entry->vme_next;
2352: continue;
2353: }
2354:
2355: assert(entry->wired_count > 0 &&
2356: (!user_wire || entry->user_wired_count > 0));
2357:
2358: vm_map_clip_start(map, entry, start);
2359: vm_map_clip_end(map, entry, end);
2360:
2361: /*
2362: * Check for holes
2363: * Holes: Next entry should be contiguous unless
2364: * this is the end of the region.
2365: */
2366: if (((entry->vme_end < end) &&
2367: ((entry->vme_next == vm_map_to_entry(map)) ||
2368: (entry->vme_next->vme_start > entry->vme_end)))) {
2369:
2370: if (!user_wire)
2371: panic("vm_map_unwire: non-contiguous region");
2372: entry = entry->vme_next;
2373: continue;
2374: }
2375:
2376: if (!user_wire || (--entry->user_wired_count == 0))
2377: entry->wired_count--;
2378:
2379: if (entry->wired_count != 0) {
2380: entry = entry->vme_next;
2381: continue;
2382: }
2383:
2384: entry->in_transition = TRUE;
2385: tmp_entry = *entry; /* see comment in vm_map_wire() */
2386:
2387: /*
2388: * We can unlock the map now. The in_transition state
2389: * guarantees existance of the entry.
2390: */
2391: vm_map_unlock(map);
2392: vm_fault_unwire(map, &tmp_entry, FALSE);
2393: vm_map_lock(map);
2394:
2395: if (last_timestamp+1 != map->timestamp) {
2396: /*
2397: * Find the entry again. It could have been clipped
2398: * or deleted after we unlocked the map.
2399: */
2400: if (!vm_map_lookup_entry(map, tmp_entry.vme_start,
2401: &first_entry)) {
2402: if (!user_wire)
2403: panic("vm_map_unwire: re-lookup failed");
2404: entry = first_entry->vme_next;
2405: } else
2406: entry = first_entry;
2407: }
2408: last_timestamp = map->timestamp;
2409:
2410: /*
2411: * clear transition bit for all constituent entries that
2412: * were in the original entry (saved in tmp_entry). Also
2413: * check for waiters.
2414: */
2415: while ((entry != vm_map_to_entry(map)) &&
2416: (entry->vme_start < tmp_entry.vme_end)) {
2417: assert(entry->in_transition);
2418: entry->in_transition = FALSE;
2419: if (entry->needs_wakeup) {
2420: entry->needs_wakeup = FALSE;
2421: need_wakeup = TRUE;
2422: }
2423: entry = entry->vme_next;
2424: }
2425: }
2426: vm_map_unlock(map);
2427: /*
2428: * wake up anybody waiting on entries that we have unwired.
2429: */
2430: if (need_wakeup)
2431: vm_map_entry_wakeup(map);
2432: return(KERN_SUCCESS);
2433:
2434: }
2435:
2436: /*
2437: * vm_map_entry_delete: [ internal use only ]
2438: *
2439: * Deallocate the given entry from the target map.
2440: */
2441: void
2442: vm_map_entry_delete(
2443: register vm_map_t map,
2444: register vm_map_entry_t entry)
2445: {
2446: register vm_offset_t s, e;
2447: register vm_object_t object;
2448: extern vm_object_t kernel_object;
2449:
2450: s = entry->vme_start;
2451: e = entry->vme_end;
2452: assert(page_aligned(s));
2453: assert(page_aligned(e));
2454: assert(entry->wired_count == 0);
2455: assert(entry->user_wired_count == 0);
2456:
2457:
2458: /*
2459: * Deallocate the object only after removing all
2460: * pmap entries pointing to its pages.
2461: */
2462: if (entry->is_sub_map)
2463: vm_map_deallocate(entry->object.sub_map);
2464: else
2465: vm_object_deallocate(entry->object.vm_object);
2466:
2467: vm_map_entry_unlink(map, entry);
2468: map->size -= e - s;
2469:
2470: vm_map_entry_dispose(map, entry);
2471: }
2472:
2473:
2474: /*
2475: * vm_map_delete: [ internal use only ]
2476: *
2477: * Deallocates the given address range from the target map.
2478: * Removes all user wirings. Unwires one kernel wiring if
2479: * VM_MAP_REMOVE_KUNWIRE is set. Waits for kernel wirings to go
2480: * away if VM_MAP_REMOVE_WAIT_FOR_KWIRE is set. Sleeps
2481: * interruptibly if VM_MAP_REMOVE_INTERRUPTIBLE is set.
2482: *
2483: * This routine is called with map locked and leaves map locked.
2484: */
2485: kern_return_t
2486: vm_map_delete(
2487: register vm_map_t map,
2488: vm_offset_t start,
2489: register vm_offset_t end,
2490: int flags)
2491: {
2492: register vm_map_entry_t entry, next;
2493: struct vm_map_entry *first_entry, tmp_entry;
2494: register vm_offset_t s, e;
2495: register vm_object_t object;
2496: boolean_t need_wakeup;
2497: unsigned int last_timestamp = ~0; /* unlikely value */
2498: int interruptible;
2499: extern vm_map_t kernel_map;
2500:
2501: interruptible = (flags & VM_MAP_REMOVE_INTERRUPTIBLE) ?
2502: THREAD_ABORTSAFE : THREAD_UNINT;
2503:
2504: /*
2505: * Find the start of the region, and clip it
2506: */
2507: if (vm_map_lookup_entry(map, start, &first_entry)) {
2508: entry = first_entry;
2509: vm_map_clip_start(map, entry, start);
2510:
2511: /*
2512: * Fix the lookup hint now, rather than each
2513: * time through the loop.
2514: */
2515: SAVE_HINT(map, entry->vme_prev);
2516: } else {
2517: entry = first_entry->vme_next;
2518: }
2519:
2520: need_wakeup = FALSE;
2521: /*
2522: * Step through all entries in this region
2523: */
2524: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
2525:
2526: vm_map_clip_end(map, entry, end);
2527: retry_entry:
2528: if (entry->in_transition) {
2529: /*
2530: * Another thread is wiring/unwiring this entry.
2531: * Let the other thread know we are waiting.
2532: */
2533: s = entry->vme_start;
2534: entry->needs_wakeup = TRUE;
2535:
2536: /*
2537: * wake up anybody waiting on entries that we have
2538: * already unwired/deleted.
2539: */
2540: if (need_wakeup) {
2541: vm_map_entry_wakeup(map);
2542: need_wakeup = FALSE;
2543: }
2544:
2545: vm_map_entry_wait(map, interruptible);
2546:
2547: if (interruptible &&
2548: current_thread()->wait_result == THREAD_INTERRUPTED)
2549: /*
2550: * We do not clear the needs_wakeup flag,
2551: * since we cannot tell if we were the only one.
2552: */
2553: return KERN_ABORTED;
2554:
2555: vm_map_lock(map);
2556: /*
2557: * Cannot avoid a lookup here. reset timestamp.
2558: */
2559: last_timestamp = map->timestamp;
2560:
2561: /*
2562: * The entry could have been clipped or it
2563: * may not exist anymore. Look it up again.
2564: */
2565: if (!vm_map_lookup_entry(map, s, &first_entry)) {
2566: assert((map != kernel_map) &&
2567: (!entry->is_sub_map));
2568: /*
2569: * User: use the next entry
2570: */
2571: entry = first_entry->vme_next;
2572: } else {
2573: entry = first_entry;
2574: SAVE_HINT(map, entry->vme_prev);
2575: }
2576: goto retry_entry;
2577: } /* end in_transition */
2578:
2579: if (entry->wired_count) {
2580: /*
2581: * Remove a kernel wiring if requested or if
2582: * there are user wirings.
2583: */
2584: if ((flags & VM_MAP_REMOVE_KUNWIRE) ||
2585: (entry->user_wired_count > 0))
2586: entry->wired_count--;
2587:
2588: /* remove all user wire references */
2589: entry->user_wired_count = 0;
2590:
2591: if (entry->wired_count != 0) {
2592: assert((map != kernel_map) &&
2593: (!entry->is_sub_map));
2594: /*
2595: * Cannot continue. Typical case is when
2596: * a user thread has physical io pending on
2597: * on this page. Either wait for the
2598: * kernel wiring to go away or return an
2599: * error.
2600: */
2601: if (flags & VM_MAP_REMOVE_WAIT_FOR_KWIRE) {
2602:
2603: s = entry->vme_start;
2604: entry->needs_wakeup = TRUE;
2605: vm_map_entry_wait(map, interruptible);
2606:
2607: if (interruptible &&
2608: current_thread()->wait_result ==
2609: THREAD_INTERRUPTED)
2610: /*
2611: * We do not clear the
2612: * needs_wakeup flag, since we
2613: * cannot tell if we were the
2614: * only one.
2615: */
2616: return KERN_ABORTED;
2617:
2618: vm_map_lock(map);
2619: /*
2620: * Cannot avoid a lookup here. reset
2621: * timestamp.
2622: */
2623: last_timestamp = map->timestamp;
2624:
2625: /*
2626: * The entry could have been clipped or
2627: * it may not exist anymore. Look it
2628: * up again.
2629: */
2630: if (!vm_map_lookup_entry(map, s,
2631: &first_entry)) {
2632: assert((map != kernel_map) &&
2633: (!entry->is_sub_map));
2634: /*
2635: * User: use the next entry
2636: */
2637: entry = first_entry->vme_next;
2638: } else {
2639: entry = first_entry;
2640: SAVE_HINT(map, entry->vme_prev);
2641: }
2642: goto retry_entry;
2643: }
2644: else {
2645: return KERN_FAILURE;
2646: }
2647: }
2648:
2649: entry->in_transition = TRUE;
2650: /*
2651: * copy current entry. see comment in vm_map_wire()
2652: */
2653: tmp_entry = *entry;
2654: s = entry->vme_start;
2655: e = entry->vme_end;
2656:
2657: /*
2658: * We can unlock the map now. The in_transition
2659: * state guarentees existance of the entry.
2660: */
2661: vm_map_unlock(map);
2662: vm_fault_unwire(map, &tmp_entry,
2663: tmp_entry.object.vm_object == kernel_object);
2664: vm_map_lock(map);
2665:
2666: if (last_timestamp+1 != map->timestamp) {
2667: /*
2668: * Find the entry again. It could have
2669: * been clipped after we unlocked the map.
2670: */
2671: if (!vm_map_lookup_entry(map, s, &first_entry)){
2672: assert((map != kernel_map) &&
2673: (!entry->is_sub_map));
2674: first_entry = first_entry->vme_next;
2675: } else {
2676: SAVE_HINT(map, entry->vme_prev);
2677: }
2678: } else {
2679: SAVE_HINT(map, entry->vme_prev);
2680: first_entry = entry;
2681: }
2682:
2683: last_timestamp = map->timestamp;
2684:
2685: entry = first_entry;
2686: while ((entry != vm_map_to_entry(map)) &&
2687: (entry->vme_start < tmp_entry.vme_end)) {
2688: assert(entry->in_transition);
2689: entry->in_transition = FALSE;
2690: if (entry->needs_wakeup) {
2691: entry->needs_wakeup = FALSE;
2692: need_wakeup = TRUE;
2693: }
2694: entry = entry->vme_next;
2695: }
2696: /*
2697: * We have unwired the entry(s). Go back and
2698: * delete them.
2699: */
2700: entry = first_entry;
2701: goto retry_entry;
2702: }
2703:
2704: /* entry is unwired */
2705: assert(entry->wired_count == 0);
2706: assert(entry->user_wired_count == 0);
2707:
2708: if ((!entry->is_sub_map &&
2709: entry->object.vm_object != kernel_object) ||
2710: entry->is_sub_map) {
2711: pmap_remove(map->pmap,
2712: entry->vme_start, entry->vme_end);
2713: }
2714:
2715: next = entry->vme_next;
2716: vm_map_entry_delete(map, entry);
2717: entry = next;
2718: }
2719:
2720: if (map->wait_for_space)
2721: thread_wakeup((event_t) map);
2722: /*
2723: * wake up anybody waiting on entries that we have already deleted.
2724: */
2725: if (need_wakeup)
2726: vm_map_entry_wakeup(map);
2727:
2728: return KERN_SUCCESS;
2729: }
2730:
2731: /*
2732: * vm_map_remove:
2733: *
2734: * Remove the given address range from the target map.
2735: * This is the exported form of vm_map_delete.
2736: */
2737: kern_return_t
2738: vm_map_remove(
2739: register vm_map_t map,
2740: register vm_offset_t start,
2741: register vm_offset_t end,
2742: register boolean_t flags)
2743: {
2744: register kern_return_t result;
2745:
2746: vm_map_lock(map);
2747: VM_MAP_RANGE_CHECK(map, start, end);
2748: result = vm_map_delete(map, start, end, flags);
2749: vm_map_unlock(map);
2750:
2751: return(result);
2752: }
2753:
2754:
2755: /*
2756: * vm_map_copy_steal_pages:
2757: *
2758: * Steal all the pages from a vm_map_copy page_list by copying ones
2759: * that have not already been stolen.
2760: */
2761: void
2762: vm_map_copy_steal_pages(
2763: vm_map_copy_t copy)
2764: {
2765: register vm_page_t m, new_m;
2766: register int i;
2767: vm_object_t object;
2768:
2769: assert(copy->type == VM_MAP_COPY_PAGE_LIST);
2770: for (i = 0; i < copy->cpy_npages; i++) {
2771:
2772: /*
2773: * If the page is not tabled, then it's already stolen.
2774: */
2775: m = copy->cpy_page_list[i];
2776: if (!m->tabled)
2777: continue;
2778:
2779: /*
2780: * Page was not stolen, get a new
2781: * one and do the copy now.
2782: */
2783: while ((new_m = vm_page_grab()) == VM_PAGE_NULL) {
2784: VM_PAGE_WAIT();
2785: }
2786:
2787: vm_page_gobble(new_m); /* mark as consumed internally */
2788: vm_page_copy(m, new_m);
2789:
2790: object = m->object;
2791: vm_object_lock(object);
2792: vm_page_lock_queues();
2793: if (!m->active && !m->inactive)
2794: vm_page_activate(m);
2795: vm_page_unlock_queues();
2796: PAGE_WAKEUP_DONE(m);
2797: vm_object_paging_end(object);
2798: vm_object_unlock(object);
2799:
2800: copy->cpy_page_list[i] = new_m;
2801: }
2802: copy->cpy_page_loose = TRUE;
2803: }
2804:
2805: /*
2806: * vm_map_copy_page_discard:
2807: *
2808: * Get rid of the pages in a page_list copy. If the pages are
2809: * stolen, they are freed. If the pages are not stolen, they
2810: * are unbusied, and associated state is cleaned up.
2811: */
2812: void
2813: vm_map_copy_page_discard(
2814: vm_map_copy_t copy)
2815: {
2816: assert(copy->type == VM_MAP_COPY_PAGE_LIST);
2817: while (copy->cpy_npages > 0) {
2818: vm_page_t m;
2819:
2820: if ((m = copy->cpy_page_list[--(copy->cpy_npages)]) !=
2821: VM_PAGE_NULL) {
2822:
2823: /*
2824: * If it's not in the table, then it's
2825: * a stolen page that goes back
2826: * to the free list. Else it belongs
2827: * to some object, and we hold a
2828: * paging reference on that object.
2829: */
2830: if (!m->tabled) {
2831: VM_PAGE_FREE(m);
2832: }
2833: else {
2834: vm_object_t object;
2835:
2836: object = m->object;
2837:
2838: vm_object_lock(object);
2839: vm_page_lock_queues();
2840: if (!m->active && !m->inactive)
2841: vm_page_activate(m);
2842: vm_page_unlock_queues();
2843:
2844: if ((!m->busy)) {
2845: kern_return_t kr;
2846: kr = vm_page_unpin(m);
2847: assert(kr == KERN_SUCCESS);
2848: } else {
2849: PAGE_WAKEUP_DONE(m);
2850: }
2851: vm_object_paging_end(object);
2852: vm_object_unlock(object);
2853: }
2854: }
2855: }
2856: }
2857:
2858: /*
2859: * Routine: vm_map_copy_discard
2860: *
2861: * Description:
2862: * Dispose of a map copy object (returned by
2863: * vm_map_copyin).
2864: */
2865: void
2866: vm_map_copy_discard(
2867: vm_map_copy_t copy)
2868: {
2869: TR_DECL("vm_map_copy_discard");
2870:
2871: /* tr3("enter: copy 0x%x type %d", copy, copy->type);*/
2872: free_next_copy:
2873: if (copy == VM_MAP_COPY_NULL)
2874: return;
2875:
2876: switch (copy->type) {
2877: case VM_MAP_COPY_ENTRY_LIST:
2878: while (vm_map_copy_first_entry(copy) !=
2879: vm_map_copy_to_entry(copy)) {
2880: vm_map_entry_t entry = vm_map_copy_first_entry(copy);
2881:
2882: vm_map_copy_entry_unlink(copy, entry);
2883: vm_object_deallocate(entry->object.vm_object);
2884: vm_map_copy_entry_dispose(copy, entry);
2885: }
2886: break;
2887: case VM_MAP_COPY_OBJECT:
2888: vm_object_deallocate(copy->cpy_object);
2889: break;
2890: case VM_MAP_COPY_PAGE_LIST:
2891:
2892: /*
2893: * To clean this up, we have to unbusy all the pages
2894: * and release the paging references in their objects.
2895: */
2896: if (copy->cpy_npages > 0)
2897: vm_map_copy_page_discard(copy);
2898:
2899: /*
2900: * If there's a continuation, abort it. The
2901: * abort routine releases any storage.
2902: */
2903: if (vm_map_copy_has_cont(copy)) {
2904:
2905: assert(vm_map_copy_cont_is_valid(copy));
2906: /*
2907: * Special case: recognize
2908: * vm_map_copy_discard_cont and optimize
2909: * here to avoid tail recursion.
2910: */
2911: if (copy->cpy_cont == vm_map_copy_discard_cont) {
2912: register vm_map_copy_t new_copy;
2913:
2914: new_copy = (vm_map_copy_t) copy->cpy_cont_args;
2915: zfree(vm_map_copy_zone, (vm_offset_t) copy);
2916: copy = new_copy;
2917: goto free_next_copy;
2918: } else {
2919: vm_map_copy_abort_cont(copy);
2920: }
2921: }
2922:
2923: break;
2924:
2925: case VM_MAP_COPY_KERNEL_BUFFER:
2926:
2927: /*
2928: * The vm_map_copy_t and possibly the data buffer were
2929: * allocated by a single call to kalloc(), i.e. the
2930: * vm_map_copy_t was not allocated out of the zone.
2931: */
2932: kfree((vm_offset_t) copy, copy->cpy_kalloc_size);
2933: return;
2934: }
2935: zfree(vm_map_copy_zone, (vm_offset_t) copy);
2936: }
2937:
2938: /*
2939: * Routine: vm_map_copy_copy
2940: *
2941: * Description:
2942: * Move the information in a map copy object to
2943: * a new map copy object, leaving the old one
2944: * empty.
2945: *
2946: * This is used by kernel routines that need
2947: * to look at out-of-line data (in copyin form)
2948: * before deciding whether to return SUCCESS.
2949: * If the routine returns FAILURE, the original
2950: * copy object will be deallocated; therefore,
2951: * these routines must make a copy of the copy
2952: * object and leave the original empty so that
2953: * deallocation will not fail.
2954: */
2955: vm_map_copy_t
2956: vm_map_copy_copy(
2957: vm_map_copy_t copy)
2958: {
2959: vm_map_copy_t new_copy;
2960:
2961: if (copy == VM_MAP_COPY_NULL)
2962: return VM_MAP_COPY_NULL;
2963:
2964: /*
2965: * Allocate a new copy object, and copy the information
2966: * from the old one into it.
2967: */
2968:
2969: new_copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
2970: *new_copy = *copy;
2971:
2972: if (copy->type == VM_MAP_COPY_ENTRY_LIST) {
2973: /*
2974: * The links in the entry chain must be
2975: * changed to point to the new copy object.
2976: */
2977: vm_map_copy_first_entry(copy)->vme_prev
2978: = vm_map_copy_to_entry(new_copy);
2979: vm_map_copy_last_entry(copy)->vme_next
2980: = vm_map_copy_to_entry(new_copy);
2981: }
2982:
2983: /*
2984: * Change the old copy object into one that contains
2985: * nothing to be deallocated.
2986: */
2987: copy->type = VM_MAP_COPY_OBJECT;
2988: copy->cpy_object = VM_OBJECT_NULL;
2989:
2990: /*
2991: * Return the new object.
2992: */
2993: return new_copy;
2994: }
2995:
2996: /*
2997: * Routine: vm_map_copy_discard_cont
2998: *
2999: * Description:
3000: * A version of vm_map_copy_discard that can be called
3001: * as a continuation from a vm_map_copy page list.
3002: */
3003: kern_return_t
3004: vm_map_copy_discard_cont(
3005: vm_map_copyin_args_t cont_args,
3006: vm_map_copy_t *copy_result) /* OUT */
3007: {
3008: vm_map_copy_discard((vm_map_copy_t) cont_args);
3009: if (copy_result != (vm_map_copy_t *)0)
3010: *copy_result = VM_MAP_COPY_NULL;
3011: return(KERN_SUCCESS);
3012: }
3013:
3014: kern_return_t
3015: vm_map_overwrite_submap_recurse(
3016: vm_map_t dst_map,
3017: vm_offset_t dst_addr,
3018: vm_size_t dst_size)
3019: {
3020: vm_offset_t dst_end;
3021: vm_map_entry_t tmp_entry;
3022: vm_map_entry_t entry;
3023: kern_return_t result;
3024: boolean_t encountered_sub_map = FALSE;
3025:
3026:
3027:
3028: /*
3029: * Verify that the destination is all writeable
3030: * initially. We have to trunc the destination
3031: * address and round the copy size or we'll end up
3032: * splitting entries in strange ways.
3033: */
3034:
3035: dst_end = round_page(dst_addr + dst_size);
3036:
3037: start_pass_1:
3038: vm_map_lock(dst_map);
3039: if (!vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry)) {
3040: vm_map_unlock(dst_map);
3041: return(KERN_INVALID_ADDRESS);
3042: }
3043:
3044: vm_map_clip_start(dst_map, tmp_entry, trunc_page(dst_addr));
3045:
3046: for (entry = tmp_entry;;) {
3047: vm_map_entry_t next;
3048:
3049: next = entry->vme_next;
3050: while(entry->is_sub_map) {
3051: vm_offset_t sub_start;
3052: vm_offset_t sub_end;
3053: vm_offset_t local_end;
3054:
3055: if (entry->in_transition) {
3056: /*
3057: * Say that we are waiting, and wait for entry.
3058: */
3059: entry->needs_wakeup = TRUE;
3060: vm_map_entry_wait(dst_map, THREAD_UNINT);
3061:
3062: goto start_pass_1;
3063: }
3064:
3065: encountered_sub_map = TRUE;
3066: sub_start = entry->offset;
3067:
3068: if(entry->vme_end < dst_end)
3069: sub_end = entry->vme_end;
3070: else
3071: sub_end = dst_end;
3072: sub_end -= entry->vme_start;
3073: sub_end += entry->offset;
3074: local_end = entry->vme_end;
3075: vm_map_unlock(dst_map);
3076:
3077: result = vm_map_overwrite_submap_recurse(
3078: entry->object.sub_map,
3079: sub_start,
3080: sub_end - sub_start);
3081:
3082: if(result != KERN_SUCCESS)
3083: return result;
3084: if (dst_end <= entry->vme_end)
3085: return KERN_SUCCESS;
3086: vm_map_lock(dst_map);
3087: if(!vm_map_lookup_entry(dst_map, local_end,
3088: &tmp_entry)) {
3089: vm_map_unlock(dst_map);
3090: return(KERN_INVALID_ADDRESS);
3091: }
3092: entry = tmp_entry;
3093: next = entry->vme_next;
3094: }
3095:
3096: if ( ! (entry->protection & VM_PROT_WRITE)) {
3097: vm_map_unlock(dst_map);
3098: return(KERN_PROTECTION_FAILURE);
3099: }
3100:
3101: /*
3102: * If the entry is in transition, we must wait
3103: * for it to exit that state. Anything could happen
3104: * when we unlock the map, so start over.
3105: */
3106: if (entry->in_transition) {
3107:
3108: /*
3109: * Say that we are waiting, and wait for entry.
3110: */
3111: entry->needs_wakeup = TRUE;
3112: vm_map_entry_wait(dst_map, THREAD_UNINT);
3113:
3114: goto start_pass_1;
3115: }
3116:
3117: /*
3118: * our range is contained completely within this map entry
3119: */
3120: if (dst_end <= entry->vme_end) {
3121: vm_map_unlock(dst_map);
3122: return KERN_SUCCESS;
3123: }
3124: /*
3125: * check that range specified is contiguous region
3126: */
3127: if ((next == vm_map_to_entry(dst_map)) ||
3128: (next->vme_start != entry->vme_end)) {
3129: vm_map_unlock(dst_map);
3130: return(KERN_INVALID_ADDRESS);
3131: }
3132:
3133: /*
3134: * Check for permanent objects in the destination.
3135: */
3136: if ((entry->object.vm_object != VM_OBJECT_NULL) &&
3137: ((!entry->object.vm_object->internal) ||
3138: (entry->object.vm_object->true_share))) {
3139: if(encountered_sub_map) {
3140: vm_map_unlock(dst_map);
3141: return(KERN_FAILURE);
3142: }
3143: }
3144:
3145:
3146: entry = next;
3147: }/* for */
3148: vm_map_unlock(dst_map);
3149: return(KERN_SUCCESS);
3150: }
3151:
3152: /*
3153: * Routine: vm_map_copy_overwrite
3154: *
3155: * Description:
3156: * Copy the memory described by the map copy
3157: * object (copy; returned by vm_map_copyin) onto
3158: * the specified destination region (dst_map, dst_addr).
3159: * The destination must be writeable.
3160: *
3161: * Unlike vm_map_copyout, this routine actually
3162: * writes over previously-mapped memory. If the
3163: * previous mapping was to a permanent (user-supplied)
3164: * memory object, it is preserved.
3165: *
3166: * The attributes (protection and inheritance) of the
3167: * destination region are preserved.
3168: *
3169: * If successful, consumes the copy object.
3170: * Otherwise, the caller is responsible for it.
3171: *
3172: * Implementation notes:
3173: * To overwrite aligned temporary virtual memory, it is
3174: * sufficient to remove the previous mapping and insert
3175: * the new copy. This replacement is done either on
3176: * the whole region (if no permanent virtual memory
3177: * objects are embedded in the destination region) or
3178: * in individual map entries.
3179: *
3180: * To overwrite permanent virtual memory , it is necessary
3181: * to copy each page, as the external memory management
3182: * interface currently does not provide any optimizations.
3183: *
3184: * Unaligned memory also has to be copied. It is possible
3185: * to use 'vm_trickery' to copy the aligned data. This is
3186: * not done but not hard to implement.
3187: *
3188: * Once a page of permanent memory has been overwritten,
3189: * it is impossible to interrupt this function; otherwise,
3190: * the call would be neither atomic nor location-independent.
3191: * The kernel-state portion of a user thread must be
3192: * interruptible.
3193: *
3194: * It may be expensive to forward all requests that might
3195: * overwrite permanent memory (vm_write, vm_copy) to
3196: * uninterruptible kernel threads. This routine may be
3197: * called by interruptible threads; however, success is
3198: * not guaranteed -- if the request cannot be performed
3199: * atomically and interruptibly, an error indication is
3200: * returned.
3201: */
3202:
3203: kern_return_t
3204: vm_map_copy_overwrite(
3205: vm_map_t dst_map,
3206: vm_offset_t dst_addr,
3207: vm_map_copy_t copy,
3208: boolean_t interruptible)
3209: {
3210: vm_offset_t dst_end;
3211: vm_map_entry_t tmp_entry;
3212: vm_map_entry_t entry;
3213: kern_return_t kr;
3214: boolean_t aligned = TRUE;
3215: boolean_t contains_permanent_objects = FALSE;
3216: boolean_t encountered_sub_map = FALSE;
3217: vm_offset_t base_addr;
3218: vm_size_t copy_size;
3219: vm_size_t total_size;
3220:
3221:
3222: /*
3223: * Check for null copy object.
3224: */
3225:
3226: if (copy == VM_MAP_COPY_NULL)
3227: return(KERN_SUCCESS);
3228:
3229: /*
3230: * Check for special kernel buffer allocated
3231: * by new_ipc_kmsg_copyin.
3232: */
3233:
3234: if (copy->type == VM_MAP_COPY_KERNEL_BUFFER) {
3235: return(vm_map_copyout_kernel_buffer(dst_map, &dst_addr,
3236: copy, TRUE));
3237: }
3238:
3239: /*
3240: * Only works for entry lists at the moment. Will
3241: * support page lists later.
3242: */
3243:
3244: assert(copy->type == VM_MAP_COPY_ENTRY_LIST);
3245:
3246: if (copy->size == 0) {
3247: vm_map_copy_discard(copy);
3248: return(KERN_SUCCESS);
3249: }
3250:
3251: /*
3252: * Verify that the destination is all writeable
3253: * initially. We have to trunc the destination
3254: * address and round the copy size or we'll end up
3255: * splitting entries in strange ways.
3256: */
3257:
3258: if (!page_aligned(copy->size) ||
3259: !page_aligned (copy->offset) ||
3260: !page_aligned (dst_addr))
3261: {
3262: aligned = FALSE;
3263: dst_end = round_page(dst_addr + copy->size);
3264: } else {
3265: dst_end = dst_addr + copy->size;
3266: }
3267:
3268: start_pass_1:
3269: vm_map_lock(dst_map);
3270: if (!vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry)) {
3271: vm_map_unlock(dst_map);
3272: return(KERN_INVALID_ADDRESS);
3273: }
3274: vm_map_clip_start(dst_map, tmp_entry, trunc_page(dst_addr));
3275: for (entry = tmp_entry;;) {
3276: vm_map_entry_t next = entry->vme_next;
3277:
3278: while(entry->is_sub_map) {
3279: vm_offset_t sub_start;
3280: vm_offset_t sub_end;
3281: vm_offset_t local_end;
3282:
3283: if (entry->in_transition) {
3284:
3285: /*
3286: * Say that we are waiting, and wait for entry.
3287: */
3288: entry->needs_wakeup = TRUE;
3289: vm_map_entry_wait(dst_map, THREAD_UNINT);
3290:
3291: goto start_pass_1;
3292: }
3293:
3294: local_end = entry->vme_end;
3295: if (!(entry->needs_copy)) {
3296: /* if needs_copy we are a COW submap */
3297: /* in such a case we just replace so */
3298: /* there is no need for the follow- */
3299: /* ing check. */
3300: encountered_sub_map = TRUE;
3301: sub_start = entry->offset;
3302:
3303: if(entry->vme_end < dst_end)
3304: sub_end = entry->vme_end;
3305: else
3306: sub_end = dst_end;
3307: sub_end -= entry->vme_start;
3308: sub_end += entry->offset;
3309: vm_map_unlock(dst_map);
3310:
3311: kr = vm_map_overwrite_submap_recurse(
3312: entry->object.sub_map,
3313: sub_start,
3314: sub_end - sub_start);
3315: if(kr != KERN_SUCCESS)
3316: return kr;
3317: vm_map_lock(dst_map);
3318: }
3319:
3320: if (dst_end <= entry->vme_end)
3321: goto start_overwrite;
3322: if(!vm_map_lookup_entry(dst_map, local_end,
3323: &entry)) {
3324: vm_map_unlock(dst_map);
3325: return(KERN_INVALID_ADDRESS);
3326: }
3327: next = entry->vme_next;
3328: }
3329:
3330: if ( ! (entry->protection & VM_PROT_WRITE)) {
3331: vm_map_unlock(dst_map);
3332: return(KERN_PROTECTION_FAILURE);
3333: }
3334:
3335: /*
3336: * If the entry is in transition, we must wait
3337: * for it to exit that state. Anything could happen
3338: * when we unlock the map, so start over.
3339: */
3340: if (entry->in_transition) {
3341:
3342: /*
3343: * Say that we are waiting, and wait for entry.
3344: */
3345: entry->needs_wakeup = TRUE;
3346: vm_map_entry_wait(dst_map, THREAD_UNINT);
3347:
3348: goto start_pass_1;
3349: }
3350:
3351: /*
3352: * our range is contained completely within this map entry
3353: */
3354: if (dst_end <= entry->vme_end)
3355: break;
3356: /*
3357: * check that range specified is contiguous region
3358: */
3359: if ((next == vm_map_to_entry(dst_map)) ||
3360: (next->vme_start != entry->vme_end)) {
3361: vm_map_unlock(dst_map);
3362: return(KERN_INVALID_ADDRESS);
3363: }
3364:
3365:
3366: /*
3367: * Check for permanent objects in the destination.
3368: */
3369: if ((entry->object.vm_object != VM_OBJECT_NULL) &&
3370: ((!entry->object.vm_object->internal) ||
3371: (entry->object.vm_object->true_share))) {
3372: if(encountered_sub_map) {
3373: vm_map_unlock(dst_map);
3374: return(KERN_INVALID_ADDRESS);
3375: }
3376: contains_permanent_objects = TRUE;
3377: }
3378:
3379: entry = next;
3380: }/* for */
3381:
3382: start_overwrite:
3383: /*
3384: * If there are permanent objects in the destination, then
3385: * the copy cannot be interrupted.
3386: */
3387:
3388: if (interruptible && contains_permanent_objects) {
3389: vm_map_unlock(dst_map);
3390: return(KERN_FAILURE); /* XXX */
3391: }
3392:
3393: /*
3394: *
3395: * Make a second pass, overwriting the data
3396: * At the beginning of each loop iteration,
3397: * the next entry to be overwritten is "tmp_entry"
3398: * (initially, the value returned from the lookup above),
3399: * and the starting address expected in that entry
3400: * is "start".
3401: */
3402:
3403: total_size = copy->size;
3404: if(encountered_sub_map) {
3405: copy_size = 0;
3406: /* re-calculate tmp_entry since we've had the map */
3407: /* unlocked */
3408: if (!vm_map_lookup_entry( dst_map, dst_addr, &tmp_entry)) {
3409: vm_map_unlock(dst_map);
3410: return(KERN_INVALID_ADDRESS);
3411: }
3412: } else {
3413: copy_size = copy->size;
3414: }
3415:
3416: base_addr = dst_addr;
3417: while(TRUE) {
3418: /* deconstruct the copy object and do in parts */
3419: /* only in sub_map, interruptable case */
3420: vm_map_entry_t copy_entry;
3421: vm_map_entry_t previous_prev;
3422: vm_map_entry_t next_copy;
3423: int nentries;
3424: int remaining_entries;
3425: int new_offset;
3426:
3427: for (entry = tmp_entry; copy_size == 0;) {
3428: vm_map_entry_t next;
3429:
3430: next = entry->vme_next;
3431:
3432: /* tmp_entry and base address are moved along */
3433: /* each time we encounter a sub-map. Otherwise */
3434: /* entry can outpase tmp_entry, and the copy_size */
3435: /* may reflect the distance between them */
3436: /* if the current entry is found to be in transition */
3437: /* we will start over at the beginning or the last */
3438: /* encounter of a submap as dictated by base_addr */
3439: /* we will zero copy_size accordingly. */
3440: if (entry->in_transition) {
3441: /*
3442: * Say that we are waiting, and wait for entry.
3443: */
3444: entry->needs_wakeup = TRUE;
3445: vm_map_entry_wait(dst_map, THREAD_UNINT);
3446:
3447: vm_map_lock(dst_map);
3448: if(!vm_map_lookup_entry(dst_map, base_addr,
3449: &tmp_entry)) {
3450: vm_map_unlock(dst_map);
3451: return(KERN_INVALID_ADDRESS);
3452: }
3453: copy_size = 0;
3454: entry = tmp_entry;
3455: continue;
3456: }
3457: if(entry->is_sub_map) {
3458: vm_offset_t sub_start;
3459: vm_offset_t sub_end;
3460: vm_offset_t local_end;
3461:
3462: if (entry->needs_copy) {
3463: /* if this is a COW submap */
3464: /* just back the range with a */
3465: /* anonymous entry */
3466: if(entry->vme_end < dst_end)
3467: sub_end = entry->vme_end;
3468: else
3469: sub_end = dst_end;
3470: if(entry->vme_start < base_addr)
3471: sub_start = base_addr;
3472: else
3473: sub_start = entry->vme_start;
3474: vm_map_clip_end(
3475: dst_map, entry, sub_end);
3476: vm_map_clip_start(
3477: dst_map, entry, sub_start);
3478: entry->is_sub_map = FALSE;
3479: vm_map_deallocate(
3480: entry->object.sub_map);
3481: entry->object.sub_map = NULL;
3482: entry->is_shared = FALSE;
3483: entry->needs_copy = FALSE;
3484: entry->offset = 0;
3485: entry->protection = VM_PROT_ALL;
3486: entry->max_protection = VM_PROT_ALL;
3487: entry->wired_count = 0;
3488: entry->user_wired_count = 0;
3489: if(entry->inheritance
3490: == VM_INHERIT_SHARE)
3491: entry->inheritance = VM_INHERIT_COPY;
3492: continue;
3493: }
3494: /* first take care of any non-sub_map */
3495: /* entries to send */
3496: if(base_addr < entry->vme_start) {
3497: /* stuff to send */
3498: copy_size =
3499: entry->vme_start - base_addr;
3500: break;
3501: }
3502: sub_start = entry->offset;
3503:
3504: if(entry->vme_end < dst_end)
3505: sub_end = entry->vme_end;
3506: else
3507: sub_end = dst_end;
3508: sub_end -= entry->vme_start;
3509: sub_end += entry->offset;
3510: local_end = entry->vme_end;
3511: vm_map_unlock(dst_map);
3512: copy_size = sub_end - sub_start;
3513:
3514: /* adjust the copy object */
3515: if (total_size > copy_size) {
3516: vm_size_t local_size = 0;
3517: vm_size_t entry_size;
3518:
3519: nentries = 1;
3520: new_offset = copy->offset;
3521: copy_entry = vm_map_copy_first_entry(copy);
3522: while(copy_entry !=
3523: vm_map_copy_to_entry(copy)){
3524: entry_size = copy_entry->vme_end -
3525: copy_entry->vme_start;
3526: if((local_size < copy_size) &&
3527: ((local_size + entry_size)
3528: >= copy_size)) {
3529: vm_map_copy_clip_end(copy,
3530: copy_entry,
3531: copy_entry->vme_start +
3532: (copy_size - local_size));
3533: entry_size = copy_entry->vme_end -
3534: copy_entry->vme_start;
3535: local_size += entry_size;
3536: new_offset += entry_size;
3537: }
3538: if(local_size >= copy_size) {
3539: next_copy = copy_entry->vme_next;
3540: copy_entry->vme_next =
3541: vm_map_copy_to_entry(copy);
3542: previous_prev =
3543: copy->cpy_hdr.links.prev;
3544: copy->cpy_hdr.links.prev = copy_entry;
3545: copy->size = copy_size;
3546: remaining_entries =
3547: copy->cpy_hdr.nentries;
3548: remaining_entries -= nentries;
3549: copy->cpy_hdr.nentries = nentries;
3550: break;
3551: } else {
3552: local_size += entry_size;
3553: new_offset += entry_size;
3554: nentries++;
3555: }
3556: copy_entry = copy_entry->vme_next;
3557: }
3558: }
3559:
3560: kr = vm_map_copy_overwrite(
3561: entry->object.sub_map,
3562: sub_start,
3563: copy,
3564: interruptible);
3565: if(kr != KERN_SUCCESS) {
3566: if(next_copy != NULL) {
3567: copy->cpy_hdr.nentries +=
3568: remaining_entries;
3569: copy->cpy_hdr.links.prev->vme_next =
3570: next_copy;
3571: copy->cpy_hdr.links.prev
3572: = previous_prev;
3573: copy->size = total_size;
3574: }
3575: return kr;
3576: }
3577: if (dst_end <= local_end) {
3578: return(KERN_SUCCESS);
3579: }
3580: /* otherwise copy no longer exists, it was */
3581: /* destroyed after successful copy_overwrite */
3582: copy = (vm_map_copy_t)
3583: zalloc(vm_map_copy_zone);
3584: vm_map_copy_first_entry(copy) =
3585: vm_map_copy_last_entry(copy) =
3586: vm_map_copy_to_entry(copy);
3587: copy->type = VM_MAP_COPY_ENTRY_LIST;
3588: copy->offset = new_offset;
3589:
3590: total_size -= copy_size;
3591: copy_size = 0;
3592: /* put back remainder of copy in container */
3593: if(next_copy != NULL) {
3594: copy->cpy_hdr.nentries = remaining_entries;
3595: copy->cpy_hdr.links.next = next_copy;
3596: copy->cpy_hdr.links.prev = previous_prev;
3597: copy->size = total_size;
3598: next_copy->vme_prev =
3599: vm_map_copy_to_entry(copy);
3600: next_copy = NULL;
3601: }
3602: base_addr = local_end;
3603: vm_map_lock(dst_map);
3604: if(!vm_map_lookup_entry(dst_map,
3605: local_end, &tmp_entry)) {
3606: vm_map_unlock(dst_map);
3607: return(KERN_INVALID_ADDRESS);
3608: }
3609: entry = tmp_entry;
3610: continue;
3611: }
3612: if (dst_end <= entry->vme_end) {
3613: copy_size = dst_end - base_addr;
3614: break;
3615: }
3616:
3617: if ((next == vm_map_to_entry(dst_map)) ||
3618: (next->vme_start != entry->vme_end)) {
3619: vm_map_unlock(dst_map);
3620: return(KERN_INVALID_ADDRESS);
3621: }
3622:
3623: entry = next;
3624: }/* for */
3625:
3626: next_copy = NULL;
3627: nentries = 1;
3628:
3629: /* adjust the copy object */
3630: if (total_size > copy_size) {
3631: vm_size_t local_size = 0;
3632: vm_size_t entry_size;
3633:
3634: new_offset = copy->offset;
3635: copy_entry = vm_map_copy_first_entry(copy);
3636: while(copy_entry != vm_map_copy_to_entry(copy)) {
3637: entry_size = copy_entry->vme_end -
3638: copy_entry->vme_start;
3639: if((local_size < copy_size) &&
3640: ((local_size + entry_size)
3641: >= copy_size)) {
3642: vm_map_copy_clip_end(copy, copy_entry,
3643: copy_entry->vme_start +
3644: (copy_size - local_size));
3645: entry_size = copy_entry->vme_end -
3646: copy_entry->vme_start;
3647: local_size += entry_size;
3648: new_offset += entry_size;
3649: }
3650: if(local_size >= copy_size) {
3651: next_copy = copy_entry->vme_next;
3652: copy_entry->vme_next =
3653: vm_map_copy_to_entry(copy);
3654: previous_prev =
3655: copy->cpy_hdr.links.prev;
3656: copy->cpy_hdr.links.prev = copy_entry;
3657: copy->size = copy_size;
3658: remaining_entries =
3659: copy->cpy_hdr.nentries;
3660: remaining_entries -= nentries;
3661: copy->cpy_hdr.nentries = nentries;
3662: break;
3663: } else {
3664: local_size += entry_size;
3665: new_offset += entry_size;
3666: nentries++;
3667: }
3668: copy_entry = copy_entry->vme_next;
3669: }
3670: }
3671:
3672: if (aligned) {
3673: if ((kr = vm_map_copy_overwrite_aligned(
3674: dst_map, tmp_entry,
3675: copy, base_addr)) != KERN_SUCCESS) {
3676: if(next_copy != NULL) {
3677: copy->cpy_hdr.nentries +=
3678: remaining_entries;
3679: copy->cpy_hdr.links.prev->vme_next =
3680: next_copy;
3681: copy->cpy_hdr.links.prev =
3682: previous_prev;
3683: copy->size += copy_size;
3684: }
3685: return kr;
3686: }
3687: vm_map_unlock(dst_map);
3688: } else {
3689: /*
3690: * Performance gain:
3691: *
3692: * if the copy and dst address are misaligned but the same
3693: * offset within the page we can copy_not_aligned the
3694: * misaligned parts and copy aligned the rest. If they are
3695: * aligned but len is unaligned we simply need to copy
3696: * the end bit unaligned. We'll need to split the misaligned
3697: * bits of the region in this case !
3698: */
3699: /* ALWAYS UNLOCKS THE dst_map MAP */
3700: if ((kr = vm_map_copy_overwrite_unaligned( dst_map,
3701: tmp_entry, copy, base_addr)) != KERN_SUCCESS) {
3702: if(next_copy != NULL) {
3703: copy->cpy_hdr.nentries +=
3704: remaining_entries;
3705: copy->cpy_hdr.links.prev->vme_next =
3706: next_copy;
3707: copy->cpy_hdr.links.prev =
3708: previous_prev;
3709: copy->size += copy_size;
3710: }
3711: return kr;
3712: }
3713: }
3714: total_size -= copy_size;
3715: if(total_size == 0)
3716: break;
3717: base_addr += copy_size;
3718: copy_size = 0;
3719: copy->offset = new_offset;
3720: if(next_copy != NULL) {
3721: copy->cpy_hdr.nentries = remaining_entries;
3722: copy->cpy_hdr.links.next = next_copy;
3723: copy->cpy_hdr.links.prev = previous_prev;
3724: next_copy->vme_prev = vm_map_copy_to_entry(copy);
3725: copy->size = total_size;
3726: }
3727: vm_map_lock(dst_map);
3728: while(TRUE) {
3729: if (!vm_map_lookup_entry(dst_map,
3730: base_addr, &tmp_entry)) {
3731: vm_map_unlock(dst_map);
3732: return(KERN_INVALID_ADDRESS);
3733: }
3734: if (tmp_entry->in_transition) {
3735: entry->needs_wakeup = TRUE;
3736: vm_map_entry_wait(dst_map, THREAD_UNINT);
3737: } else {
3738: break;
3739: }
3740: }
3741: vm_map_clip_start(dst_map, tmp_entry, trunc_page(base_addr));
3742:
3743: entry = tmp_entry;
3744: } /* while */
3745:
3746: /*
3747: * Throw away the vm_map_copy object
3748: */
3749: vm_map_copy_discard(copy);
3750:
3751: return(KERN_SUCCESS);
3752: }/* vm_map_copy_overwrite */
3753:
3754: /*
3755: * Routine: vm_map_copy_overwrite_unaligned
3756: *
3757: * Decription:
3758: * Physically copy unaligned data
3759: *
3760: * Implementation:
3761: * Unaligned parts of pages have to be physically copied. We use
3762: * a modified form of vm_fault_copy (which understands none-aligned
3763: * page offsets and sizes) to do the copy. We attempt to copy as
3764: * much memory in one go as possibly, however vm_fault_copy copies
3765: * within 1 memory object so we have to find the smaller of "amount left"
3766: * "source object data size" and "target object data size". With
3767: * unaligned data we don't need to split regions, therefore the source
3768: * (copy) object should be one map entry, the target range may be split
3769: * over multiple map entries however. In any event we are pessimistic
3770: * about these assumptions.
3771: *
3772: * Assumptions:
3773: * dst_map is locked on entry and is return locked on success,
3774: * unlocked on error.
3775: */
3776:
3777: kern_return_t
3778: vm_map_copy_overwrite_unaligned(
3779: vm_map_t dst_map,
3780: vm_map_entry_t entry,
3781: vm_map_copy_t copy,
3782: vm_offset_t start)
3783: {
3784: vm_map_entry_t copy_entry = vm_map_copy_first_entry(copy);
3785: vm_map_version_t version;
3786: vm_object_t dst_object;
3787: vm_offset_t dst_offset;
3788: vm_offset_t src_offset;
3789: vm_offset_t entry_offset;
3790: vm_offset_t entry_end;
3791: vm_size_t src_size,
3792: dst_size,
3793: copy_size,
3794: amount_left;
3795: kern_return_t kr = KERN_SUCCESS;
3796:
3797: vm_map_lock_write_to_read(dst_map);
3798:
3799: src_offset = copy->offset - trunc_page(copy->offset);
3800: amount_left = copy->size;
3801: /*
3802: * unaligned so we never clipped this entry, we need the offset into
3803: * the vm_object not just the data.
3804: */
3805: while (amount_left > 0) {
3806:
3807: /* "start" must be within the current map entry */
3808: assert ((start>=entry->vme_start) && (start<entry->vme_end));
3809:
3810: dst_offset = start - entry->vme_start;
3811:
3812: dst_size = entry->vme_end - start;
3813:
3814: src_size = copy_entry->vme_end -
3815: (copy_entry->vme_start + src_offset);
3816:
3817: if (dst_size < src_size) {
3818: /*
3819: * we can only copy dst_size bytes before
3820: * we have to get the next destination entry
3821: */
3822: copy_size = dst_size;
3823: } else {
3824: /*
3825: * we can only copy src_size bytes before
3826: * we have to get the next source copy entry
3827: */
3828: copy_size = src_size;
3829: }
3830:
3831: if (copy_size > amount_left) {
3832: copy_size = amount_left;
3833: }
3834: /*
3835: * Entry needs copy, create a shadow shadow object for
3836: * copy on write region.
3837: */
3838: if (entry->needs_copy &&
3839: ((entry->protection & VM_PROT_WRITE) != 0))
3840: {
3841: if (vm_map_lock_read_to_write(dst_map)) {
3842: vm_map_lock_read(dst_map);
3843: goto RetryLookup;
3844: }
3845: vm_object_shadow(&entry->object.vm_object,
3846: &entry->offset,
3847: (vm_size_t)(entry->vme_end
3848: - entry->vme_start));
3849: entry->needs_copy = FALSE;
3850: vm_map_lock_write_to_read(dst_map);
3851: }
3852: dst_object = entry->object.vm_object;
3853: /*
3854: * unlike with the virtual (aligned) copy we're going
3855: * to fault on it therefore we need a target object.
3856: */
3857: if (dst_object == VM_OBJECT_NULL) {
3858: if (vm_map_lock_read_to_write(dst_map)) {
3859: vm_map_lock_read(dst_map);
3860: goto RetryLookup;
3861: }
3862: dst_object = vm_object_allocate((vm_size_t)
3863: entry->vme_end - entry->vme_start);
3864: entry->object.vm_object = dst_object;
3865: entry->offset = 0;
3866: vm_map_lock_write_to_read(dst_map);
3867: }
3868: /*
3869: * Take an object reference and unlock map. The "entry" may
3870: * disappear or change when the map is unlocked.
3871: */
3872: vm_object_reference(dst_object);
3873: version.main_timestamp = dst_map->timestamp;
3874: entry_offset = entry->offset;
3875: entry_end = entry->vme_end;
3876: vm_map_unlock_read(dst_map);
3877: /*
3878: * Copy as much as possible in one pass
3879: */
3880: kr = vm_fault_copy(
3881: copy_entry->object.vm_object,
3882: copy_entry->offset + src_offset,
3883: ©_size,
3884: dst_object,
3885: entry_offset + dst_offset,
3886: dst_map,
3887: &version,
3888: THREAD_UNINT );
3889:
3890: start += copy_size;
3891: src_offset += copy_size;
3892: amount_left -= copy_size;
3893: /*
3894: * Release the object reference
3895: */
3896: vm_object_deallocate(dst_object);
3897: /*
3898: * If a hard error occurred, return it now
3899: */
3900: if (kr != KERN_SUCCESS)
3901: return kr;
3902:
3903: if ((copy_entry->vme_start + src_offset) == copy_entry->vme_end
3904: || amount_left == 0)
3905: {
3906: /*
3907: * all done with this copy entry, dispose.
3908: */
3909: vm_map_copy_entry_unlink(copy, copy_entry);
3910: vm_object_deallocate(copy_entry->object.vm_object);
3911: vm_map_copy_entry_dispose(copy, copy_entry);
3912:
3913: if ((copy_entry = vm_map_copy_first_entry(copy))
3914: == vm_map_copy_to_entry(copy) && amount_left) {
3915: /*
3916: * not finished copying but run out of source
3917: */
3918: return KERN_INVALID_ADDRESS;
3919: }
3920: src_offset = 0;
3921: }
3922:
3923: if (amount_left == 0)
3924: return KERN_SUCCESS;
3925:
3926: vm_map_lock_read(dst_map);
3927: if (version.main_timestamp == dst_map->timestamp) {
3928: if (start == entry_end) {
3929: /*
3930: * destination region is split. Use the version
3931: * information to avoid a lookup in the normal
3932: * case.
3933: */
3934: entry = entry->vme_next;
3935: /*
3936: * should be contiguous. Fail if we encounter
3937: * a hole in the destination.
3938: */
3939: if (start != entry->vme_start) {
3940: vm_map_unlock_read(dst_map);
3941: return KERN_INVALID_ADDRESS ;
3942: }
3943: }
3944: } else {
3945: /*
3946: * Map version check failed.
3947: * we must lookup the entry because somebody
3948: * might have changed the map behind our backs.
3949: */
3950: RetryLookup:
3951: if (!vm_map_lookup_entry(dst_map, start, &entry))
3952: {
3953: vm_map_unlock_read(dst_map);
3954: return KERN_INVALID_ADDRESS ;
3955: }
3956: }
3957: }/* while */
3958:
3959: /* NOTREACHED ?? */
3960: vm_map_unlock_read(dst_map);
3961:
3962: return KERN_SUCCESS;
3963: }/* vm_map_copy_overwrite_unaligned */
3964:
3965: /*
3966: * Routine: vm_map_copy_overwrite_aligned
3967: *
3968: * Description:
3969: * Does all the vm_trickery possible for whole pages.
3970: *
3971: * Implementation:
3972: *
3973: * If there are no permanent objects in the destination,
3974: * and the source and destination map entry zones match,
3975: * and the destination map entry is not shared,
3976: * then the map entries can be deleted and replaced
3977: * with those from the copy. The following code is the
3978: * basic idea of what to do, but there are lots of annoying
3979: * little details about getting protection and inheritance
3980: * right. Should add protection, inheritance, and sharing checks
3981: * to the above pass and make sure that no wiring is involved.
3982: */
3983:
3984: kern_return_t
3985: vm_map_copy_overwrite_aligned(
3986: vm_map_t dst_map,
3987: vm_map_entry_t tmp_entry,
3988: vm_map_copy_t copy,
3989: vm_offset_t start)
3990: {
3991: vm_object_t object;
3992: vm_map_entry_t copy_entry;
3993: vm_size_t copy_size;
3994: vm_size_t size;
3995: vm_map_entry_t entry;
3996:
3997: while ((copy_entry = vm_map_copy_first_entry(copy))
3998: != vm_map_copy_to_entry(copy))
3999: {
4000: copy_size = (copy_entry->vme_end - copy_entry->vme_start);
4001:
4002: entry = tmp_entry;
4003: size = (entry->vme_end - entry->vme_start);
4004: /*
4005: * Make sure that no holes popped up in the
4006: * address map, and that the protection is
4007: * still valid, in case the map was unlocked
4008: * earlier.
4009: */
4010:
4011: if ((entry->vme_start != start) || (entry->is_sub_map)) {
4012: vm_map_unlock(dst_map);
4013: return(KERN_INVALID_ADDRESS);
4014: }
4015: assert(entry != vm_map_to_entry(dst_map));
4016:
4017: /*
4018: * Check protection again
4019: */
4020:
4021: if ( ! (entry->protection & VM_PROT_WRITE)) {
4022: vm_map_unlock(dst_map);
4023: return(KERN_PROTECTION_FAILURE);
4024: }
4025:
4026: /*
4027: * Adjust to source size first
4028: */
4029:
4030: if (copy_size < size) {
4031: vm_map_clip_end(dst_map, entry, entry->vme_start + copy_size);
4032: size = copy_size;
4033: }
4034:
4035: /*
4036: * Adjust to destination size
4037: */
4038:
4039: if (size < copy_size) {
4040: vm_map_copy_clip_end(copy, copy_entry,
4041: copy_entry->vme_start + size);
4042: copy_size = size;
4043: }
4044:
4045: assert((entry->vme_end - entry->vme_start) == size);
4046: assert((tmp_entry->vme_end - tmp_entry->vme_start) == size);
4047: assert((copy_entry->vme_end - copy_entry->vme_start) == size);
4048:
4049: /*
4050: * If the destination contains temporary unshared memory,
4051: * we can perform the copy by throwing it away and
4052: * installing the source data.
4053: */
4054:
4055: object = entry->object.vm_object;
4056: if ((!entry->is_shared &&
4057: ((object == VM_OBJECT_NULL) ||
4058: (object->internal && !object->true_share))) ||
4059: entry->needs_copy) {
4060: vm_object_t old_object = entry->object.vm_object;
4061: vm_offset_t old_offset = entry->offset;
4062: vm_offset_t offset;
4063:
4064: /*
4065: * Ensure that the source and destination aren't
4066: * identical
4067: */
4068: if (old_object == copy_entry->object.vm_object &&
4069: old_offset == copy_entry->offset) {
4070: vm_map_copy_entry_unlink(copy, copy_entry);
4071: vm_map_copy_entry_dispose(copy, copy_entry);
4072:
4073: if (old_object != VM_OBJECT_NULL)
4074: vm_object_deallocate(old_object);
4075:
4076: start = tmp_entry->vme_end;
4077: tmp_entry = tmp_entry->vme_next;
4078: continue;
4079: }
4080:
4081: entry->object = copy_entry->object;
4082: object = entry->object.vm_object;
4083: offset = entry->offset = copy_entry->offset;
4084: entry->needs_copy = copy_entry->needs_copy;
4085: entry->wired_count = 0;
4086: entry->user_wired_count = 0;
4087:
4088: vm_map_copy_entry_unlink(copy, copy_entry);
4089: vm_map_copy_entry_dispose(copy, copy_entry);
4090:
4091: if (old_object != VM_OBJECT_NULL) {
4092: vm_object_pmap_protect(
4093: old_object,
4094: old_offset,
4095: size,
4096: dst_map->pmap,
4097: tmp_entry->vme_start,
4098: VM_PROT_NONE);
4099:
4100: vm_object_deallocate(old_object);
4101: }
4102:
4103: /*
4104: * Try to aggressively enter physical mappings
4105: * (but avoid uninstantiated objects)
4106: */
4107: if (object != VM_OBJECT_NULL) {
4108: vm_offset_t va = entry->vme_start;
4109:
4110: while (va < entry->vme_end) {
4111: register vm_page_t m;
4112: vm_prot_t prot;
4113:
4114: /*
4115: * Look for the page in the top object
4116: */
4117: prot = entry->protection;
4118: vm_object_lock(object);
4119: vm_object_paging_begin(object);
4120:
4121: if ((m = vm_page_lookup(object,offset)) !=
4122: VM_PAGE_NULL && !m->busy &&
4123: !m->fictitious &&
4124: (!m->unusual || (!m->error &&
4125: !m->restart && !m->absent &&
4126: (prot & m->page_lock) == 0))) {
4127:
4128: m->busy = TRUE;
4129: vm_object_unlock(object);
4130:
4131: /*
4132: * Honor COW obligations
4133: */
4134: if (entry->needs_copy)
4135: prot &= ~VM_PROT_WRITE;
4136:
4137: PMAP_ENTER(dst_map->pmap, va, m,
4138: prot, FALSE);
4139:
4140: vm_object_lock(object);
4141: vm_page_lock_queues();
4142: if (!m->active && !m->inactive)
4143: vm_page_activate(m);
4144: vm_page_unlock_queues();
4145: PAGE_WAKEUP_DONE(m);
4146: }
4147: vm_object_paging_end(object);
4148: vm_object_unlock(object);
4149:
4150: offset += PAGE_SIZE;
4151: va += PAGE_SIZE;
4152: } /* end while (va < entry->vme_end) */
4153: } /* end if (object) */
4154:
4155: /*
4156: * Set up for the next iteration. The map
4157: * has not been unlocked, so the next
4158: * address should be at the end of this
4159: * entry, and the next map entry should be
4160: * the one following it.
4161: */
4162:
4163: start = tmp_entry->vme_end;
4164: tmp_entry = tmp_entry->vme_next;
4165: } else {
4166: vm_map_version_t version;
4167: vm_object_t dst_object = entry->object.vm_object;
4168: vm_offset_t dst_offset = entry->offset;
4169: kern_return_t r;
4170:
4171: /*
4172: * Take an object reference, and record
4173: * the map version information so that the
4174: * map can be safely unlocked.
4175: */
4176:
4177: vm_object_reference(dst_object);
4178:
4179: version.main_timestamp = dst_map->timestamp;
4180:
4181: vm_map_unlock(dst_map);
4182:
4183: /*
4184: * Copy as much as possible in one pass
4185: */
4186:
4187: copy_size = size;
4188: r = vm_fault_copy(
4189: copy_entry->object.vm_object,
4190: copy_entry->offset,
4191: ©_size,
4192: dst_object,
4193: dst_offset,
4194: dst_map,
4195: &version,
4196: THREAD_UNINT );
4197:
4198: /*
4199: * Release the object reference
4200: */
4201:
4202: vm_object_deallocate(dst_object);
4203:
4204: /*
4205: * If a hard error occurred, return it now
4206: */
4207:
4208: if (r != KERN_SUCCESS)
4209: return(r);
4210:
4211: if (copy_size != 0) {
4212: /*
4213: * Dispose of the copied region
4214: */
4215:
4216: vm_map_copy_clip_end(copy, copy_entry,
4217: copy_entry->vme_start + copy_size);
4218: vm_map_copy_entry_unlink(copy, copy_entry);
4219: vm_object_deallocate(copy_entry->object.vm_object);
4220: vm_map_copy_entry_dispose(copy, copy_entry);
4221: }
4222:
4223: /*
4224: * Pick up in the destination map where we left off.
4225: *
4226: * Use the version information to avoid a lookup
4227: * in the normal case.
4228: */
4229:
4230: start += copy_size;
4231: vm_map_lock(dst_map);
4232: if ((version.main_timestamp + 1) == dst_map->timestamp) {
4233: /* We can safely use saved tmp_entry value */
4234:
4235: vm_map_clip_end(dst_map, tmp_entry, start);
4236: tmp_entry = tmp_entry->vme_next;
4237: } else {
4238: /* Must do lookup of tmp_entry */
4239:
4240: if (!vm_map_lookup_entry(dst_map, start, &tmp_entry)) {
4241: vm_map_unlock(dst_map);
4242: return(KERN_INVALID_ADDRESS);
4243: }
4244: vm_map_clip_start(dst_map, tmp_entry, start);
4245: }
4246: }
4247: }/* while */
4248:
4249: return(KERN_SUCCESS);
4250: }/* vm_map_copy_overwrite_aligned */
4251:
4252: #if DIPC
4253: #include <dipc/dipc_counters.h>
4254: dcntr_decl(unsigned int c_dipc_overwrite_opt = 0;)
4255: dcntr_decl(unsigned int c_dipc_overwrite_nonopt = 0;)
4256: dcntr_decl(unsigned int c_dipc_overwrite_recv_done = 0;)
4257: #else /* DIPC */
4258: #define dstat_decl(foo)
4259: #define dstat(foo)
4260: #define dcntr_decl(foo)
4261: #define dcntr(foo)
4262: #endif /* DIPC */
4263:
4264: #if DIPC
4265: vm_map_copy_t
4266: vm_map_copy_overwrite_recv(
4267: vm_map_t map,
4268: vm_offset_t addr,
4269: vm_size_t size)
4270: {
4271: vm_offset_t end_addr;
4272: vm_map_copy_t copy = VM_MAP_COPY_NULL;
4273: vm_map_entry_t entry, new_entry;
4274: kern_return_t kr;
4275:
4276: if (size == 0)
4277: return VM_MAP_COPY_NULL;
4278:
4279: if (!page_aligned(size) || !page_aligned(addr)) {
4280: end_addr = round_page(addr + size);
4281: } else {
4282: end_addr = addr + size;
4283: }
4284:
4285: /* Do allocations before taking map lock. */
4286:
4287: /* build an ENTRY_LIST vm_map_copy_t */
4288: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
4289: vm_map_copy_first_entry(copy) =
4290: vm_map_copy_last_entry(copy) = vm_map_copy_to_entry(copy);
4291: copy->type = VM_MAP_COPY_ENTRY_LIST;
4292: copy->offset = addr;
4293: copy->size = size;
4294: copy->cpy_hdr.nentries = 0;
4295: copy->cpy_hdr.entries_pageable = TRUE;
4296: new_entry = vm_map_copy_entry_create(copy);
4297:
4298: vm_map_lock(map);
4299: if (!vm_map_lookup_entry(map, addr, &entry)) {
4300: vm_map_unlock(map);
4301: vm_map_copy_entry_dispose(copy, new_entry);
4302: vm_map_copy_discard(copy);
4303: return VM_MAP_COPY_NULL;
4304: }
4305: if (entry->is_sub_map) {
4306: vm_map_unlock(map);
4307: vm_map_copy_entry_dispose(copy, new_entry);
4308: vm_map_copy_discard(copy);
4309: return VM_MAP_COPY_NULL;
4310: }
4311:
4312: /*
4313: * for now, only do this if the range is contained completely
4314: * within a single entry. Just give up if entry is in_transition:
4315: * it could be another thread wiring/unwiring, but it could be another
4316: * part of this message that set it, in which case we'd deadlock if
4317: * we waited for it to clear. If the entry is not writeable, give up
4318: * and let the ipc_kmsg_copyout code handle the error later.
4319: */
4320: if ((end_addr > entry->vme_end) ||
4321: entry->in_transition ||
4322: !(entry->protection & VM_PROT_WRITE)) {
4323: vm_map_unlock(map);
4324: dcntr(++c_dipc_overwrite_nonopt);
4325: vm_map_copy_entry_dispose(copy, new_entry);
4326: vm_map_copy_discard(copy);
4327: return VM_MAP_COPY_NULL;
4328: }
4329:
4330: vm_map_clip_start(map, entry, trunc_page(addr));
4331:
4332: /* handle COW obligations */
4333: if (entry->needs_copy) {
4334: vm_object_shadow(&entry->object.vm_object, &entry->offset,
4335: (vm_size_t)(entry->vme_end - entry->vme_start));
4336: entry->needs_copy = FALSE;
4337: }
4338:
4339: /* make sure there's a target object to put pages into */
4340: if (entry->object.vm_object == VM_OBJECT_NULL) {
4341: entry->object.vm_object = vm_object_allocate((vm_size_t)
4342: (entry->vme_end - entry->vme_start));
4343: entry->offset = 0;
4344: }
4345:
4346: /*
4347: * set in_transition to keep the entry in the map from moving around
4348: * while DIPC fills the object in with data. This must be cleared
4349: * later on by calling vm_map_copy_overwrite_recv_done (below).
4350: */
4351: entry->in_transition = TRUE;
4352:
4353: /* make a copy of the entry */
4354: vm_map_entry_copy(new_entry, entry);
4355: vm_object_reference(new_entry->object.vm_object);
4356:
4357: vm_map_unlock(map);
4358:
4359: /* link in the new entry */
4360: vm_map_copy_entry_link(copy, vm_map_copy_last_entry(copy), new_entry);
4361:
4362: dcntr(++c_dipc_overwrite_opt);
4363: return copy;
4364: }
4365:
4366: /*
4367: * Find the map entry that corresponds to the copy entry, then clear
4368: * in_transition on it. Discard the copy.
4369: */
4370: kern_return_t
4371: vm_map_copy_overwrite_recv_done(
4372: vm_map_t map,
4373: vm_map_copy_t copy)
4374: {
4375: vm_map_entry_t entry, map_entry;
4376: boolean_t need_wakeup = FALSE;
4377:
4378: assert(copy != VM_MAP_COPY_NULL);
4379: assert(copy->type == VM_MAP_COPY_ENTRY_LIST);
4380: dcntr(++c_dipc_overwrite_recv_done);
4381:
4382: entry = vm_map_copy_first_entry(copy);
4383: assert(entry != VM_MAP_ENTRY_NULL);
4384:
4385: vm_map_lock(map);
4386:
4387: if (!vm_map_lookup_entry(map, entry->vme_start, &map_entry)) {
4388: vm_map_unlock(map);
4389: return KERN_INVALID_ADDRESS;
4390: }
4391: while ((map_entry != vm_map_to_entry(map)) &&
4392: (map_entry->vme_end <= entry->vme_end)) {
4393: assert(map_entry->in_transition);
4394: map_entry->in_transition = FALSE;
4395: if (map_entry->needs_wakeup) {
4396: map_entry->needs_wakeup = FALSE;
4397: need_wakeup = TRUE;
4398: }
4399: map_entry = map_entry->vme_next;
4400: }
4401: vm_map_unlock(map);
4402: if (need_wakeup)
4403: vm_map_entry_wakeup(map);
4404: vm_map_copy_discard(copy);
4405:
4406: return KERN_SUCCESS;
4407: }
4408:
4409: #endif /* DIPC */
4410:
4411: /*
4412: * Routine: vm_map_copyout_kernel_buffer
4413: *
4414: * Description:
4415: * Copy out data from a kernel buffer into space in the
4416: * destination map. The space may be otpionally dynamically
4417: * allocated.
4418: *
4419: * If successful, consumes the copy object.
4420: * Otherwise, the caller is responsible for it.
4421: */
4422: kern_return_t
4423: vm_map_copyout_kernel_buffer(
4424: vm_map_t map,
4425: vm_offset_t *addr, /* IN/OUT */
4426: vm_map_copy_t copy,
4427: boolean_t overwrite)
4428: {
4429: kern_return_t kr = KERN_SUCCESS;
4430: thread_act_t thr_act = current_act();
4431:
4432: if (!overwrite) {
4433:
4434: /*
4435: * Allocate space in the target map for the data
4436: */
4437: *addr = 0;
4438: kr = vm_map_enter(map,
4439: addr,
4440: round_page(copy->size),
4441: (vm_offset_t) 0,
4442: TRUE,
4443: VM_OBJECT_NULL,
4444: (vm_offset_t) 0,
4445: FALSE,
4446: VM_PROT_DEFAULT,
4447: VM_PROT_ALL,
4448: VM_INHERIT_DEFAULT);
4449: if (kr != KERN_SUCCESS)
4450: return(kr);
4451: }
4452:
4453: /*
4454: * Copyout the data from the kernel buffer to the target map.
4455: */
4456: if (thr_act->map == map) {
4457:
4458: /*
4459: * If the target map is the current map, just do
4460: * the copy.
4461: */
4462: if (copyout((char *)copy->cpy_kdata, (char *)*addr,
4463: copy->size)) {
4464: kr = KERN_INVALID_ADDRESS;
4465: }
4466: }
4467: else {
4468: vm_map_t oldmap;
4469:
4470: /*
4471: * If the target map is another map, assume the
4472: * target's address space identity for the duration
4473: * of the copy.
4474: */
4475: vm_map_reference(map);
4476: oldmap = vm_map_switch(map);
4477:
4478: if (copyout((char *)copy->cpy_kdata, (char *)*addr,
4479: copy->size)) {
4480: kr = KERN_INVALID_ADDRESS;
4481: }
4482:
4483: (void) vm_map_switch(oldmap);
4484: vm_map_deallocate(map);
4485: }
4486:
4487: kfree((vm_offset_t)copy, copy->cpy_kalloc_size);
4488:
4489: return(kr);
4490: }
4491:
4492: /*
4493: * Macro: vm_map_copy_insert
4494: *
4495: * Description:
4496: * Link a copy chain ("copy") into a map at the
4497: * specified location (after "where").
4498: * Side effects:
4499: * The copy chain is destroyed.
4500: * Warning:
4501: * The arguments are evaluated multiple times.
4502: */
4503: #define vm_map_copy_insert(map, where, copy) \
4504: MACRO_BEGIN \
4505: vm_map_t VMCI_map; \
4506: vm_map_entry_t VMCI_where; \
4507: vm_map_copy_t VMCI_copy; \
4508: VMCI_map = (map); \
4509: VMCI_where = (where); \
4510: VMCI_copy = (copy); \
4511: ((VMCI_where->vme_next)->vme_prev = vm_map_copy_last_entry(VMCI_copy))\
4512: ->vme_next = (VMCI_where->vme_next); \
4513: ((VMCI_where)->vme_next = vm_map_copy_first_entry(VMCI_copy)) \
4514: ->vme_prev = VMCI_where; \
4515: VMCI_map->hdr.nentries += VMCI_copy->cpy_hdr.nentries; \
4516: UPDATE_FIRST_FREE(VMCI_map, VMCI_map->first_free); \
4517: zfree(vm_map_copy_zone, (vm_offset_t) VMCI_copy); \
4518: MACRO_END
4519:
4520: /*
4521: * Routine: vm_map_copyout
4522: *
4523: * Description:
4524: * Copy out a copy chain ("copy") into newly-allocated
4525: * space in the destination map.
4526: *
4527: * If successful, consumes the copy object.
4528: * Otherwise, the caller is responsible for it.
4529: */
4530: kern_return_t
4531: vm_map_copyout(
4532: register vm_map_t dst_map,
4533: vm_offset_t *dst_addr, /* OUT */
4534: register vm_map_copy_t copy)
4535: {
4536: vm_size_t size;
4537: vm_size_t adjustment;
4538: vm_offset_t start;
4539: vm_offset_t vm_copy_start;
4540: vm_map_entry_t last;
4541: register
4542: vm_map_entry_t entry;
4543:
4544: /*
4545: * Check for null copy object.
4546: */
4547:
4548: if (copy == VM_MAP_COPY_NULL) {
4549: *dst_addr = 0;
4550: return(KERN_SUCCESS);
4551: }
4552:
4553: /*
4554: * Check for special copy object, created
4555: * by vm_map_copyin_object.
4556: */
4557:
4558: if (copy->type == VM_MAP_COPY_OBJECT) {
4559: vm_object_t object = copy->cpy_object;
4560: kern_return_t kr;
4561: vm_size_t offset;
4562:
4563: offset = trunc_page(copy->offset);
4564: size = round_page(copy->size + copy->offset - offset);
4565: *dst_addr = 0;
4566: kr = vm_map_enter(dst_map, dst_addr, size,
4567: (vm_offset_t) 0, TRUE,
4568: object, offset, FALSE,
4569: VM_PROT_DEFAULT, VM_PROT_ALL,
4570: VM_INHERIT_DEFAULT);
4571: if (kr != KERN_SUCCESS)
4572: return(kr);
4573: /* Account for non-pagealigned copy object */
4574: *dst_addr += copy->offset - offset;
4575: zfree(vm_map_copy_zone, (vm_offset_t) copy);
4576: return(KERN_SUCCESS);
4577: }
4578:
4579: /*
4580: * Check for special kernel buffer allocated
4581: * by new_ipc_kmsg_copyin.
4582: */
4583:
4584: if (copy->type == VM_MAP_COPY_KERNEL_BUFFER) {
4585: return(vm_map_copyout_kernel_buffer(dst_map, dst_addr,
4586: copy, FALSE));
4587: }
4588:
4589: if (copy->type == VM_MAP_COPY_PAGE_LIST)
4590: return(vm_map_copyout_page_list(dst_map, dst_addr, copy));
4591:
4592: /*
4593: * Find space for the data
4594: */
4595:
4596: vm_copy_start = trunc_page(copy->offset);
4597: size = round_page(copy->offset + copy->size) - vm_copy_start;
4598:
4599: StartAgain: ;
4600:
4601: vm_map_lock(dst_map);
4602: assert(first_free_is_valid(dst_map));
4603: start = ((last = dst_map->first_free) == vm_map_to_entry(dst_map)) ?
4604: vm_map_min(dst_map) : last->vme_end;
4605:
4606: while (TRUE) {
4607: vm_map_entry_t next = last->vme_next;
4608: vm_offset_t end = start + size;
4609:
4610: if ((end > dst_map->max_offset) || (end < start)) {
4611: if (dst_map->wait_for_space) {
4612: if (size <= (dst_map->max_offset - dst_map->min_offset)) {
4613: assert_wait((event_t) dst_map,
4614: THREAD_INTERRUPTIBLE);
4615: vm_map_unlock(dst_map);
4616: thread_block((void (*)(void))0);
4617: goto StartAgain;
4618: }
4619: }
4620: vm_map_unlock(dst_map);
4621: return(KERN_NO_SPACE);
4622: }
4623:
4624: if ((next == vm_map_to_entry(dst_map)) ||
4625: (next->vme_start >= end))
4626: break;
4627:
4628: last = next;
4629: start = last->vme_end;
4630: }
4631:
4632: /*
4633: * Since we're going to just drop the map
4634: * entries from the copy into the destination
4635: * map, they must come from the same pool.
4636: */
4637:
4638: if (copy->cpy_hdr.entries_pageable != dst_map->hdr.entries_pageable) {
4639: /*
4640: * Mismatches occur when dealing with the default
4641: * pager.
4642: */
4643: zone_t old_zone;
4644: vm_map_entry_t next, new;
4645:
4646: /*
4647: * Find the zone that the copies were allocated from
4648: */
4649: old_zone = (copy->cpy_hdr.entries_pageable)
4650: ? vm_map_entry_zone
4651: : vm_map_kentry_zone;
4652: entry = vm_map_copy_first_entry(copy);
4653:
4654: /*
4655: * Reinitialize the copy so that vm_map_copy_entry_link
4656: * will work.
4657: */
4658: copy->cpy_hdr.nentries = 0;
4659: copy->cpy_hdr.entries_pageable = dst_map->hdr.entries_pageable;
4660: vm_map_copy_first_entry(copy) =
4661: vm_map_copy_last_entry(copy) =
4662: vm_map_copy_to_entry(copy);
4663:
4664: /*
4665: * Copy each entry.
4666: */
4667: while (entry != vm_map_copy_to_entry(copy)) {
4668: new = vm_map_copy_entry_create(copy);
4669: vm_map_entry_copy_full(new, entry);
4670: vm_map_copy_entry_link(copy,
4671: vm_map_copy_last_entry(copy),
4672: new);
4673: next = entry->vme_next;
4674: zfree(old_zone, (vm_offset_t) entry);
4675: entry = next;
4676: }
4677: }
4678:
4679: /*
4680: * Adjust the addresses in the copy chain, and
4681: * reset the region attributes.
4682: */
4683:
4684: adjustment = start - vm_copy_start;
4685: for (entry = vm_map_copy_first_entry(copy);
4686: entry != vm_map_copy_to_entry(copy);
4687: entry = entry->vme_next) {
4688: entry->vme_start += adjustment;
4689: entry->vme_end += adjustment;
4690:
4691: entry->inheritance = VM_INHERIT_DEFAULT;
4692: entry->protection = VM_PROT_DEFAULT;
4693: entry->max_protection = VM_PROT_ALL;
4694: entry->behavior = VM_BEHAVIOR_DEFAULT;
4695:
4696: /*
4697: * If the entry is now wired,
4698: * map the pages into the destination map.
4699: */
4700: if (entry->wired_count != 0) {
4701: register vm_offset_t va;
4702: vm_offset_t offset;
4703: register vm_object_t object;
4704:
4705: object = entry->object.vm_object;
4706: offset = entry->offset;
4707: va = entry->vme_start;
4708:
4709: pmap_pageable(dst_map->pmap,
4710: entry->vme_start,
4711: entry->vme_end,
4712: TRUE);
4713:
4714: while (va < entry->vme_end) {
4715: register vm_page_t m;
4716:
4717: /*
4718: * Look up the page in the object.
4719: * Assert that the page will be found in the
4720: * top object:
4721: * either
4722: * the object was newly created by
4723: * vm_object_copy_slowly, and has
4724: * copies of all of the pages from
4725: * the source object
4726: * or
4727: * the object was moved from the old
4728: * map entry; because the old map
4729: * entry was wired, all of the pages
4730: * were in the top-level object.
4731: * (XXX not true if we wire pages for
4732: * reading)
4733: */
4734: vm_object_lock(object);
4735: vm_object_paging_begin(object);
4736:
4737: m = vm_page_lookup(object, offset);
4738: if (m == VM_PAGE_NULL || m->wire_count == 0 ||
4739: m->absent)
4740: panic("vm_map_copyout: wiring 0x%x", m);
4741:
4742: m->busy = TRUE;
4743: vm_object_unlock(object);
4744:
4745: PMAP_ENTER(dst_map->pmap, va, m,
4746: entry->protection, TRUE);
4747:
4748: vm_object_lock(object);
4749: PAGE_WAKEUP_DONE(m);
4750: /* the page is wired, so we don't have to activate */
4751: vm_object_paging_end(object);
4752: vm_object_unlock(object);
4753:
4754: offset += PAGE_SIZE;
4755: va += PAGE_SIZE;
4756: }
4757: }
4758: else if (size <= vm_map_aggressive_enter_max) {
4759:
4760: register vm_offset_t va;
4761: vm_offset_t offset;
4762: register vm_object_t object;
4763: vm_prot_t prot;
4764:
4765: object = entry->object.vm_object;
4766: if (object != VM_OBJECT_NULL) {
4767:
4768: offset = entry->offset;
4769: va = entry->vme_start;
4770: while (va < entry->vme_end) {
4771: register vm_page_t m;
4772:
4773: /*
4774: * Look up the page in the object.
4775: * Assert that the page will be found
4776: * in the top object if at all...
4777: */
4778: vm_object_lock(object);
4779: vm_object_paging_begin(object);
4780:
4781: if (((m = vm_page_lookup(object,
4782: offset))
4783: != VM_PAGE_NULL) &&
4784: !m->busy && !m->fictitious &&
4785: !m->absent && !m->error) {
4786: m->busy = TRUE;
4787: vm_object_unlock(object);
4788:
4789: /* honor cow obligations */
4790: prot = entry->protection;
4791: if (entry->needs_copy)
4792: prot &= ~VM_PROT_WRITE;
4793:
4794: PMAP_ENTER(dst_map->pmap, va,
4795: m, prot, FALSE);
4796:
4797: vm_object_lock(object);
4798: vm_page_lock_queues();
4799: if (!m->active && !m->inactive)
4800: vm_page_activate(m);
4801: vm_page_unlock_queues();
4802: PAGE_WAKEUP_DONE(m);
4803: }
4804: vm_object_paging_end(object);
4805: vm_object_unlock(object);
4806:
4807: offset += PAGE_SIZE;
4808: va += PAGE_SIZE;
4809: }
4810: }
4811: }
4812: }
4813:
4814: /*
4815: * Correct the page alignment for the result
4816: */
4817:
4818: *dst_addr = start + (copy->offset - vm_copy_start);
4819:
4820: /*
4821: * Update the hints and the map size
4822: */
4823:
4824: SAVE_HINT(dst_map, vm_map_copy_last_entry(copy));
4825:
4826: dst_map->size += size;
4827:
4828: /*
4829: * Link in the copy
4830: */
4831:
4832: vm_map_copy_insert(dst_map, last, copy);
4833:
4834: vm_map_unlock(dst_map);
4835:
4836: /*
4837: * XXX If wiring_required, call vm_map_pageable
4838: */
4839:
4840: return(KERN_SUCCESS);
4841: }
4842:
4843: boolean_t vm_map_aggressive_enter; /* not used yet */
4844:
4845: /*
4846: *
4847: * vm_map_copyout_page_list:
4848: *
4849: * Version of vm_map_copyout() for page list vm map copies.
4850: *
4851: */
4852: kern_return_t
4853: vm_map_copyout_page_list(
4854: register vm_map_t dst_map,
4855: vm_offset_t *dst_addr, /* OUT */
4856: register vm_map_copy_t copy)
4857: {
4858: vm_size_t size;
4859: vm_offset_t start;
4860: vm_offset_t end;
4861: vm_offset_t offset;
4862: vm_map_entry_t last;
4863: register
4864: vm_object_t object;
4865: vm_page_t *page_list, m;
4866: vm_map_entry_t entry;
4867: vm_offset_t old_last_offset;
4868: boolean_t cont_invoked, needs_wakeup;
4869: kern_return_t result = KERN_SUCCESS;
4870: vm_map_copy_t orig_copy;
4871: vm_offset_t dst_offset;
4872: boolean_t must_wire;
4873: boolean_t aggressive_enter;
4874:
4875: /*
4876: * Check for null copy object.
4877: */
4878:
4879: if (copy == VM_MAP_COPY_NULL) {
4880: *dst_addr = 0;
4881: return(KERN_SUCCESS);
4882: }
4883:
4884: assert(copy->type == VM_MAP_COPY_PAGE_LIST);
4885:
4886: /*
4887: * Make sure the pages are stolen, because we are
4888: * going to put them in a new object. Assume that
4889: * all pages are identical to first in this regard.
4890: */
4891:
4892: page_list = ©->cpy_page_list[0];
4893: if (!copy->cpy_page_loose)
4894: vm_map_copy_steal_pages(copy);
4895:
4896: /*
4897: * Find space for the data
4898: */
4899:
4900: size = round_page(copy->offset + copy->size) -
4901: trunc_page(copy->offset);
4902: StartAgain:
4903: vm_map_lock(dst_map);
4904: must_wire = dst_map->wiring_required;
4905:
4906: assert(first_free_is_valid(dst_map));
4907: last = dst_map->first_free;
4908: if (last == vm_map_to_entry(dst_map)) {
4909: start = vm_map_min(dst_map);
4910: } else {
4911: start = last->vme_end;
4912: }
4913:
4914: while (TRUE) {
4915: vm_map_entry_t next = last->vme_next;
4916: end = start + size;
4917:
4918: if ((end > dst_map->max_offset) || (end < start)) {
4919: if (dst_map->wait_for_space) {
4920: if (size <= (dst_map->max_offset -
4921: dst_map->min_offset)) {
4922: assert_wait((event_t) dst_map,
4923: THREAD_INTERRUPTIBLE);
4924: vm_map_unlock(dst_map);
4925: thread_block((void (*)(void))0);
4926: goto StartAgain;
4927: }
4928: }
4929: vm_map_unlock(dst_map);
4930: return(KERN_NO_SPACE);
4931: }
4932:
4933: if ((next == vm_map_to_entry(dst_map)) ||
4934: (next->vme_start >= end)) {
4935: break;
4936: }
4937:
4938: last = next;
4939: start = last->vme_end;
4940: }
4941:
4942: /*
4943: * See whether we can avoid creating a new entry (and object) by
4944: * extending one of our neighbors. [So far, we only attempt to
4945: * extend from below.]
4946: *
4947: * The code path below here is a bit twisted. If any of the
4948: * extension checks fails, we branch to create_object. If
4949: * it all works, we fall out the bottom and goto insert_pages.
4950: */
4951: if (last == vm_map_to_entry(dst_map) ||
4952: last->vme_end != start ||
4953: last->is_shared != FALSE ||
4954: last->is_sub_map != FALSE ||
4955: last->inheritance != VM_INHERIT_DEFAULT ||
4956: last->protection != VM_PROT_DEFAULT ||
4957: last->max_protection != VM_PROT_ALL ||
4958: last->behavior != VM_BEHAVIOR_DEFAULT ||
4959: last->in_transition ||
4960: (must_wire ? (last->wired_count != 1 ||
4961: last->user_wired_count != 0) :
4962: (last->wired_count != 0))) {
4963: goto create_object;
4964: }
4965:
4966: /*
4967: * If this entry needs an object, make one.
4968: */
4969: if (last->object.vm_object == VM_OBJECT_NULL) {
4970: object = vm_object_allocate(
4971: (vm_size_t)(last->vme_end - last->vme_start + size));
4972: last->object.vm_object = object;
4973: last->offset = 0;
4974: }
4975: else {
4976: vm_offset_t prev_offset = last->offset;
4977: vm_size_t prev_size = start - last->vme_start;
4978: vm_size_t new_size;
4979:
4980: /*
4981: * This is basically vm_object_coalesce.
4982: */
4983:
4984: object = last->object.vm_object;
4985: vm_object_lock(object);
4986:
4987: /*
4988: * Try to collapse the object first
4989: */
4990: vm_object_collapse(object);
4991:
4992: /*
4993: * Can't coalesce if pages not mapped to
4994: * last may be in use anyway:
4995: * . more than one reference
4996: * . paged out
4997: * . shadows another object
4998: * . has a copy elsewhere
4999: * . paging references (pages might be in page-list)
5000: */
5001:
5002: if ((object->ref_count > 1) ||
5003: object->pager_created ||
5004: (object->shadow != VM_OBJECT_NULL) ||
5005: (object->copy != VM_OBJECT_NULL) ||
5006: (object->paging_in_progress != 0)) {
5007: vm_object_unlock(object);
5008: goto create_object;
5009: }
5010:
5011: /*
5012: * Extend the object if necessary. Don't have to call
5013: * vm_object_page_remove because the pages aren't mapped,
5014: * and vm_page_replace will free up any old ones it encounters.
5015: */
5016: new_size = prev_offset + prev_size + size;
5017: if (new_size > object->size) {
5018: #if MACH_PAGEMAP
5019: /*
5020: * We cannot extend an object that has existence info,
5021: * since the existence info might then fail to cover
5022: * the entire object.
5023: *
5024: * This assertion must be true because the object
5025: * has no pager, and we only create existence info
5026: * for objects with pagers.
5027: */
5028: assert(object->existence_map == VM_EXTERNAL_NULL);
5029: #endif /* MACH_PAGEMAP */
5030: object->size = new_size;
5031: }
5032: vm_object_unlock(object);
5033: }
5034:
5035: /*
5036: * Coalesced the two objects - can extend
5037: * the previous map entry to include the
5038: * new range.
5039: */
5040: dst_map->size += size;
5041: last->vme_end = end;
5042: UPDATE_FIRST_FREE(dst_map, dst_map->first_free);
5043:
5044: SAVE_HINT(dst_map, last);
5045:
5046: goto insert_pages;
5047:
5048: create_object:
5049:
5050: /*
5051: * Create object
5052: */
5053: object = vm_object_allocate(size);
5054:
5055: /*
5056: * Create entry
5057: */
5058: last = vm_map_entry_insert(dst_map, last, start, start + size,
5059: object, 0, FALSE, FALSE, TRUE,
5060: VM_PROT_DEFAULT, VM_PROT_ALL,
5061: VM_BEHAVIOR_DEFAULT,
5062: VM_INHERIT_DEFAULT, (must_wire ? 1 : 0));
5063:
5064: /*
5065: * Transfer pages into new object.
5066: * Scan page list in vm_map_copy.
5067: */
5068: insert_pages:
5069: dst_offset = copy->offset & PAGE_MASK;
5070: cont_invoked = FALSE;
5071: orig_copy = copy;
5072: last->in_transition = TRUE;
5073: old_last_offset = last->offset
5074: + (start - last->vme_start);
5075:
5076: aggressive_enter = (size <= vm_map_aggressive_enter_max);
5077:
5078: for (offset = 0; offset < size; offset += PAGE_SIZE) {
5079: m = *page_list;
5080: assert(m && !m->tabled);
5081:
5082: /*
5083: * Must clear busy bit in page before inserting it.
5084: * Ok to skip wakeup logic because nobody else
5085: * can possibly know about this page. Also set
5086: * dirty bit on the assumption that the page is
5087: * not a page of zeros.
5088: */
5089:
5090: m->busy = FALSE;
5091: m->dirty = TRUE;
5092: vm_object_lock(object);
5093: vm_page_lock_queues();
5094: vm_page_replace(m, object, old_last_offset + offset);
5095: if (must_wire) {
5096: vm_page_wire(m);
5097: } else if (aggressive_enter) {
5098: vm_page_activate(m);
5099: }
5100: vm_page_unlock_queues();
5101: vm_object_unlock(object);
5102:
5103: if (aggressive_enter || must_wire) {
5104: PMAP_ENTER(dst_map->pmap,
5105: last->vme_start + m->offset - last->offset,
5106: m, last->protection, must_wire);
5107: }
5108:
5109: *page_list++ = VM_PAGE_NULL;
5110: assert(copy != VM_MAP_COPY_NULL);
5111: assert(copy->type == VM_MAP_COPY_PAGE_LIST);
5112: if (--(copy->cpy_npages) == 0 &&
5113: vm_map_copy_has_cont(copy)) {
5114: vm_map_copy_t new_copy;
5115:
5116: /*
5117: * Ok to unlock map because entry is
5118: * marked in_transition.
5119: */
5120: cont_invoked = TRUE;
5121: vm_map_unlock(dst_map);
5122: vm_map_copy_invoke_cont(copy, &new_copy, &result);
5123:
5124: if (result == KERN_SUCCESS) {
5125:
5126: /*
5127: * If we got back a copy with real pages,
5128: * steal them now. Either all of the
5129: * pages in the list are tabled or none
5130: * of them are; mixtures are not possible.
5131: *
5132: * Save original copy for consume on
5133: * success logic at end of routine.
5134: */
5135: if (copy != orig_copy)
5136: vm_map_copy_discard(copy);
5137:
5138: if ((copy = new_copy) != VM_MAP_COPY_NULL) {
5139: page_list = ©->cpy_page_list[0];
5140: if (!copy->cpy_page_loose)
5141: vm_map_copy_steal_pages(copy);
5142: }
5143: }
5144: else {
5145: /*
5146: * Continuation failed.
5147: */
5148: vm_map_lock(dst_map);
5149: goto error;
5150: }
5151:
5152: vm_map_lock(dst_map);
5153: }
5154: }
5155:
5156: *dst_addr = start + dst_offset;
5157:
5158: /*
5159: * Clear the in transition bits. This is easy if we
5160: * didn't have a continuation.
5161: */
5162: error:
5163: needs_wakeup = FALSE;
5164: if (!cont_invoked) {
5165: /*
5166: * We didn't unlock the map, so nobody could
5167: * be waiting.
5168: */
5169: last->in_transition = FALSE;
5170: assert(!last->needs_wakeup);
5171: }
5172: else {
5173: if (!vm_map_lookup_entry(dst_map, start, &entry))
5174: panic("vm_map_copyout_page_list: missing entry");
5175:
5176: /*
5177: * Clear transition bit for all constituent entries that
5178: * were in the original entry. Also check for waiters.
5179: */
5180: while ((entry != vm_map_to_entry(dst_map)) &&
5181: (entry->vme_start < end)) {
5182: assert(entry->in_transition);
5183: entry->in_transition = FALSE;
5184: if (entry->needs_wakeup) {
5185: entry->needs_wakeup = FALSE;
5186: needs_wakeup = TRUE;
5187: }
5188: entry = entry->vme_next;
5189: }
5190: }
5191:
5192: if (result != KERN_SUCCESS)
5193: (void) vm_map_delete(dst_map, start, end, VM_MAP_NO_FLAGS);
5194:
5195: vm_map_unlock(dst_map);
5196:
5197: if (needs_wakeup)
5198: vm_map_entry_wakeup(dst_map);
5199:
5200: /*
5201: * Consume on success logic.
5202: */
5203: if (copy != VM_MAP_COPY_NULL && copy != orig_copy) {
5204: zfree(vm_map_copy_zone, (vm_offset_t) copy);
5205: }
5206: if (result == KERN_SUCCESS) {
5207: assert(orig_copy != VM_MAP_COPY_NULL);
5208: assert(orig_copy->type == VM_MAP_COPY_PAGE_LIST);
5209: zfree(vm_map_copy_zone, (vm_offset_t) orig_copy);
5210: }
5211:
5212: return(result);
5213: }
5214:
5215: /*
5216: * Routine: vm_map_copyin
5217: *
5218: * Description:
5219: * Copy the specified region (src_addr, len) from the
5220: * source address space (src_map), possibly removing
5221: * the region from the source address space (src_destroy).
5222: *
5223: * Returns:
5224: * A vm_map_copy_t object (copy_result), suitable for
5225: * insertion into another address space (using vm_map_copyout),
5226: * copying over another address space region (using
5227: * vm_map_copy_overwrite). If the copy is unused, it
5228: * should be destroyed (using vm_map_copy_discard).
5229: *
5230: * In/out conditions:
5231: * The source map should not be locked on entry.
5232: */
5233: #if DIPC
5234: dstat_decl(unsigned int c_vmcc_volatile = 0;)
5235: dstat_decl(unsigned int c_vmcc_null_entry = 0;)
5236: dstat_decl(unsigned int c_vmcc_null_entry_continue = 0;)
5237: dstat_decl(unsigned int c_vmcc_src_destroy_opt = 0;)
5238: dstat_decl(unsigned int c_vmcc_wasnt_wired = 0;)
5239: dstat_decl(unsigned int c_vmcc_vocq = 0;)
5240: dstat_decl(unsigned int c_vmcc_vopp = 0;)
5241: dstat_decl(unsigned int c_vmcc_voept = 0;)
5242: dstat_decl(unsigned int c_vmcc_vocs = 0;)
5243: dstat_decl(unsigned int c_vmcc_vocstrat = 0;)
5244: dstat_decl(unsigned int c_vmcc_vmle = 0;)
5245: dstat_decl(unsigned int c_vmcc_reloop = 0;)
5246: dstat_decl(unsigned int c_vmcc_vmd = 0;)
5247: #endif /* DIPC */
5248:
5249:
5250: typedef struct submap_map {
5251: vm_map_t parent_map;
5252: vm_offset_t base_start;
5253: vm_offset_t base_end;
5254: struct submap_map *next;
5255: } submap_map_t;
5256:
5257: kern_return_t
5258: vm_map_copyin_common(
5259: vm_map_t src_map,
5260: vm_offset_t src_addr,
5261: vm_size_t len,
5262: boolean_t src_destroy,
5263: boolean_t src_volatile,
5264: vm_map_copy_t *copy_result, /* OUT */
5265: boolean_t use_maxprot)
5266: {
5267: vm_map_entry_t tmp_entry; /* Result of last map lookup --
5268: * in multi-level lookup, this
5269: * entry contains the actual
5270: * vm_object/offset.
5271: */
5272: register
5273: vm_map_entry_t new_entry = VM_MAP_ENTRY_NULL; /* Map entry for copy */
5274:
5275: vm_offset_t src_start; /* Start of current entry --
5276: * where copy is taking place now
5277: */
5278: vm_offset_t src_end; /* End of entire region to be
5279: * copied */
5280: vm_offset_t base_start; /* submap fields to save offsets */
5281: /* in original map */
5282: vm_offset_t base_end;
5283: vm_map_t base_map=src_map;
5284: vm_map_entry_t base_entry;
5285: boolean_t map_share=FALSE;
5286: submap_map_t *parent_maps = NULL;
5287:
5288: register
5289: vm_map_copy_t copy; /* Resulting copy */
5290:
5291: /*
5292: * Check for copies of zero bytes.
5293: */
5294:
5295: if (len == 0) {
5296: *copy_result = VM_MAP_COPY_NULL;
5297: return(KERN_SUCCESS);
5298: }
5299:
5300: /*
5301: * Compute start and end of region
5302: */
5303:
5304: src_start = trunc_page(src_addr);
5305: src_end = round_page(src_addr + len);
5306:
5307: #if DIPC
5308: XPR(XPR_VM_MAP,
5309: "vm_map_copyin_common map 0x%x addr 0x%x len 0x%x dest %d volatile %d\n",
5310: (natural_t)src_map, src_addr, len, src_destroy, src_volatile);
5311: #else /* DIPC */
5312: XPR(XPR_VM_MAP, "vm_map_copyin_common map 0x%x addr 0x%x len 0x%x dest %d\n",
5313: (natural_t)src_map, src_addr, len, src_destroy, 0);
5314: #endif /* DIPC */
5315:
5316: /*
5317: * Check that the end address doesn't overflow
5318: */
5319:
5320: if (src_end <= src_start)
5321: if ((src_end < src_start) || (src_start != 0))
5322: return(KERN_INVALID_ADDRESS);
5323:
5324: /*
5325: * Allocate a header element for the list.
5326: *
5327: * Use the start and end in the header to
5328: * remember the endpoints prior to rounding.
5329: */
5330:
5331: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
5332: vm_map_copy_first_entry(copy) =
5333: vm_map_copy_last_entry(copy) = vm_map_copy_to_entry(copy);
5334: copy->type = VM_MAP_COPY_ENTRY_LIST;
5335: copy->cpy_hdr.nentries = 0;
5336: copy->cpy_hdr.entries_pageable = TRUE;
5337:
5338: copy->offset = src_addr;
5339: copy->size = len;
5340:
5341: new_entry = vm_map_copy_entry_create(copy);
5342:
5343: #define RETURN(x) \
5344: MACRO_BEGIN \
5345: vm_map_unlock(src_map); \
5346: if (new_entry != VM_MAP_ENTRY_NULL) \
5347: vm_map_copy_entry_dispose(copy,new_entry); \
5348: vm_map_copy_discard(copy); \
5349: { \
5350: submap_map_t *ptr; \
5351: \
5352: for(ptr = parent_maps; ptr != NULL; ptr = parent_maps) { \
5353: parent_maps=parent_maps->next; \
5354: kfree((vm_offset_t)ptr, sizeof(submap_map_t)); \
5355: } \
5356: } \
5357: MACRO_RETURN(x); \
5358: MACRO_END
5359:
5360: /*
5361: * Find the beginning of the region.
5362: */
5363:
5364: vm_map_lock(src_map);
5365:
5366: if (!vm_map_lookup_entry(src_map, src_start, &tmp_entry))
5367: RETURN(KERN_INVALID_ADDRESS);
5368: vm_map_clip_start(src_map, tmp_entry, src_start);
5369:
5370: /*
5371: * Go through entries until we get to the end.
5372: */
5373:
5374: while (TRUE) {
5375: register
5376: vm_map_entry_t src_entry = tmp_entry; /* Top-level entry */
5377: vm_size_t src_size; /* Size of source
5378: * map entry (in both
5379: * maps)
5380: */
5381:
5382: register
5383: vm_object_t src_object; /* Object to copy */
5384: vm_offset_t src_offset;
5385:
5386: boolean_t src_needs_copy; /* Should source map
5387: * be made read-only
5388: * for copy-on-write?
5389: */
5390:
5391: boolean_t new_entry_needs_copy; /* Will new entry be COW? */
5392:
5393: boolean_t was_wired; /* Was source wired? */
5394: vm_map_version_t version; /* Version before locks
5395: * dropped to make copy
5396: */
5397: kern_return_t result; /* Return value from
5398: * copy_strategically.
5399: */
5400: while(tmp_entry->is_sub_map) {
5401: vm_size_t submap_len;
5402: submap_map_t *ptr;
5403:
5404: ptr = (submap_map_t *)kalloc(sizeof(submap_map_t));
5405: ptr->next = parent_maps;
5406: parent_maps = ptr;
5407: ptr->parent_map = src_map;
5408: ptr->base_start = src_start;
5409: ptr->base_end = src_end;
5410: submap_len = tmp_entry->vme_end - tmp_entry->vme_start;
5411: if(submap_len > (src_end-src_start))
5412: submap_len = src_end-src_start;
5413: ptr->base_start += submap_len;
5414:
5415: src_start -= tmp_entry->vme_start;
5416: src_start += tmp_entry->offset;
5417: src_end = src_start + submap_len;
5418: src_map = tmp_entry->object.sub_map;
5419: vm_map_lock(src_map);
5420: vm_map_unlock(ptr->parent_map);
5421: if (!vm_map_lookup_entry(
5422: src_map, src_start, &tmp_entry))
5423: RETURN(KERN_INVALID_ADDRESS);
5424: map_share = TRUE;
5425: vm_map_clip_start(src_map, tmp_entry, src_start);
5426: src_entry = tmp_entry;
5427: }
5428: /*
5429: * Create a new address map entry to hold the result.
5430: * Fill in the fields from the appropriate source entries.
5431: * We must unlock the source map to do this if we need
5432: * to allocate a map entry.
5433: */
5434: if (new_entry == VM_MAP_ENTRY_NULL) {
5435: version.main_timestamp = src_map->timestamp;
5436: vm_map_unlock(src_map);
5437:
5438: dstat(++c_vmcc_null_entry);
5439: new_entry = vm_map_copy_entry_create(copy);
5440:
5441: vm_map_lock(src_map);
5442: if ((version.main_timestamp + 1) != src_map->timestamp) {
5443: if (!vm_map_lookup_entry(src_map, src_start,
5444: &tmp_entry)) {
5445: RETURN(KERN_INVALID_ADDRESS);
5446: }
5447: vm_map_clip_start(src_map, tmp_entry, src_start);
5448: dstat(++c_vmcc_null_entry_continue);
5449: continue; /* restart w/ new tmp_entry */
5450: }
5451: }
5452:
5453: /*
5454: * Verify that the region can be read.
5455: */
5456: if (((src_entry->protection & VM_PROT_READ) == VM_PROT_NONE &&
5457: !use_maxprot) ||
5458: (src_entry->max_protection & VM_PROT_READ) == 0)
5459: RETURN(KERN_PROTECTION_FAILURE);
5460:
5461: /*
5462: * Clip against the endpoints of the entire region.
5463: */
5464:
5465: vm_map_clip_end(src_map, src_entry, src_end);
5466:
5467: src_size = src_entry->vme_end - src_start;
5468: src_object = src_entry->object.vm_object;
5469: src_offset = src_entry->offset;
5470: was_wired = (src_entry->wired_count != 0);
5471:
5472: vm_map_entry_copy(new_entry, src_entry);
5473:
5474: /*
5475: * Attempt non-blocking copy-on-write optimizations.
5476: */
5477:
5478: if (src_destroy &&
5479: (src_object == VM_OBJECT_NULL ||
5480: (src_object->internal && !src_object->true_share
5481: && !map_share))) {
5482: /*
5483: * If we are destroying the source, and the object
5484: * is internal, we can move the object reference
5485: * from the source to the copy. The copy is
5486: * copy-on-write only if the source is.
5487: * We make another reference to the object, because
5488: * destroying the source entry will deallocate it.
5489: */
5490: vm_object_reference(src_object);
5491:
5492: /*
5493: * Copy is always unwired. vm_map_copy_entry
5494: * set its wired count to zero.
5495: */
5496:
5497: dstat(++c_vmcc_src_destroy_opt);
5498: goto CopySuccessful;
5499: }
5500:
5501: #if DIPC
5502: /*
5503: * If the caller promises not to modify the data,
5504: * we don't have to apply copy-on-write processing
5505: * to it. This works best in the distributed case.
5506: * In the local case, we can wind up with fully
5507: * shared data between sender and receiver -- a
5508: * behavior that we aren't entirely sure we want
5509: * at this point. So for now, we'll only do this
5510: * on remote data transfers.
5511: */
5512: if (src_volatile == TRUE) {
5513: XPR(XPR_VM_MAP,
5514: "vmcc src_obj 0x%x ent 0x%x obj 0x%x VOLATILE\n",
5515: src_object, new_entry, new_entry->object.vm_object,
5516: 0, 0);
5517: assert(src_destroy == FALSE);
5518: dstat(++c_vmcc_volatile);
5519: vm_object_reference(src_object);
5520: goto CopySuccessful;
5521: }
5522: #endif /* DIPC */
5523:
5524: RestartCopy:
5525: XPR(XPR_VM_MAP, "vm_map_copyin_common src_obj 0x%x ent 0x%x obj 0x%x was_wired %d\n",
5526: src_object, new_entry, new_entry->object.vm_object,
5527: was_wired, 0);
5528: dstat(!was_wired ? ++c_vmcc_wasnt_wired : 0);
5529: if (!was_wired &&
5530: vm_object_copy_quickly(
5531: &new_entry->object.vm_object,
5532: src_offset,
5533: src_size,
5534: &src_needs_copy,
5535: &new_entry_needs_copy)) {
5536:
5537: dstat(++c_vmcc_vocq);
5538: new_entry->needs_copy = new_entry_needs_copy;
5539:
5540: /*
5541: * Handle copy-on-write obligations
5542: */
5543:
5544: if (src_needs_copy && !tmp_entry->needs_copy) {
5545: if (tmp_entry->is_shared ||
5546: tmp_entry->object.vm_object->true_share ||
5547: map_share) {
5548: /* dec ref gained in copy_quickly */
5549: vm_object_lock(src_object);
5550: src_object->ref_count--;
5551: vm_object_res_deallocate(src_object);
5552: vm_object_unlock(src_object);
5553: new_entry->object.vm_object =
5554: vm_object_copy_delayed(
5555: src_object,
5556: src_offset,
5557: src_size);
5558: } else {
5559: dstat(++c_vmcc_vopp);
5560: vm_object_pmap_protect(
5561: src_object,
5562: src_offset,
5563: src_size,
5564: (src_entry->is_shared ?
5565: PMAP_NULL
5566: : src_map->pmap),
5567: src_entry->vme_start,
5568: src_entry->protection &
5569: ~VM_PROT_WRITE);
5570:
5571: tmp_entry->needs_copy = TRUE;
5572: }
5573: }
5574:
5575: /*
5576: * The map has never been unlocked, so it's safe
5577: * to move to the next entry rather than doing
5578: * another lookup.
5579: */
5580:
5581: goto CopySuccessful;
5582: }
5583:
5584: new_entry->needs_copy = FALSE;
5585:
5586: /*
5587: * Take an object reference, so that we may
5588: * release the map lock(s).
5589: */
5590:
5591: assert(src_object != VM_OBJECT_NULL);
5592: vm_object_reference(src_object);
5593:
5594: /*
5595: * Record the timestamp for later verification.
5596: * Unlock the map.
5597: */
5598:
5599: version.main_timestamp = src_map->timestamp;
5600: vm_map_unlock(src_map);
5601:
5602: /*
5603: * Perform the copy
5604: */
5605:
5606: if (was_wired) {
5607: dstat(++c_vmcc_vocs);
5608: vm_object_lock(src_object);
5609: result = vm_object_copy_slowly(
5610: src_object,
5611: src_offset,
5612: src_size,
5613: THREAD_UNINT,
5614: &new_entry->object.vm_object);
5615: new_entry->offset = 0;
5616: new_entry->needs_copy = FALSE;
5617: } else {
5618: dstat(++c_vmcc_vocstrat);
5619: result = vm_object_copy_strategically(src_object,
5620: src_offset,
5621: src_size,
5622: &new_entry->object.vm_object,
5623: &new_entry->offset,
5624: &new_entry_needs_copy);
5625:
5626: new_entry->needs_copy = new_entry_needs_copy;
5627:
5628: }
5629:
5630: if (result != KERN_SUCCESS &&
5631: result != KERN_MEMORY_RESTART_COPY) {
5632: vm_map_lock(src_map);
5633: RETURN(result);
5634: }
5635:
5636: /*
5637: * Throw away the extra reference
5638: */
5639:
5640: vm_object_deallocate(src_object);
5641:
5642: /*
5643: * Verify that the map has not substantially
5644: * changed while the copy was being made.
5645: */
5646:
5647: vm_map_lock(src_map); /* Increments timestamp once! */
5648:
5649: if ((version.main_timestamp + 1) == src_map->timestamp)
5650: goto VerificationSuccessful;
5651:
5652: /*
5653: * Simple version comparison failed.
5654: *
5655: * Retry the lookup and verify that the
5656: * same object/offset are still present.
5657: *
5658: * [Note: a memory manager that colludes with
5659: * the calling task can detect that we have
5660: * cheated. While the map was unlocked, the
5661: * mapping could have been changed and restored.]
5662: */
5663:
5664: dstat(++c_vmcc_vmle);
5665: if (!vm_map_lookup_entry(src_map, src_start, &tmp_entry)) {
5666: RETURN(KERN_INVALID_ADDRESS);
5667: }
5668:
5669: src_entry = tmp_entry;
5670: vm_map_clip_start(src_map, src_entry, src_start);
5671:
5672: if ((src_entry->protection & VM_PROT_READ == VM_PROT_NONE &&
5673: !use_maxprot) ||
5674: src_entry->max_protection & VM_PROT_READ == 0)
5675: goto VerificationFailed;
5676:
5677: if (src_entry->vme_end < new_entry->vme_end)
5678: src_size = (new_entry->vme_end = src_entry->vme_end) - src_start;
5679:
5680: if ((src_entry->object.vm_object != src_object) ||
5681: (src_entry->offset != src_offset) ) {
5682:
5683: /*
5684: * Verification failed.
5685: *
5686: * Start over with this top-level entry.
5687: */
5688:
5689: VerificationFailed: ;
5690:
5691: vm_object_deallocate(new_entry->object.vm_object);
5692: tmp_entry = src_entry;
5693: continue;
5694: }
5695:
5696: /*
5697: * Verification succeeded.
5698: */
5699:
5700: VerificationSuccessful: ;
5701:
5702: if (result == KERN_MEMORY_RESTART_COPY)
5703: goto RestartCopy;
5704:
5705: /*
5706: * Copy succeeded.
5707: */
5708:
5709: CopySuccessful: ;
5710:
5711: /*
5712: * Link in the new copy entry.
5713: */
5714:
5715: vm_map_copy_entry_link(copy, vm_map_copy_last_entry(copy),
5716: new_entry);
5717:
5718: /*
5719: * Determine whether the entire region
5720: * has been copied.
5721: */
5722: src_start = new_entry->vme_end;
5723: new_entry = VM_MAP_ENTRY_NULL;
5724: while ((src_start >= src_end) && (src_end != 0)) {
5725: if (src_map != base_map) {
5726: submap_map_t *ptr;
5727:
5728: ptr = parent_maps;
5729: assert(ptr != NULL);
5730: parent_maps = parent_maps->next;
5731: vm_map_lock(ptr->parent_map);
5732: vm_map_unlock(src_map);
5733: src_map = ptr->parent_map;
5734: src_start = ptr->base_start;
5735: src_end = ptr->base_end;
5736: if ((src_end > src_start) &&
5737: !vm_map_lookup_entry(
5738: src_map, src_start, &tmp_entry))
5739: RETURN(KERN_INVALID_ADDRESS);
5740: kfree((vm_offset_t)ptr, sizeof(submap_map_t));
5741: if(parent_maps == NULL)
5742: map_share = FALSE;
5743: src_entry = tmp_entry->vme_prev;
5744: } else
5745: break;
5746: }
5747: if ((src_start >= src_end) && (src_end != 0))
5748: break;
5749:
5750: /*
5751: * Verify that there are no gaps in the region
5752: */
5753:
5754: tmp_entry = src_entry->vme_next;
5755: dstat(++c_vmcc_reloop);
5756: if (tmp_entry->vme_start != src_start)
5757: RETURN(KERN_INVALID_ADDRESS);
5758: }
5759:
5760: /*
5761: * If the source should be destroyed, do it now, since the
5762: * copy was successful.
5763: */
5764: if (src_destroy) {
5765: dstat(++c_vmcc_vmd);
5766: (void) vm_map_delete(src_map,
5767: trunc_page(src_addr),
5768: src_end,
5769: (src_map == kernel_map) ?
5770: VM_MAP_REMOVE_KUNWIRE :
5771: VM_MAP_NO_FLAGS);
5772: }
5773:
5774: vm_map_unlock(src_map);
5775:
5776: *copy_result = copy;
5777: return(KERN_SUCCESS);
5778:
5779: #undef RETURN
5780: }
5781:
5782: /*
5783: * vm_map_copyin_object:
5784: *
5785: * Create a copy object from an object.
5786: * Our caller donates an object reference.
5787: */
5788:
5789: kern_return_t
5790: vm_map_copyin_object(
5791: vm_object_t object,
5792: vm_offset_t offset, /* offset of region in object */
5793: vm_size_t size, /* size of region in object */
5794: vm_map_copy_t *copy_result) /* OUT */
5795: {
5796: vm_map_copy_t copy; /* Resulting copy */
5797:
5798: /*
5799: * We drop the object into a special copy object
5800: * that contains the object directly.
5801: */
5802:
5803: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
5804: copy->type = VM_MAP_COPY_OBJECT;
5805: copy->cpy_object = object;
5806: copy->cpy_index = 0;
5807: copy->offset = offset;
5808: copy->size = size;
5809:
5810: *copy_result = copy;
5811: return(KERN_SUCCESS);
5812: }
5813:
5814: /*
5815: * vm_map_copyin_page_list_cont:
5816: *
5817: * Continuation routine for vm_map_copyin_page_list.
5818: *
5819: * If vm_map_copyin_page_list can't fit the entire vm range
5820: * into a single page list object, it creates a continuation.
5821: * When the target of the operation has used the pages in the
5822: * initial page list, it invokes the continuation, which calls
5823: * this routine. If an error happens, the continuation is aborted
5824: * (abort arg to this routine is TRUE). To avoid deadlocks, the
5825: * pages are discarded from the initial page list before invoking
5826: * the continuation.
5827: *
5828: * NOTE: This is not the same sort of continuation used by
5829: * the scheduler.
5830: */
5831:
5832: kern_return_t
5833: vm_map_copyin_page_list_cont(
5834: vm_map_copyin_args_t cont_args,
5835: vm_map_copy_t *copy_result) /* OUT */
5836: {
5837: kern_return_t result = KERN_SUCCESS;
5838: register boolean_t abort, src_destroy, src_destroy_only;
5839:
5840: /*
5841: * Check for cases that only require memory destruction.
5842: */
5843: abort = (copy_result == (vm_map_copy_t *) 0);
5844: src_destroy = (cont_args->destroy_len != (vm_size_t) 0);
5845: src_destroy_only = (cont_args->src_len == (vm_size_t) 0);
5846:
5847: if (abort || src_destroy_only) {
5848: if (src_destroy)
5849: result = vm_map_remove(cont_args->map,
5850: cont_args->destroy_addr,
5851: cont_args->destroy_addr + cont_args->destroy_len,
5852: VM_MAP_NO_FLAGS);
5853: if (!abort)
5854: *copy_result = VM_MAP_COPY_NULL;
5855: }
5856: else {
5857: result = vm_map_copyin_page_list(cont_args->map,
5858: cont_args->src_addr, cont_args->src_len,
5859: cont_args->options, copy_result, TRUE);
5860:
5861: if (src_destroy &&
5862: (cont_args->options & VM_MAP_COPYIN_OPT_STEAL_PAGES) &&
5863: vm_map_copy_has_cont(*copy_result)) {
5864: vm_map_copyin_args_t new_args;
5865: /*
5866: * Transfer old destroy info.
5867: */
5868: new_args = (vm_map_copyin_args_t)
5869: (*copy_result)->cpy_cont_args;
5870: new_args->destroy_addr = cont_args->destroy_addr;
5871: new_args->destroy_len = cont_args->destroy_len;
5872: }
5873: }
5874:
5875: vm_map_deallocate(cont_args->map);
5876: kfree((vm_offset_t)cont_args, sizeof(vm_map_copyin_args_data_t));
5877:
5878: return(result);
5879: }
5880:
5881: /*
5882: * vm_map_copyin_page_list:
5883: *
5884: * This is a variant of vm_map_copyin that copies in a list of pages.
5885: * If steal_pages is TRUE, the pages are only in the returned list.
5886: * If steal_pages is FALSE, the pages are busy and still in their
5887: * objects. A continuation may be returned if not all the pages fit:
5888: * the recipient of this copy_result must be prepared to deal with it.
5889: */
5890:
5891: kern_return_t
5892: vm_map_copyin_page_list(
5893: vm_map_t src_map,
5894: vm_offset_t src_addr,
5895: vm_size_t len,
5896: int options,
5897: vm_map_copy_t *copy_result, /* OUT */
5898: boolean_t is_cont)
5899: {
5900: vm_map_entry_t src_entry;
5901: vm_page_t m;
5902: vm_offset_t src_start;
5903: vm_offset_t src_end;
5904: vm_size_t src_size;
5905: register vm_object_t src_object;
5906: register vm_offset_t src_offset;
5907: vm_offset_t src_last_offset;
5908: register vm_map_copy_t copy; /* Resulting copy */
5909: kern_return_t result = KERN_SUCCESS;
5910: boolean_t need_map_lookup;
5911: vm_map_copyin_args_t cont_args;
5912: kern_return_t error_code;
5913: vm_prot_t prot;
5914: boolean_t wired;
5915: boolean_t no_zero_fill;
5916:
5917: submap_map_t *parent_maps = NULL;
5918: vm_map_t base_map = src_map;
5919:
5920: prot = (options & VM_MAP_COPYIN_OPT_VM_PROT);
5921: no_zero_fill = (options & VM_MAP_COPYIN_OPT_NO_ZERO_FILL);
5922:
5923: /*
5924: * If steal_pages is FALSE, this leaves busy pages in
5925: * the object. A continuation must be used if src_destroy
5926: * is true in this case (!steal_pages && src_destroy).
5927: *
5928: * XXX Still have a more general problem of what happens
5929: * XXX if the same page occurs twice in a list. Deadlock
5930: * XXX can happen if vm_fault_page was called. A
5931: * XXX possible solution is to use a continuation if vm_fault_page
5932: * XXX is called and we cross a map entry boundary.
5933: */
5934:
5935: /*
5936: * Check for copies of zero bytes.
5937: */
5938:
5939: if (len == 0) {
5940: *copy_result = VM_MAP_COPY_NULL;
5941: return(KERN_SUCCESS);
5942: }
5943:
5944: /*
5945: * Compute start and end of region
5946: */
5947:
5948: src_start = trunc_page(src_addr);
5949: src_end = round_page(src_addr + len);
5950:
5951: /*
5952: * If the region is not page aligned, override the no_zero_fill
5953: * argument.
5954: */
5955:
5956: if (options & VM_MAP_COPYIN_OPT_NO_ZERO_FILL) {
5957: if (!page_aligned(src_addr) || !page_aligned(src_addr +len))
5958: options &= ~VM_MAP_COPYIN_OPT_NO_ZERO_FILL;
5959: }
5960:
5961: /*
5962: * Check that the end address doesn't overflow
5963: */
5964:
5965: if (src_end <= src_start && (src_end < src_start || src_start != 0)) {
5966: return KERN_INVALID_ADDRESS;
5967: }
5968:
5969: /*
5970: * Allocate a header element for the page list.
5971: *
5972: * Record original offset and size, as caller may not
5973: * be page-aligned.
5974: */
5975:
5976: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
5977: copy->type = VM_MAP_COPY_PAGE_LIST;
5978: copy->cpy_npages = 0;
5979: copy->cpy_page_loose = FALSE;
5980: copy->offset = src_addr;
5981: copy->size = len;
5982: copy->cpy_cont = VM_MAP_COPY_CONT_NULL;
5983: copy->cpy_cont_args = VM_MAP_COPYIN_ARGS_NULL;
5984:
5985: /*
5986: * Find the beginning of the region.
5987: */
5988:
5989: do_map_lookup:
5990:
5991: vm_map_lock(src_map);
5992:
5993: if (!vm_map_lookup_entry(src_map, src_start, &src_entry)) {
5994: result = KERN_INVALID_ADDRESS;
5995: goto error;
5996: }
5997: need_map_lookup = FALSE;
5998:
5999: /*
6000: * Go through entries until we get to the end.
6001: */
6002:
6003: while (TRUE) {
6004: if ((src_entry->protection & prot) != prot) {
6005: result = KERN_PROTECTION_FAILURE;
6006: goto error;
6007: }
6008:
6009: /* translate down through submaps to find the target entry */
6010: while(src_entry->is_sub_map) {
6011: vm_size_t submap_len;
6012: submap_map_t *ptr;
6013:
6014: ptr = (submap_map_t *)kalloc(sizeof(submap_map_t));
6015: ptr->next = parent_maps;
6016: parent_maps = ptr;
6017: ptr->parent_map = src_map;
6018: ptr->base_start = src_start;
6019: ptr->base_end = src_end;
6020: submap_len = src_entry->vme_end - src_entry->vme_start;
6021: if(submap_len > (src_end-src_start))
6022: submap_len = src_end-src_start;
6023: ptr->base_start += submap_len;
6024:
6025: src_start -= src_entry->vme_start;
6026: src_start += src_entry->offset;
6027: src_end = src_start + submap_len;
6028: src_map = src_entry->object.sub_map;
6029: vm_map_lock(src_map);
6030: vm_map_unlock(ptr->parent_map);
6031: if (!vm_map_lookup_entry(
6032: src_map, src_start, &src_entry)) {
6033: result = KERN_INVALID_ADDRESS;
6034: goto error;
6035: }
6036: vm_map_clip_start(src_map, src_entry, src_start);
6037: }
6038:
6039: wired = (src_entry->wired_count != 0);
6040:
6041: if (src_end > src_entry->vme_end)
6042: src_size = src_entry->vme_end - src_start;
6043: else
6044: src_size = src_end - src_start;
6045:
6046: src_object = src_entry->object.vm_object;
6047:
6048: /*
6049: * If src_object is NULL, allocate it now;
6050: * we're going to fault on it shortly.
6051: */
6052: if (src_object == VM_OBJECT_NULL) {
6053: src_object = vm_object_allocate((vm_size_t)
6054: src_entry->vme_end -
6055: src_entry->vme_start);
6056: src_entry->object.vm_object = src_object;
6057: }
6058: else if (src_entry->needs_copy && (prot & VM_PROT_WRITE)) {
6059: vm_object_shadow(
6060: &src_entry->object.vm_object,
6061: &src_entry->offset,
6062: (vm_size_t) (src_entry->vme_end -
6063: src_entry->vme_start));
6064:
6065: src_entry->needs_copy = FALSE;
6066:
6067: /* reset src_object */
6068: src_object = src_entry->object.vm_object;
6069: }
6070:
6071: /*
6072: * calculate src_offset now, since vm_object_shadow
6073: * may have changed src_entry->offset.
6074: */
6075: src_offset = src_entry->offset + (src_start - src_entry->vme_start);
6076:
6077: /*
6078: * Iterate over pages. Fault in ones that aren't present.
6079: */
6080: src_last_offset = src_offset + src_size;
6081: for (; (src_offset < src_last_offset);
6082: src_offset += PAGE_SIZE, src_start += PAGE_SIZE) {
6083:
6084: if (copy->cpy_npages == VM_MAP_COPY_PAGE_LIST_MAX) {
6085: vm_offset_t src_delta;
6086: make_continuation:
6087: /*
6088: * At this point we have the max number of
6089: * pages busy for this thread that we're
6090: * willing to allow. Stop here and record
6091: * arguments for the remainder. Note:
6092: * this means that this routine isn't atomic,
6093: * but that's the breaks. Note that only
6094: * the first vm_map_copy_t that comes back
6095: * from this routine has the right offset
6096: * and size; those from continuations are
6097: * page rounded, and short by the amount
6098: * already done.
6099: *
6100: * Reset src_end so the src_destroy
6101: * code at the bottom doesn't do
6102: * something stupid.
6103: */
6104:
6105: src_delta = src_end - src_start;
6106: while (src_map != base_map) {
6107: submap_map_t *ptr;
6108:
6109: if(!need_map_lookup) {
6110: vm_map_unlock(src_map);
6111: }
6112: ptr = parent_maps;
6113: assert(ptr != NULL);
6114: parent_maps = parent_maps->next;
6115: src_map = ptr->parent_map;
6116: src_start = ptr->base_start - src_delta;
6117: src_delta = ptr->base_end - src_start;
6118: kfree((vm_offset_t)ptr, sizeof(submap_map_t));
6119:
6120: need_map_lookup = TRUE;
6121: }
6122: src_end = src_start;
6123:
6124:
6125: cont_args = (vm_map_copyin_args_t)
6126: kalloc(sizeof(vm_map_copyin_args_data_t));
6127: cont_args->map = src_map;
6128: vm_map_reference(src_map);
6129: cont_args->src_addr = src_start;
6130: cont_args->src_len = len - (src_start - src_addr);
6131: if (options & VM_MAP_COPYIN_OPT_SRC_DESTROY) {
6132: cont_args->destroy_addr = cont_args->src_addr;
6133: cont_args->destroy_len = cont_args->src_len;
6134: } else {
6135: cont_args->destroy_addr = (vm_offset_t) 0;
6136: cont_args->destroy_len = (vm_offset_t) 0;
6137: }
6138: cont_args->options = options;
6139:
6140: copy->cpy_cont_args = cont_args;
6141: copy->cpy_cont = vm_map_copyin_page_list_cont;
6142:
6143: break;
6144: }
6145:
6146: /*
6147: * Try to find the page of data. Have to
6148: * fault it in if there's no page, or something
6149: * going on with the page, or the object has
6150: * a copy object.
6151: */
6152: vm_object_lock(src_object);
6153: vm_object_paging_begin(src_object);
6154: if (((m = vm_page_lookup(src_object, src_offset)) !=
6155: VM_PAGE_NULL) &&
6156: !m->busy && !m->fictitious && !m->unusual &&
6157: ((prot & VM_PROT_WRITE) == 0 ||
6158: (m->object->copy == VM_OBJECT_NULL))) {
6159:
6160: if (!m->absent &&
6161: !(options & VM_MAP_COPYIN_OPT_STEAL_PAGES)) {
6162:
6163: /*
6164: * The page is present and will not be
6165: * replaced, prep it. Thus allowing
6166: * mutiple access on this page
6167: */
6168: kern_return_t kr;
6169:
6170: kr = vm_page_prep(m);
6171: assert(kr == KERN_SUCCESS);
6172: kr = vm_page_pin(m);
6173: assert(kr == KERN_SUCCESS);
6174: } else {
6175: /*
6176: * This is the page. Mark it busy
6177: * and keep the paging reference on
6178: * the object whilst we do our thing.
6179: */
6180:
6181: m->busy = TRUE;
6182: }
6183: } else {
6184: vm_prot_t result_prot;
6185: vm_page_t top_page;
6186: kern_return_t kr;
6187: boolean_t data_supply;
6188:
6189: /*
6190: * Have to fault the page in; must
6191: * unlock the map to do so. While
6192: * the map is unlocked, anything
6193: * can happen, we must lookup the
6194: * map entry before continuing.
6195: */
6196: vm_map_unlock(src_map);
6197: need_map_lookup = TRUE;
6198: data_supply = src_object->silent_overwrite &&
6199: (prot & VM_PROT_WRITE) &&
6200: src_start >= src_addr &&
6201: src_start + PAGE_SIZE <=
6202: src_addr + len;
6203:
6204: retry:
6205: result_prot = prot;
6206:
6207: XPR(XPR_VM_FAULT,
6208: "vm_map_copyin_page_list -> vm_fault_page\n",
6209: 0,0,0,0,0);
6210: kr = vm_fault_page(src_object, src_offset,
6211: prot, FALSE, THREAD_UNINT,
6212: src_entry->offset,
6213: src_entry->offset +
6214: (src_entry->vme_end -
6215: src_entry->vme_start),
6216: VM_BEHAVIOR_SEQUENTIAL,
6217: &result_prot, &m, &top_page,
6218: (int *)0,
6219: &error_code,
6220: options & VM_MAP_COPYIN_OPT_NO_ZERO_FILL,
6221: data_supply);
6222: /*
6223: * Cope with what happened.
6224: */
6225: switch (kr) {
6226: case VM_FAULT_SUCCESS:
6227:
6228: /*
6229: * If we lost write access,
6230: * try again.
6231: */
6232: if ((prot & VM_PROT_WRITE) &&
6233: !(result_prot & VM_PROT_WRITE)) {
6234: vm_object_lock(src_object);
6235: vm_object_paging_begin(src_object);
6236: goto retry;
6237: }
6238: break;
6239: case VM_FAULT_INTERRUPTED: /* ??? */
6240: case VM_FAULT_RETRY:
6241: vm_object_lock(src_object);
6242: vm_object_paging_begin(src_object);
6243: goto retry;
6244: case VM_FAULT_MEMORY_SHORTAGE:
6245: VM_PAGE_WAIT();
6246: vm_object_lock(src_object);
6247: vm_object_paging_begin(src_object);
6248: goto retry;
6249: case VM_FAULT_FICTITIOUS_SHORTAGE:
6250: vm_page_more_fictitious();
6251: vm_object_lock(src_object);
6252: vm_object_paging_begin(src_object);
6253: goto retry;
6254: case VM_FAULT_MEMORY_ERROR:
6255: /*
6256: * Something broke. If this
6257: * is a continuation, return
6258: * a partial result if possible,
6259: * else fail the whole thing.
6260: * In the continuation case, the
6261: * next continuation call will
6262: * get this error if it persists.
6263: */
6264: vm_map_lock(src_map);
6265: if (is_cont &&
6266: copy->cpy_npages != 0)
6267: goto make_continuation;
6268:
6269: result = error_code ? error_code : KERN_MEMORY_ERROR;
6270: goto error;
6271: }
6272:
6273: if (top_page != VM_PAGE_NULL) {
6274: vm_object_lock(src_object);
6275: VM_PAGE_FREE(top_page);
6276: vm_object_paging_end(src_object);
6277: vm_object_unlock(src_object);
6278: }
6279:
6280: }
6281:
6282: /*
6283: * The page is busy, its object is locked, and
6284: * we have a paging reference on it. Either
6285: * the map is locked, or need_map_lookup is
6286: * TRUE.
6287: */
6288:
6289: /*
6290: * Put the page in the page list.
6291: */
6292: copy->cpy_page_list[copy->cpy_npages++] = m;
6293: vm_object_unlock(m->object);
6294:
6295: /*
6296: * Pmap enter support. Only used for
6297: * device I/O for colocated server.
6298: *
6299: * WARNING: This code assumes that this
6300: * option is only used for well behaved
6301: * memory. If the mapping has changed,
6302: * the following code will make mistakes.
6303: *
6304: * XXXO probably ought to do pmap_extract first,
6305: * XXXO to avoid needless pmap_enter, but this
6306: * XXXO can't detect protection mismatch??
6307: */
6308:
6309: if (options & VM_MAP_COPYIN_OPT_PMAP_ENTER) {
6310: /*
6311: * XXX Only used on kernel map.
6312: * XXX Must not remove VM_PROT_WRITE on
6313: * XXX an I/O only requiring VM_PROT_READ
6314: * XXX as another I/O may be active on same page
6315: * XXX assume that if mapping exists, it must
6316: * XXX have the equivalent of at least VM_PROT_READ,
6317: * XXX but don't assume it has VM_PROT_WRITE as the
6318: * XXX pmap might not all the rights of the object
6319: */
6320: assert(vm_map_pmap(src_map) == kernel_pmap);
6321:
6322: if ((prot & VM_PROT_WRITE) ||
6323: (pmap_extract(vm_map_pmap(src_map),
6324: src_start) != m->phys_addr))
6325:
6326: PMAP_ENTER(vm_map_pmap(src_map), src_start,
6327: m, prot, wired);
6328: }
6329: if(need_map_lookup) {
6330: need_map_lookup = FALSE;
6331: vm_map_lock(src_map);
6332: if (!vm_map_lookup_entry(src_map, src_start, &src_entry)) {
6333: result = KERN_INVALID_ADDRESS;
6334: goto error;
6335: }
6336: }
6337: }
6338:
6339: /*
6340: * Verify that there are no gaps in the region
6341: */
6342: src_start = src_entry->vme_end;
6343: if (src_start < src_end) {
6344: src_entry = src_entry->vme_next;
6345: if (need_map_lookup) {
6346: need_map_lookup = FALSE;
6347: vm_map_lock(src_map);
6348: if(!vm_map_lookup_entry(src_map,
6349: src_start, &src_entry)) {
6350: result = KERN_INVALID_ADDRESS;
6351: goto error;
6352: }
6353: } else if (src_entry->vme_start != src_start) {
6354: result = KERN_INVALID_ADDRESS;
6355: goto error;
6356: }
6357: }
6358:
6359: /*
6360: * DETERMINE whether the entire region
6361: * has been copied.
6362: */
6363:
6364: while ((src_start >= src_end) && (src_end != 0)) {
6365: if (src_map != base_map) {
6366: submap_map_t *ptr;
6367:
6368: ptr = parent_maps;
6369: assert(ptr != NULL);
6370: parent_maps = parent_maps->next;
6371: src_start = ptr->base_start;
6372: src_end = ptr->base_end;
6373: if(need_map_lookup) {
6374: need_map_lookup = FALSE;
6375: }
6376: else {
6377: vm_map_unlock(src_map);
6378: }
6379: src_map = ptr->parent_map;
6380: vm_map_lock(src_map);
6381: if((src_start < src_end) &&
6382: (!vm_map_lookup_entry(ptr->parent_map,
6383: src_start, &src_entry))) {
6384: result = KERN_INVALID_ADDRESS;
6385: kfree((vm_offset_t)ptr, sizeof(submap_map_t));
6386: goto error;
6387: }
6388: kfree((vm_offset_t)ptr, sizeof(submap_map_t));
6389: } else
6390: break;
6391: }
6392: if ((src_start >= src_end) && (src_end != 0)) {
6393: if (need_map_lookup)
6394: vm_map_lock(src_map);
6395: break;
6396: }
6397:
6398: }
6399:
6400: /*
6401: * If steal_pages is true, make sure all
6402: * pages in the copy are not in any object
6403: * We try to remove them from the original
6404: * object, but we may have to copy them.
6405: *
6406: * At this point every page in the list is busy
6407: * and holds a paging reference to its object.
6408: * When we're done stealing, every page is busy,
6409: * and in no object (m->tabled == FALSE).
6410: */
6411: src_start = trunc_page(src_addr);
6412: if (options & VM_MAP_COPYIN_OPT_STEAL_PAGES) {
6413: register int i;
6414: vm_offset_t page_vaddr;
6415: vm_offset_t unwire_end;
6416: vm_offset_t map_entry_end;
6417: boolean_t share_map = FALSE;
6418:
6419: unwire_end = src_start;
6420: map_entry_end = src_start;
6421: for (i = 0; i < copy->cpy_npages; i++) {
6422:
6423:
6424: /*
6425: * Remove the page from its object if it
6426: * can be stolen. It can be stolen if:
6427: *
6428: * (1) The source is being destroyed,
6429: * the object is internal (hence
6430: * temporary), and not shared.
6431: * (2) The page is not precious.
6432: *
6433: * The not shared check consists of two
6434: * parts: (a) there are no objects that
6435: * shadow this object. (b) it is not the
6436: * object in any shared map entries (i.e.,
6437: * use_shared_copy is not set).
6438: *
6439: * The first check (a) means that we can't
6440: * steal pages from objects that are not
6441: * at the top of their shadow chains. This
6442: * should not be a frequent occurrence.
6443: *
6444: * Stealing wired pages requires telling the
6445: * pmap module to let go of them.
6446: *
6447: * NOTE: stealing clean pages from objects
6448: * whose mappings survive requires a call to
6449: * the pmap module. Maybe later.
6450: */
6451: m = copy->cpy_page_list[i];
6452: src_object = m->object;
6453: vm_object_lock(src_object);
6454:
6455: page_vaddr = src_start + (i * PAGE_SIZE);
6456: if(page_vaddr > map_entry_end) {
6457: if (!vm_map_lookup_entry(src_map, page_vaddr, &src_entry))
6458: share_map = TRUE;
6459: else if (src_entry->is_sub_map) {
6460: map_entry_end = src_entry->vme_end;
6461: share_map = TRUE;
6462: } else {
6463: map_entry_end = src_entry->vme_end;
6464: share_map = FALSE;
6465: }
6466: }
6467:
6468:
6469: if ((options & VM_MAP_COPYIN_OPT_SRC_DESTROY) &&
6470: src_object->internal &&
6471: !src_object->true_share &&
6472: (!src_object->shadowed) &&
6473: (src_object->copy_strategy ==
6474: MEMORY_OBJECT_COPY_SYMMETRIC) &&
6475: !m->precious &&
6476: !share_map) {
6477:
6478: if (m->wire_count > 0) {
6479:
6480: assert(m->wire_count == 1);
6481: /*
6482: * In order to steal a wired
6483: * page, we have to unwire it
6484: * first. We do this inline
6485: * here because we have the page.
6486: *
6487: * Step 1: Unwire the map entry.
6488: * Also tell the pmap module
6489: * that this piece of the
6490: * pmap is pageable.
6491: */
6492: vm_object_unlock(src_object);
6493: if (page_vaddr >= unwire_end) {
6494: if (!vm_map_lookup_entry(src_map,
6495: page_vaddr, &src_entry))
6496: panic("vm_map_copyin_page_list: missing wired map entry");
6497:
6498: vm_map_clip_start(src_map, src_entry,
6499: page_vaddr);
6500: vm_map_clip_end(src_map, src_entry,
6501: src_start + src_size);
6502:
6503: /* revisit why this assert fails CDY
6504: assert(src_entry->wired_count > 0);
6505: */
6506: src_entry->wired_count = 0;
6507: src_entry->user_wired_count = 0;
6508: unwire_end = src_entry->vme_end;
6509: pmap_pageable(vm_map_pmap(src_map),
6510: page_vaddr, unwire_end, TRUE);
6511: }
6512:
6513: /*
6514: * Step 2: Unwire the page.
6515: * pmap_remove handles this for us.
6516: */
6517: vm_object_lock(src_object);
6518: }
6519:
6520: /*
6521: * Don't need to remove the mapping;
6522: * vm_map_delete will handle it.
6523: *
6524: * Steal the page. Setting the wire count
6525: * to zero is vm_page_unwire without
6526: * activating the page.
6527: */
6528: vm_page_lock_queues();
6529: vm_page_remove(m);
6530: if (m->wire_count > 0) {
6531: m->wire_count = 0;
6532: vm_page_wire_count--;
6533: } else {
6534: VM_PAGE_QUEUES_REMOVE(m);
6535: }
6536: vm_page_unlock_queues();
6537: } else {
6538: /*
6539: * Have to copy this page. Have to
6540: * unlock the map while copying,
6541: * hence no further page stealing.
6542: * Hence just copy all the pages.
6543: * Unlock the map while copying;
6544: * This means no further page stealing.
6545: */
6546: vm_object_unlock(src_object);
6547: vm_map_unlock(src_map);
6548: vm_map_copy_steal_pages(copy);
6549: vm_map_lock(src_map);
6550: break;
6551: }
6552:
6553: vm_object_paging_end(src_object);
6554: vm_object_unlock(src_object);
6555: }
6556:
6557: copy->cpy_page_loose = TRUE;
6558:
6559: /*
6560: * If the source should be destroyed, do it now, since the
6561: * copy was successful.
6562: */
6563:
6564: if (options & VM_MAP_COPYIN_OPT_SRC_DESTROY) {
6565: (void) vm_map_delete(src_map, src_start,
6566: src_end, VM_MAP_NO_FLAGS);
6567: }
6568: } else {
6569: /*
6570: * Not stealing pages leaves busy or prepped pages in the map.
6571: * This will cause source destruction to hang. Use
6572: * a continuation to prevent this.
6573: */
6574: if ((options & VM_MAP_COPYIN_OPT_SRC_DESTROY) &&
6575: !vm_map_copy_has_cont(copy)) {
6576: cont_args = (vm_map_copyin_args_t)
6577: kalloc(sizeof(vm_map_copyin_args_data_t));
6578: vm_map_reference(src_map);
6579: cont_args->map = src_map;
6580: cont_args->src_addr = (vm_offset_t) 0;
6581: cont_args->src_len = (vm_size_t) 0;
6582: cont_args->destroy_addr = src_start;
6583: cont_args->destroy_len = src_end - src_start;
6584: cont_args->options = options;
6585:
6586: copy->cpy_cont_args = cont_args;
6587: copy->cpy_cont = vm_map_copyin_page_list_cont;
6588: }
6589: }
6590:
6591: vm_map_unlock(src_map);
6592:
6593: *copy_result = copy;
6594: return(result);
6595:
6596: error:
6597: {
6598: submap_map_t *ptr;
6599:
6600: vm_map_unlock(src_map);
6601: vm_map_copy_discard(copy);
6602:
6603: for(ptr = parent_maps; ptr != NULL; ptr = parent_maps) {
6604: parent_maps=parent_maps->next;
6605: kfree((vm_offset_t)ptr, sizeof(submap_map_t));
6606: }
6607: return(result);
6608: }
6609: }
6610:
6611: void
6612: vm_map_fork_share(
6613: vm_map_t old_map,
6614: vm_map_entry_t old_entry,
6615: vm_map_t new_map)
6616: {
6617: vm_object_t object;
6618: vm_map_entry_t new_entry;
6619:
6620: /*
6621: * New sharing code. New map entry
6622: * references original object. Internal
6623: * objects use asynchronous copy algorithm for
6624: * future copies. First make sure we have
6625: * the right object. If we need a shadow,
6626: * or someone else already has one, then
6627: * make a new shadow and share it.
6628: */
6629:
6630: object = old_entry->object.vm_object;
6631: if (old_entry->is_sub_map) {
6632: assert(old_entry->wired_count == 0);
6633: } else if (object == VM_OBJECT_NULL) {
6634: object = vm_object_allocate((vm_size_t)(old_entry->vme_end -
6635: old_entry->vme_start));
6636: old_entry->offset = 0;
6637: old_entry->object.vm_object = object;
6638: assert(!old_entry->needs_copy);
6639: } else if (object->copy_strategy !=
6640: MEMORY_OBJECT_COPY_SYMMETRIC) {
6641:
6642: /*
6643: * We are already using an asymmetric
6644: * copy, and therefore we already have
6645: * the right object.
6646: */
6647:
6648: assert(! old_entry->needs_copy);
6649: }
6650: else if (old_entry->needs_copy || /* case 1 */
6651: object->shadowed || /* case 2 */
6652: (!object->true_share && /* case 3 */
6653: !old_entry->is_shared &&
6654: (object->size >
6655: (vm_size_t)(old_entry->vme_end -
6656: old_entry->vme_start)))) {
6657:
6658: /*
6659: * We need to create a shadow.
6660: * There are three cases here.
6661: * In the first case, we need to
6662: * complete a deferred symmetrical
6663: * copy that we participated in.
6664: * In the second and third cases,
6665: * we need to create the shadow so
6666: * that changes that we make to the
6667: * object do not interfere with
6668: * any symmetrical copies which
6669: * have occured (case 2) or which
6670: * might occur (case 3).
6671: *
6672: * The first case is when we had
6673: * deferred shadow object creation
6674: * via the entry->needs_copy mechanism.
6675: * This mechanism only works when
6676: * only one entry points to the source
6677: * object, and we are about to create
6678: * a second entry pointing to the
6679: * same object. The problem is that
6680: * there is no way of mapping from
6681: * an object to the entries pointing
6682: * to it. (Deferred shadow creation
6683: * works with one entry because occurs
6684: * at fault time, and we walk from the
6685: * entry to the object when handling
6686: * the fault.)
6687: *
6688: * The second case is when the object
6689: * to be shared has already been copied
6690: * with a symmetric copy, but we point
6691: * directly to the object without
6692: * needs_copy set in our entry. (This
6693: * can happen because different ranges
6694: * of an object can be pointed to by
6695: * different entries. In particular,
6696: * a single entry pointing to an object
6697: * can be split by a call to vm_inherit,
6698: * which, combined with task_create, can
6699: * result in the different entries
6700: * having different needs_copy values.)
6701: * The shadowed flag in the object allows
6702: * us to detect this case. The problem
6703: * with this case is that if this object
6704: * has or will have shadows, then we
6705: * must not perform an asymmetric copy
6706: * of this object, since such a copy
6707: * allows the object to be changed, which
6708: * will break the previous symmetrical
6709: * copies (which rely upon the object
6710: * not changing). In a sense, the shadowed
6711: * flag says "don't change this object".
6712: * We fix this by creating a shadow
6713: * object for this object, and sharing
6714: * that. This works because we are free
6715: * to change the shadow object (and thus
6716: * to use an asymmetric copy strategy);
6717: * this is also semantically correct,
6718: * since this object is temporary, and
6719: * therefore a copy of the object is
6720: * as good as the object itself. (This
6721: * is not true for permanent objects,
6722: * since the pager needs to see changes,
6723: * which won't happen if the changes
6724: * are made to a copy.)
6725: *
6726: * The third case is when the object
6727: * to be shared has parts sticking
6728: * outside of the entry we're working
6729: * with, and thus may in the future
6730: * be subject to a symmetrical copy.
6731: * (This is a preemptive version of
6732: * case 2.)
6733: */
6734:
6735: assert(!(object->shadowed && old_entry->is_shared));
6736: vm_object_shadow(&old_entry->object.vm_object,
6737: &old_entry->offset,
6738: (vm_size_t) (old_entry->vme_end -
6739: old_entry->vme_start));
6740:
6741: /*
6742: * If we're making a shadow for other than
6743: * copy on write reasons, then we have
6744: * to remove write permission.
6745: */
6746:
6747: if (!old_entry->needs_copy &&
6748: (old_entry->protection & VM_PROT_WRITE)) {
6749: pmap_protect(vm_map_pmap(old_map),
6750: old_entry->vme_start,
6751: old_entry->vme_end,
6752: old_entry->protection & ~VM_PROT_WRITE);
6753: }
6754: old_entry->needs_copy = FALSE;
6755: object = old_entry->object.vm_object;
6756: }
6757:
6758: /*
6759: * If object was using a symmetric copy strategy,
6760: * change its copy strategy to the default
6761: * asymmetric copy strategy, which is copy_delay
6762: * in the non-norma case and copy_call in the
6763: * norma case. Bump the reference count for the
6764: * new entry.
6765: */
6766:
6767: if(old_entry->is_sub_map) {
6768: vm_map_lock(old_entry->object.sub_map);
6769: vm_map_reference(old_entry->object.sub_map);
6770: vm_map_unlock(old_entry->object.sub_map);
6771: } else {
6772: vm_object_lock(object);
6773: object->ref_count++;
6774: vm_object_res_reference(object);
6775: if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC) {
6776: object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
6777: }
6778: vm_object_unlock(object);
6779: }
6780:
6781: /*
6782: * Clone the entry, using object ref from above.
6783: * Mark both entries as shared.
6784: */
6785:
6786: new_entry = vm_map_entry_create(new_map);
6787: vm_map_entry_copy(new_entry, old_entry);
6788: old_entry->is_shared = TRUE;
6789: new_entry->is_shared = TRUE;
6790:
6791: /*
6792: * Insert the entry into the new map -- we
6793: * know we're inserting at the end of the new
6794: * map.
6795: */
6796:
6797: vm_map_entry_link(new_map, vm_map_last_entry(new_map), new_entry);
6798:
6799: /*
6800: * Update the physical map
6801: */
6802:
6803: if (old_entry->is_sub_map) {
6804: /* Bill Angell pmap support goes here */
6805: } else {
6806: pmap_copy(new_map->pmap, old_map->pmap, new_entry->vme_start,
6807: old_entry->vme_end - old_entry->vme_start,
6808: old_entry->vme_start);
6809: }
6810: }
6811:
6812: boolean_t
6813: vm_map_fork_copy(
6814: vm_map_t old_map,
6815: vm_map_entry_t *old_entry_p,
6816: vm_map_t new_map)
6817: {
6818: vm_map_entry_t old_entry = *old_entry_p;
6819: vm_size_t entry_size = old_entry->vme_end - old_entry->vme_start;
6820: vm_offset_t start = old_entry->vme_start;
6821: vm_map_copy_t copy;
6822: vm_map_entry_t last = vm_map_last_entry(new_map);
6823:
6824: vm_map_unlock(old_map);
6825: /*
6826: * Use maxprot version of copyin because we
6827: * care about whether this memory can ever
6828: * be accessed, not just whether it's accessible
6829: * right now.
6830: */
6831: if (vm_map_copyin_maxprot(old_map, start, entry_size, FALSE, ©)
6832: != KERN_SUCCESS) {
6833: /*
6834: * The map might have changed while it
6835: * was unlocked, check it again. Skip
6836: * any blank space or permanently
6837: * unreadable region.
6838: */
6839: vm_map_lock(old_map);
6840: if (!vm_map_lookup_entry(old_map, start, &last) ||
6841: last->max_protection & VM_PROT_READ ==
6842: VM_PROT_NONE) {
6843: last = last->vme_next;
6844: }
6845: *old_entry_p = last;
6846:
6847: /*
6848: * XXX For some error returns, want to
6849: * XXX skip to the next element. Note
6850: * that INVALID_ADDRESS and
6851: * PROTECTION_FAILURE are handled above.
6852: */
6853:
6854: return FALSE;
6855: }
6856:
6857: /*
6858: * Insert the copy into the new map
6859: */
6860:
6861: vm_map_copy_insert(new_map, last, copy);
6862:
6863: /*
6864: * Pick up the traversal at the end of
6865: * the copied region.
6866: */
6867:
6868: vm_map_lock(old_map);
6869: start += entry_size;
6870: if (! vm_map_lookup_entry(old_map, start, &last)) {
6871: last = last->vme_next;
6872: } else {
6873: vm_map_clip_start(old_map, last, start);
6874: }
6875: *old_entry_p = last;
6876:
6877: return TRUE;
6878: }
6879:
6880: /*
6881: * vm_map_fork:
6882: *
6883: * Create and return a new map based on the old
6884: * map, according to the inheritance values on the
6885: * regions in that map.
6886: *
6887: * The source map must not be locked.
6888: */
6889: vm_map_t
6890: vm_map_fork(
6891: vm_map_t old_map)
6892: {
6893: pmap_t new_pmap = pmap_create((vm_size_t) 0);
6894: vm_map_t new_map;
6895: vm_map_entry_t old_entry;
6896: vm_size_t new_size = 0, entry_size;
6897: vm_map_entry_t new_entry;
6898: boolean_t src_needs_copy;
6899: boolean_t new_entry_needs_copy;
6900:
6901: vm_map_reference_swap(old_map);
6902: vm_map_lock(old_map);
6903:
6904: new_map = vm_map_create(new_pmap,
6905: old_map->min_offset,
6906: old_map->max_offset,
6907: old_map->hdr.entries_pageable);
6908:
6909: for (
6910: old_entry = vm_map_first_entry(old_map);
6911: old_entry != vm_map_to_entry(old_map);
6912: ) {
6913:
6914: entry_size = old_entry->vme_end - old_entry->vme_start;
6915:
6916: switch (old_entry->inheritance) {
6917: case VM_INHERIT_NONE:
6918: break;
6919:
6920: case VM_INHERIT_SHARE:
6921: vm_map_fork_share(old_map, old_entry, new_map);
6922: new_size += entry_size;
6923: break;
6924:
6925: case VM_INHERIT_COPY:
6926:
6927: /*
6928: * Inline the copy_quickly case;
6929: * upon failure, fall back on call
6930: * to vm_map_fork_copy.
6931: */
6932:
6933: if(old_entry->is_sub_map)
6934: break;
6935: if (old_entry->wired_count != 0) {
6936: goto slow_vm_map_fork_copy;
6937: }
6938:
6939: new_entry = vm_map_entry_create(new_map);
6940: vm_map_entry_copy(new_entry, old_entry);
6941:
6942: if (! vm_object_copy_quickly(
6943: &new_entry->object.vm_object,
6944: old_entry->offset,
6945: (old_entry->vme_end -
6946: old_entry->vme_start),
6947: &src_needs_copy,
6948: &new_entry_needs_copy)) {
6949: vm_map_entry_dispose(new_map, new_entry);
6950: goto slow_vm_map_fork_copy;
6951: }
6952:
6953: /*
6954: * Handle copy-on-write obligations
6955: */
6956:
6957: if (src_needs_copy && !old_entry->needs_copy) {
6958: vm_object_pmap_protect(
6959: old_entry->object.vm_object,
6960: old_entry->offset,
6961: (old_entry->vme_end -
6962: old_entry->vme_start),
6963: (old_entry->is_shared ? PMAP_NULL :
6964: old_map->pmap),
6965: old_entry->vme_start,
6966: old_entry->protection & ~VM_PROT_WRITE);
6967:
6968: old_entry->needs_copy = TRUE;
6969: }
6970: new_entry->needs_copy = new_entry_needs_copy;
6971:
6972: /*
6973: * Insert the entry at the end
6974: * of the map.
6975: */
6976:
6977: vm_map_entry_link(new_map, vm_map_last_entry(new_map),
6978: new_entry);
6979: new_size += entry_size;
6980: break;
6981:
6982: slow_vm_map_fork_copy:
6983: if (vm_map_fork_copy(old_map, &old_entry, new_map)) {
6984: new_size += entry_size;
6985: }
6986: continue;
6987: }
6988: old_entry = old_entry->vme_next;
6989: }
6990:
6991: new_map->size = new_size;
6992: vm_map_unlock(old_map);
6993: vm_map_deallocate(old_map);
6994:
6995: return(new_map);
6996: }
6997:
6998: /*
6999: * vm_map_lookup_locked:
7000: *
7001: * Finds the VM object, offset, and
7002: * protection for a given virtual address in the
7003: * specified map, assuming a page fault of the
7004: * type specified.
7005: *
7006: * Returns the (object, offset, protection) for
7007: * this address, whether it is wired down, and whether
7008: * this map has the only reference to the data in question.
7009: * In order to later verify this lookup, a "version"
7010: * is returned.
7011: *
7012: * The map MUST be locked by the caller and WILL be
7013: * locked on exit. In order to guarantee the
7014: * existence of the returned object, it is returned
7015: * locked.
7016: *
7017: * If a lookup is requested with "write protection"
7018: * specified, the map may be changed to perform virtual
7019: * copying operations, although the data referenced will
7020: * remain the same.
7021: */
7022: kern_return_t
7023: vm_map_lookup_locked(
7024: vm_map_t *var_map, /* IN/OUT */
7025: register vm_offset_t vaddr,
7026: register vm_prot_t fault_type,
7027: vm_map_version_t *out_version, /* OUT */
7028: vm_object_t *object, /* OUT */
7029: vm_offset_t *offset, /* OUT */
7030: vm_prot_t *out_prot, /* OUT */
7031: boolean_t *wired, /* OUT */
7032: int *behavior, /* OUT */
7033: vm_offset_t *lo_offset, /* OUT */
7034: vm_offset_t *hi_offset) /* OUT */
7035: {
7036: vm_map_entry_t entry;
7037: register vm_map_t map = *var_map;
7038: vm_map_t old_map = *var_map;
7039: vm_offset_t old_vaddr = vaddr;
7040: vm_map_t cow_sub_map;
7041: vm_offset_t old_start;
7042: vm_offset_t old_end;
7043: register vm_prot_t prot;
7044:
7045: RetryLookup: ;
7046:
7047: /*
7048: * If the map has an interesting hint, try it before calling
7049: * full blown lookup routine.
7050: */
7051:
7052: mutex_lock(&map->s_lock);
7053: entry = map->hint;
7054: mutex_unlock(&map->s_lock);
7055:
7056: if ((entry == vm_map_to_entry(map)) ||
7057: (vaddr < entry->vme_start) || (vaddr >= entry->vme_end)) {
7058: vm_map_entry_t tmp_entry;
7059:
7060: /*
7061: * Entry was either not a valid hint, or the vaddr
7062: * was not contained in the entry, so do a full lookup.
7063: */
7064: if (!vm_map_lookup_entry(map, vaddr, &tmp_entry))
7065: return KERN_INVALID_ADDRESS;
7066:
7067: entry = tmp_entry;
7068: }
7069: if(map == old_map) {
7070: old_start = entry->vme_start;
7071: old_end = entry->vme_end;
7072: }
7073:
7074: /*
7075: * Handle submaps. Drop lock on upper map, submap is
7076: * returned locked.
7077: */
7078:
7079: submap_recurse:
7080: if (entry->is_sub_map) {
7081: vm_map_entry_t our_entry;
7082: vm_offset_t local_vaddr;
7083: vm_offset_t end_delta;
7084: vm_offset_t start_delta;
7085: vm_map_entry_t submap_entry;
7086: boolean_t mapped_needs_copy=FALSE;
7087:
7088: local_vaddr = vaddr;
7089: our_entry = entry;
7090:
7091: vm_map_lock_read(entry->object.sub_map);
7092: vm_map_unlock_read(map);
7093: *var_map = map = entry->object.sub_map;
7094:
7095: /* calculate the offset in the submap for vaddr */
7096: local_vaddr = (local_vaddr - entry->vme_start) + entry->offset;
7097:
7098: if(entry->needs_copy) {
7099: if(!mapped_needs_copy) {
7100: cow_sub_map = entry->object.sub_map;
7101: mapped_needs_copy = TRUE;
7102: }
7103: }
7104:
7105: if(!vm_map_lookup_entry(map, local_vaddr, &submap_entry)) {
7106: return KERN_INVALID_ADDRESS;
7107: }
7108: /* find the attenuated shadow of the underlying object */
7109: /* on our target map */
7110:
7111: /* in english the submap object may extend beyond the */
7112: /* region mapped by the entry or, may only fill a portion */
7113: /* of it. For our purposes, we only care if the object */
7114: /* doesn't fill. In this case the area which will */
7115: /* ultimately be clipped in the top map will only need */
7116: /* to be as big as the portion of the underlying entry */
7117: /* which is mapped */
7118: start_delta = submap_entry->vme_start > entry->offset ?
7119: submap_entry->vme_start - entry->offset : 0;
7120:
7121: end_delta =
7122: (entry->offset + start_delta + (old_end - old_start)) <=
7123: submap_entry->vme_end ?
7124: 0 : (entry->offset +
7125: start_delta + (old_end - old_start))
7126: - submap_entry->vme_end;
7127:
7128: old_start += start_delta;
7129: old_end -= end_delta;
7130:
7131: vaddr = local_vaddr;
7132: entry = submap_entry;
7133: if(submap_entry->is_sub_map) {
7134: goto submap_recurse;
7135: }
7136: if((fault_type & VM_PROT_WRITE) &&
7137: !(submap_entry->protection & VM_PROT_WRITE)) {
7138: if(mapped_needs_copy) {
7139:
7140: vm_object_t copy_object;
7141: vm_offset_t object_offset;
7142: vm_offset_t local_start;
7143: vm_offset_t local_end;
7144:
7145: object_offset = submap_entry->offset;
7146:
7147: /* This is the COW case, lets connect */
7148: /* an entry in our space to the underlying */
7149: /* object in the submap, bypassing the */
7150: /* submap. */
7151:
7152: /* set up shadow object */
7153: copy_object =
7154: vm_object_copy_delayed(
7155: submap_entry->object.vm_object,
7156: submap_entry->offset,
7157: old_end-old_start);
7158:
7159: /* This case works opposite of the */
7160: /* normal submap case. We go back */
7161: /* to the top of the map tree and */
7162: /* clip out the target portion of */
7163: /* the sub_map, substituting the */
7164: /* new copy object, we do this for */
7165: /* all maps in the tree, down to */
7166: /* the COW one. */
7167:
7168: vm_map_unlock_read(map);
7169: vm_map_lock(old_map);
7170: local_start = old_start;
7171: local_end = old_end;
7172: local_vaddr = vaddr = old_vaddr;
7173: map = old_map;
7174: while(TRUE) {
7175: vm_map_t new_map;
7176:
7177: if(!vm_map_lookup_entry(map,
7178: local_vaddr, &entry)) {
7179: vm_object_deallocate(
7180: copy_object);
7181: vm_map_unlock(map);
7182: vm_map_lock_read(*var_map);
7183: return KERN_INVALID_ADDRESS;
7184: }
7185:
7186: /* clip out the portion of space */
7187: /* mapped by the sub map which */
7188: /* corresponds to the underlying */
7189: /* object */
7190: vm_map_clip_start(map, entry,
7191: local_start);
7192: vm_map_clip_end(map, entry,
7193: local_end);
7194: new_map = entry->object.sub_map;
7195:
7196: /* update local start and end */
7197: /* in possible underlying submap */
7198: local_start = entry->offset;
7199: local_end = (entry->vme_end -
7200: entry->vme_start) +
7201: entry->offset;
7202: local_vaddr -= entry->vme_start;
7203: local_vaddr += entry->offset;
7204:
7205: /* substitute copy object for */
7206: /* shared map entry */
7207: vm_map_deallocate(
7208: entry->object.sub_map);
7209: entry->is_sub_map = FALSE;
7210: vm_object_reference(copy_object);
7211: entry->object.vm_object = copy_object;
7212: entry->protection |= VM_PROT_WRITE;
7213: entry->max_protection |= VM_PROT_WRITE;
7214: entry->needs_copy = FALSE;
7215: if(entry->inheritance
7216: == VM_INHERIT_SHARE)
7217: entry->inheritance = VM_INHERIT_COPY;
7218: entry->offset = object_offset;
7219: if (map != old_map)
7220: entry->is_shared = TRUE;
7221:
7222: vm_map_unlock(map);
7223: if(new_map == cow_sub_map)
7224: break;
7225: map = new_map;
7226: vm_map_lock(map);
7227: }
7228: map = old_map;
7229: vm_map_lock_read(map);
7230: vaddr = old_vaddr;
7231: /* get rid of extra reference */
7232: vm_object_deallocate(copy_object);
7233: if(!vm_map_lookup_entry(map, vaddr, &entry)) {
7234: return KERN_INVALID_ADDRESS;
7235: }
7236: } else {
7237: /* write fault! */
7238: return KERN_INVALID_ADDRESS;
7239: }
7240: }
7241: vm_map_lock_read(old_map);
7242: vm_map_unlock_read(map);
7243: *var_map = map = old_map;
7244: }
7245:
7246: /*
7247: * Check whether this task is allowed to have
7248: * this page.
7249: */
7250:
7251: prot = entry->protection;
7252: if ((fault_type & (prot)) != fault_type)
7253: return KERN_PROTECTION_FAILURE;
7254:
7255: /*
7256: * If this page is not pageable, we have to get
7257: * it for all possible accesses.
7258: */
7259:
7260: if (*wired = (entry->wired_count != 0))
7261: prot = fault_type = entry->protection;
7262:
7263: /*
7264: * If the entry was copy-on-write, we either ...
7265: */
7266:
7267: if (entry->needs_copy) {
7268: /*
7269: * If we want to write the page, we may as well
7270: * handle that now since we've got the map locked.
7271: *
7272: * If we don't need to write the page, we just
7273: * demote the permissions allowed.
7274: */
7275:
7276: if (fault_type & VM_PROT_WRITE || *wired) {
7277: /*
7278: * Make a new object, and place it in the
7279: * object chain. Note that no new references
7280: * have appeared -- one just moved from the
7281: * map to the new object.
7282: */
7283:
7284: if (vm_map_lock_read_to_write(map)) {
7285: vm_map_lock_read(map);
7286: goto RetryLookup;
7287: }
7288: vm_object_shadow(&entry->object.vm_object,
7289: &entry->offset,
7290: (vm_size_t) (entry->vme_end -
7291: entry->vme_start));
7292:
7293: entry->needs_copy = FALSE;
7294: vm_map_lock_write_to_read(map);
7295: }
7296: else {
7297: /*
7298: * We're attempting to read a copy-on-write
7299: * page -- don't allow writes.
7300: */
7301:
7302: prot &= (~VM_PROT_WRITE);
7303: }
7304: }
7305:
7306: /*
7307: * Create an object if necessary.
7308: */
7309: if (entry->object.vm_object == VM_OBJECT_NULL) {
7310:
7311: if (vm_map_lock_read_to_write(map)) {
7312: vm_map_lock_read(map);
7313: goto RetryLookup;
7314: }
7315:
7316: entry->object.vm_object = vm_object_allocate(
7317: (vm_size_t)(entry->vme_end - entry->vme_start));
7318: entry->offset = 0;
7319: vm_map_lock_write_to_read(map);
7320: }
7321:
7322: /*
7323: * Return the object/offset from this entry. If the entry
7324: * was copy-on-write or empty, it has been fixed up. Also
7325: * return the protection.
7326: */
7327:
7328: *offset = (vaddr - entry->vme_start) + entry->offset;
7329: *object = entry->object.vm_object;
7330: *out_prot = prot;
7331: *behavior = entry->behavior;
7332: *lo_offset = entry->offset;
7333: *hi_offset = (entry->vme_end - entry->vme_start) + entry->offset;
7334:
7335: /*
7336: * Lock the object to prevent it from disappearing
7337: */
7338:
7339: vm_object_lock(*object);
7340:
7341: /*
7342: * Save the version number
7343: */
7344:
7345: out_version->main_timestamp = map->timestamp;
7346:
7347: return KERN_SUCCESS;
7348: }
7349:
7350:
7351: /*
7352: * vm_map_verify:
7353: *
7354: * Verifies that the map in question has not changed
7355: * since the given version. If successful, the map
7356: * will not change until vm_map_verify_done() is called.
7357: */
7358: boolean_t
7359: vm_map_verify(
7360: register vm_map_t map,
7361: register vm_map_version_t *version) /* REF */
7362: {
7363: boolean_t result;
7364:
7365: vm_map_lock_read(map);
7366: result = (map->timestamp == version->main_timestamp);
7367:
7368: if (!result)
7369: vm_map_unlock_read(map);
7370:
7371: return(result);
7372: }
7373:
7374: /*
7375: * vm_map_verify_done:
7376: *
7377: * Releases locks acquired by a vm_map_verify.
7378: *
7379: * This is now a macro in vm/vm_map.h. It does a
7380: * vm_map_unlock_read on the map.
7381: */
7382:
7383:
7384: /*
7385: * vm_region:
7386: *
7387: * User call to obtain information about a region in
7388: * a task's address map. Currently, only one flavor is
7389: * supported.
7390: *
7391: * XXX The reserved and behavior fields cannot be filled
7392: * in until the vm merge from the IK is completed, and
7393: * vm_reserve is implemented.
7394: *
7395: * XXX Dependency: syscall_vm_region() also supports only one flavor.
7396: */
7397:
7398: kern_return_t
7399: vm_region(
7400: vm_map_t map,
7401: vm_offset_t *address, /* IN/OUT */
7402: vm_size_t *size, /* OUT */
7403: vm_region_flavor_t flavor, /* IN */
7404: vm_region_info_t info, /* OUT */
7405: mach_msg_type_number_t *count, /* IN/OUT */
7406: ipc_port_t *object_name) /* OUT */
7407: {
7408: vm_map_entry_t tmp_entry;
7409: register
7410: vm_map_entry_t entry;
7411: register
7412: vm_offset_t start;
7413: vm_region_basic_info_t basic;
7414: vm_region_extended_info_t extended;
7415: vm_region_top_info_t top;
7416:
7417: if (map == VM_MAP_NULL)
7418: return(KERN_INVALID_ARGUMENT);
7419:
7420: switch (flavor) {
7421:
7422: case VM_REGION_BASIC_INFO:
7423: {
7424: if (*count < VM_REGION_BASIC_INFO_COUNT)
7425: return(KERN_INVALID_ARGUMENT);
7426:
7427: basic = (vm_region_basic_info_t) info;
7428: *count = VM_REGION_BASIC_INFO_COUNT;
7429:
7430: vm_map_lock_read(map);
7431:
7432: start = *address;
7433: if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
7434: if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) {
7435: vm_map_unlock_read(map);
7436: return(KERN_INVALID_ADDRESS);
7437: }
7438: } else {
7439: entry = tmp_entry;
7440: }
7441:
7442: start = entry->vme_start;
7443:
7444: basic->offset = entry->offset;
7445: basic->protection = entry->protection;
7446: basic->inheritance = entry->inheritance;
7447: basic->max_protection = entry->max_protection;
7448: basic->behavior = entry->behavior;
7449: basic->user_wired_count = entry->user_wired_count;
7450: basic->reserved = FALSE; /* XXX when vm_reserve fini */
7451: *address = start;
7452: *size = (entry->vme_end - start);
7453:
7454: if (object_name) *object_name = IP_NULL;
7455: if (entry->is_sub_map) {
7456: basic->shared = FALSE;
7457: } else {
7458: basic->shared = entry->is_shared;
7459: }
7460:
7461: vm_map_unlock_read(map);
7462: return(KERN_SUCCESS);
7463: }
7464: case VM_REGION_EXTENDED_INFO:
7465: { void vm_region_walk();
7466:
7467: if (*count < VM_REGION_EXTENDED_INFO_COUNT)
7468: return(KERN_INVALID_ARGUMENT);
7469:
7470: extended = (vm_region_extended_info_t) info;
7471: *count = VM_REGION_EXTENDED_INFO_COUNT;
7472:
7473: vm_map_lock_read(map);
7474:
7475: start = *address;
7476: if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
7477: if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) {
7478: vm_map_unlock_read(map);
7479: return(KERN_INVALID_ADDRESS);
7480: }
7481: } else {
7482: entry = tmp_entry;
7483: }
7484: start = entry->vme_start;
7485:
7486: extended->protection = entry->protection;
7487: extended->user_tag = entry->alias;
7488: extended->pages_resident = 0;
7489: extended->pages_swapped_out = 0;
7490: extended->pages_shared_now_private = 0;
7491: extended->pages_referenced = 0;
7492: extended->external_pager = 0;
7493: extended->shadow_depth = 0;
7494:
7495: vm_region_walk(entry, extended, entry->offset, entry->vme_end - start, map, start);
7496:
7497: if (object_name)
7498: *object_name = IP_NULL;
7499: *address = start;
7500: *size = (entry->vme_end - start);
7501:
7502: vm_map_unlock_read(map);
7503: return(KERN_SUCCESS);
7504: }
7505: case VM_REGION_TOP_INFO:
7506: { void vm_region_top_walk();
7507:
7508: if (*count < VM_REGION_TOP_INFO_COUNT)
7509: return(KERN_INVALID_ARGUMENT);
7510:
7511: top = (vm_region_top_info_t) info;
7512: *count = VM_REGION_TOP_INFO_COUNT;
7513:
7514: vm_map_lock_read(map);
7515:
7516: start = *address;
7517: if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
7518: if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) {
7519: vm_map_unlock_read(map);
7520: return(KERN_INVALID_ADDRESS);
7521: }
7522: } else {
7523: entry = tmp_entry;
7524:
7525: }
7526: start = entry->vme_start;
7527:
7528: top->private_pages_resident = 0;
7529: top->shared_pages_resident = 0;
7530:
7531: vm_region_top_walk(entry, top);
7532:
7533: if (object_name)
7534: *object_name = IP_NULL;
7535: *address = start;
7536: *size = (entry->vme_end - start);
7537:
7538: vm_map_unlock_read(map);
7539: return(KERN_SUCCESS);
7540: }
7541: default:
7542: return(KERN_INVALID_ARGUMENT);
7543: }
7544: }
7545:
7546:
7547: void
7548: vm_region_top_walk(
7549: vm_map_entry_t entry,
7550: vm_region_top_info_t top)
7551: {
7552: register struct vm_object *obj, *tmp_obj;
7553:
7554: if (entry->object.vm_object == 0) {
7555: top->share_mode = SM_EMPTY;
7556: top->ref_count = 0;
7557: top->obj_id = 0;
7558: return;
7559: }
7560: if (entry->is_sub_map)
7561: vm_region_top_walk((vm_map_entry_t)entry->object.sub_map, top);
7562: else {
7563: obj = entry->object.vm_object;
7564:
7565: vm_object_lock(obj);
7566:
7567: if (obj->shadow) {
7568: if (obj->ref_count == 1)
7569: top->private_pages_resident = obj->resident_page_count;
7570: else
7571: top->shared_pages_resident = obj->resident_page_count;
7572: top->ref_count = obj->ref_count;
7573: top->share_mode = SM_COW;
7574:
7575: while (tmp_obj = obj->shadow) {
7576: vm_object_lock(tmp_obj);
7577: vm_object_unlock(obj);
7578: obj = tmp_obj;
7579:
7580: top->shared_pages_resident += obj->resident_page_count;
7581: top->ref_count += obj->resident_page_count - 1;
7582: }
7583: } else {
7584: if (entry->needs_copy) {
7585: top->share_mode = SM_COW;
7586: top->shared_pages_resident = obj->resident_page_count;
7587: } else {
7588: if (obj->ref_count == 1) {
7589: top->share_mode = SM_PRIVATE;
7590: top->private_pages_resident = obj->resident_page_count;
7591: } else {
7592: top->share_mode = SM_SHARED;
7593: top->shared_pages_resident = obj->resident_page_count;
7594: }
7595: }
7596: top->ref_count = obj->ref_count;
7597: }
7598: top->obj_id = (int)obj;
7599:
7600: vm_object_unlock(obj);
7601: }
7602: }
7603:
7604: void
7605: vm_region_walk(
7606: vm_map_entry_t entry,
7607: vm_region_extended_info_t extended,
7608: vm_offset_t offset,
7609: vm_offset_t range,
7610: vm_map_t map,
7611: vm_offset_t va)
7612: {
7613: register struct vm_object *obj, *tmp_obj;
7614: register vm_offset_t last_offset;
7615: register int i;
7616: void vm_region_look_for_page();
7617:
7618: if (entry->object.vm_object == 0) {
7619: extended->share_mode = SM_EMPTY;
7620: extended->ref_count = 0;
7621: return;
7622: }
7623: if (entry->is_sub_map)
7624: vm_region_walk((vm_map_entry_t)entry->object.sub_map, extended, offset + entry->offset,
7625: range, map, va);
7626: else {
7627: obj = entry->object.vm_object;
7628:
7629: vm_object_lock(obj);
7630:
7631: for (last_offset = offset + range; offset < last_offset; offset += PAGE_SIZE, va += PAGE_SIZE)
7632: vm_region_look_for_page(obj, extended, offset, obj->ref_count, 0, map, va);
7633:
7634: if (extended->shadow_depth || entry->needs_copy)
7635: extended->share_mode = SM_COW;
7636: else {
7637: if (obj->ref_count == 1)
7638: extended->share_mode = SM_PRIVATE;
7639: else {
7640: if (obj->true_share)
7641: extended->share_mode = SM_TRUESHARED;
7642: else
7643: extended->share_mode = SM_SHARED;
7644: }
7645: }
7646: extended->ref_count = obj->ref_count - extended->shadow_depth;
7647:
7648: for (i = 0; i < extended->shadow_depth; i++) {
7649: if ((tmp_obj = obj->shadow) == 0)
7650: break;
7651: vm_object_lock(tmp_obj);
7652: vm_object_unlock(obj);
7653: extended->ref_count += tmp_obj->ref_count;
7654: obj = tmp_obj;
7655: }
7656: vm_object_unlock(obj);
7657:
7658: if (extended->share_mode == SM_SHARED) {
7659: register vm_map_entry_t cur;
7660: register vm_map_entry_t last;
7661: int my_refs;
7662:
7663: obj = entry->object.vm_object;
7664: last = vm_map_to_entry(map);
7665: my_refs = 0;
7666:
7667: for (cur = vm_map_first_entry(map); cur != last; cur = cur->vme_next)
7668: my_refs += vm_region_count_obj_refs(cur, obj);
7669:
7670: if (my_refs == obj->ref_count)
7671: extended->share_mode = SM_PRIVATE_ALIASED;
7672: else if (my_refs > 1)
7673: extended->share_mode = SM_SHARED_ALIASED;
7674: }
7675: }
7676: }
7677:
7678:
7679:
7680: void
7681: vm_region_look_for_page(
7682: vm_object_t object,
7683: vm_region_extended_info_t extended,
7684: vm_offset_t offset,
7685: int max_refcnt,
7686: int depth,
7687: vm_map_t map,
7688: vm_offset_t va)
7689: {
7690: register vm_page_t p;
7691: register vm_object_t shadow;
7692:
7693: shadow = object->shadow;
7694:
7695: queue_iterate(&object->memq, p, vm_page_t, listq) {
7696: if (p->offset == offset) {
7697: if (shadow && (max_refcnt == 1))
7698: extended->pages_shared_now_private++;
7699:
7700: if (pmap_extract(vm_map_pmap(map), va))
7701: extended->pages_referenced++;
7702: extended->pages_resident++;
7703:
7704: return;
7705: }
7706: }
7707: if (object->existence_map) {
7708: if (vm_external_state_get(object->existence_map, offset) == VM_EXTERNAL_STATE_EXISTS) {
7709: if (shadow && (max_refcnt == 1))
7710: extended->pages_shared_now_private++;
7711: extended->pages_swapped_out++;
7712:
7713: return;
7714: }
7715: }
7716: if (shadow) {
7717: vm_object_lock(shadow);
7718:
7719: if (++depth > extended->shadow_depth)
7720: extended->shadow_depth = depth;
7721:
7722: if (shadow->ref_count > max_refcnt)
7723: max_refcnt = shadow->ref_count;
7724:
7725: vm_region_look_for_page(shadow, extended, offset + object->shadow_offset,
7726: max_refcnt, depth, map, va);
7727: vm_object_unlock(shadow);
7728:
7729: return;
7730: }
7731: if ( !(object->pager_trusted) && !(object->internal))
7732: extended->external_pager = 1;
7733: }
7734:
7735:
7736: vm_region_count_obj_refs(
7737: vm_map_entry_t entry,
7738: vm_object_t object)
7739: {
7740: register int ref_count;
7741: register vm_object_t chk_obj;
7742: register vm_object_t tmp_obj;
7743:
7744: if (entry->object.vm_object == 0)
7745: return(0);
7746:
7747: if (entry->is_sub_map)
7748: ref_count = vm_region_count_obj_refs((vm_map_entry_t)entry->object.sub_map, object);
7749: else {
7750: ref_count = 0;
7751:
7752: chk_obj = entry->object.vm_object;
7753: vm_object_lock(chk_obj);
7754:
7755: while (chk_obj) {
7756: if (chk_obj == object)
7757: ref_count++;
7758: if (tmp_obj = chk_obj->shadow)
7759: vm_object_lock(tmp_obj);
7760: vm_object_unlock(chk_obj);
7761:
7762: chk_obj = tmp_obj;
7763: }
7764: }
7765: return(ref_count);
7766: }
7767:
7768:
7769: /*
7770: * Routine: vm_map_simplify
7771: *
7772: * Description:
7773: * Attempt to simplify the map representation in
7774: * the vicinity of the given starting address.
7775: * Note:
7776: * This routine is intended primarily to keep the
7777: * kernel maps more compact -- they generally don't
7778: * benefit from the "expand a map entry" technology
7779: * at allocation time because the adjacent entry
7780: * is often wired down.
7781: */
7782: void
7783: vm_map_simplify(
7784: vm_map_t map,
7785: vm_offset_t start)
7786: {
7787: vm_map_entry_t this_entry;
7788: vm_map_entry_t prev_entry;
7789: vm_map_entry_t next_entry;
7790:
7791: vm_map_lock(map);
7792: if (
7793: (vm_map_lookup_entry(map, start, &this_entry)) &&
7794: ((prev_entry = this_entry->vme_prev) != vm_map_to_entry(map)) &&
7795:
7796: (prev_entry->vme_end == this_entry->vme_start) &&
7797:
7798: (prev_entry->is_shared == FALSE) &&
7799: (prev_entry->is_sub_map == FALSE) &&
7800:
7801: (this_entry->is_shared == FALSE) &&
7802: (this_entry->is_sub_map == FALSE) &&
7803:
7804: (prev_entry->inheritance == this_entry->inheritance) &&
7805: (prev_entry->protection == this_entry->protection) &&
7806: (prev_entry->max_protection == this_entry->max_protection) &&
7807: (prev_entry->behavior == this_entry->behavior) &&
7808: (prev_entry->wired_count == this_entry->wired_count) &&
7809: (prev_entry->user_wired_count == this_entry->user_wired_count)&&
7810: (prev_entry->in_transition == FALSE) &&
7811: (this_entry->in_transition == FALSE) &&
7812:
7813: (prev_entry->needs_copy == this_entry->needs_copy) &&
7814:
7815: (prev_entry->object.vm_object == this_entry->object.vm_object)&&
7816: ((prev_entry->offset +
7817: (prev_entry->vme_end - prev_entry->vme_start))
7818: == this_entry->offset)
7819: ) {
7820: SAVE_HINT(map, prev_entry);
7821: vm_map_entry_unlink(map, this_entry);
7822: prev_entry->vme_end = this_entry->vme_end;
7823: UPDATE_FIRST_FREE(map, map->first_free);
7824: vm_object_deallocate(this_entry->object.vm_object);
7825: vm_map_entry_dispose(map, this_entry);
7826: counter(c_vm_map_simplified_lower++);
7827: }
7828: if (
7829: (vm_map_lookup_entry(map, start, &this_entry)) &&
7830: ((next_entry = this_entry->vme_next) != vm_map_to_entry(map)) &&
7831:
7832: (next_entry->vme_start == this_entry->vme_end) &&
7833:
7834: (next_entry->is_shared == FALSE) &&
7835: (next_entry->is_sub_map == FALSE) &&
7836:
7837: (next_entry->is_shared == FALSE) &&
7838: (next_entry->is_sub_map == FALSE) &&
7839:
7840: (next_entry->inheritance == this_entry->inheritance) &&
7841: (next_entry->protection == this_entry->protection) &&
7842: (next_entry->max_protection == this_entry->max_protection) &&
7843: (next_entry->behavior == this_entry->behavior) &&
7844: (next_entry->wired_count == this_entry->wired_count) &&
7845: (next_entry->user_wired_count == this_entry->user_wired_count)&&
7846: (this_entry->in_transition == FALSE) &&
7847: (next_entry->in_transition == FALSE) &&
7848:
7849: (next_entry->needs_copy == this_entry->needs_copy) &&
7850:
7851: (next_entry->object.vm_object == this_entry->object.vm_object)&&
7852: ((this_entry->offset +
7853: (this_entry->vme_end - this_entry->vme_start))
7854: == next_entry->offset)
7855: ) {
7856: vm_map_entry_unlink(map, next_entry);
7857: this_entry->vme_end = next_entry->vme_end;
7858: UPDATE_FIRST_FREE(map, map->first_free);
7859: vm_object_deallocate(next_entry->object.vm_object);
7860: vm_map_entry_dispose(map, next_entry);
7861: counter(c_vm_map_simplified_upper++);
7862: }
7863: counter(c_vm_map_simplify_called++);
7864: vm_map_unlock(map);
7865: }
7866:
7867:
7868: /*
7869: * Routine: vm_map_machine_attribute
7870: * Purpose:
7871: * Provide machine-specific attributes to mappings,
7872: * such as cachability etc. for machines that provide
7873: * them. NUMA architectures and machines with big/strange
7874: * caches will use this.
7875: * Note:
7876: * Responsibilities for locking and checking are handled here,
7877: * everything else in the pmap module. If any non-volatile
7878: * information must be kept, the pmap module should handle
7879: * it itself. [This assumes that attributes do not
7880: * need to be inherited, which seems ok to me]
7881: */
7882: kern_return_t
7883: vm_map_machine_attribute(
7884: vm_map_t map,
7885: vm_offset_t address,
7886: vm_size_t size,
7887: vm_machine_attribute_t attribute,
7888: vm_machine_attribute_val_t* value) /* IN/OUT */
7889: {
7890: kern_return_t ret;
7891:
7892: if (address < vm_map_min(map) ||
7893: (address + size) > vm_map_max(map))
7894: return KERN_INVALID_ADDRESS;
7895:
7896: vm_map_lock(map);
7897:
7898: ret = pmap_attribute(map->pmap, address, size, attribute, value);
7899:
7900: vm_map_unlock(map);
7901:
7902: return ret;
7903: }
7904:
7905: /*
7906: * vm_map_behavior_set:
7907: *
7908: * Sets the paging reference behavior of the specified address
7909: * range in the target map. Paging reference behavior affects
7910: * how pagein operations resulting from faults on the map will be
7911: * clustered.
7912: */
7913: kern_return_t
7914: vm_map_behavior_set(
7915: vm_map_t map,
7916: vm_offset_t start,
7917: vm_offset_t end,
7918: vm_behavior_t new_behavior)
7919: {
7920: register vm_map_entry_t entry;
7921: vm_map_entry_t temp_entry;
7922:
7923: XPR(XPR_VM_MAP,
7924: "vm_map_behavior_set, 0x%X start 0x%X end 0x%X behavior %d",
7925: (integer_t)map, start, end, new_behavior, 0);
7926:
7927: switch (new_behavior) {
7928: case VM_BEHAVIOR_DEFAULT:
7929: case VM_BEHAVIOR_RANDOM:
7930: case VM_BEHAVIOR_SEQUENTIAL:
7931: case VM_BEHAVIOR_RSEQNTL:
7932: break;
7933: default:
7934: return(KERN_INVALID_ARGUMENT);
7935: }
7936:
7937: vm_map_lock(map);
7938:
7939: /*
7940: * The entire address range must be valid for the map.
7941: * Note that vm_map_range_check() does a
7942: * vm_map_lookup_entry() internally and returns the
7943: * entry containing the start of the address range if
7944: * the entire range is valid.
7945: */
7946: if (vm_map_range_check(map, start, end, &temp_entry)) {
7947: entry = temp_entry;
7948: vm_map_clip_start(map, entry, start);
7949: }
7950: else {
7951: vm_map_unlock(map);
7952: return(KERN_INVALID_ADDRESS);
7953: }
7954:
7955: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) {
7956: vm_map_clip_end(map, entry, end);
7957:
7958: entry->behavior = new_behavior;
7959:
7960: entry = entry->vme_next;
7961: }
7962:
7963: vm_map_unlock(map);
7964: return(KERN_SUCCESS);
7965: }
7966:
7967: #if DIPC
7968:
7969: /*
7970: * This should one day be eliminated;
7971: * we should always construct the right flavor of copy object
7972: * the first time. Troublesome areas include vm_read, where vm_map_copyin
7973: * is called without knowing whom the copy object is for.
7974: * There are also situations where we do want a lazy data structure
7975: * even if we are sending to a remote port...
7976: */
7977:
7978: extern kern_return_t vm_map_object_to_page_list(
7979: vm_map_copy_t *caller_copy);
7980:
7981: /*
7982: * Convert a copy to a page list. The copy argument is in/out
7983: * because we probably have to allocate a new vm_map_copy structure.
7984: * We take responsibility for discarding the old structure and
7985: * use a continuation to do so. Postponing this discard ensures
7986: * that the objects containing the pages we've marked busy will stick
7987: * around.
7988: *
7989: * N.B. For the entry list case, be warned that this routine steals
7990: * the pages from the entry list's objects!
7991: */
7992: kern_return_t
7993: vm_map_convert_to_page_list(
7994: vm_map_copy_t *caller_copy)
7995: {
7996: vm_map_entry_t entry;
7997: vm_offset_t va;
7998: vm_offset_t offset;
7999: vm_object_t object;
8000: vm_map_copy_t copy, new_copy;
8001: vm_size_t vm_copy_size;
8002: vm_prot_t result_prot;
8003: vm_page_t m, top_page;
8004: kern_return_t result;
8005: kern_return_t kr;
8006:
8007: copy = *caller_copy;
8008:
8009: /*
8010:
8011: * We may not have to do anything,
8012: * or may not be able to do anything.
8013: */
8014: if (copy == VM_MAP_COPY_NULL || copy->type == VM_MAP_COPY_PAGE_LIST) {
8015: return KERN_SUCCESS;
8016: }
8017: if (copy->type == VM_MAP_COPY_OBJECT) {
8018: return vm_map_object_to_page_list(caller_copy);
8019: }
8020: assert(copy->type == VM_MAP_COPY_ENTRY_LIST);
8021:
8022: /*
8023: * Check size. If this is really big, copy it out
8024: * to the kernel map, and copy in using src_destroy
8025: */
8026: vm_copy_size = round_page(copy->offset + copy->size) -
8027: trunc_page(copy->offset);
8028:
8029: if (vm_copy_size > (VM_MAP_COPY_PAGE_LIST_MAX * PAGE_SIZE)) {
8030: vm_size_t copy_size;
8031:
8032: offset = copy->offset;
8033: copy_size = copy->size;
8034: result = vm_map_copyout(kernel_map, &va, copy);
8035: assert(result == KERN_SUCCESS);
8036: va += offset - trunc_page(offset);
8037: result = vm_map_copyin_page_list(kernel_map, va, copy_size,
8038: (VM_MAP_COPYIN_OPT_SRC_DESTROY|
8039: VM_MAP_COPYIN_OPT_STEAL_PAGES|
8040: VM_PROT_READ),
8041: caller_copy, FALSE);
8042: return(result);
8043: }
8044:
8045: /*
8046: * Allocate the new copy. Set its continuation to
8047: * discard the old one.
8048: */
8049: new_copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
8050: new_copy->type = VM_MAP_COPY_PAGE_LIST;
8051: new_copy->cpy_npages = 0;
8052: new_copy->cpy_page_loose = FALSE;
8053: new_copy->offset = copy->offset;
8054: new_copy->size = copy->size;
8055: new_copy->cpy_cont = vm_map_copy_discard_cont;
8056: new_copy->cpy_cont_args = (vm_map_copyin_args_t) copy;
8057:
8058: /*
8059: * Iterate over entries.
8060: */
8061: for (entry = vm_map_copy_first_entry(copy);
8062: entry != vm_map_copy_to_entry(copy);
8063: entry = entry->vme_next) {
8064:
8065: object = entry->object.vm_object;
8066: offset = entry->offset;
8067: /*
8068: * Iterate over pages.
8069: */
8070: for (va = entry->vme_start;
8071: va < entry->vme_end;
8072: va += PAGE_SIZE, offset += PAGE_SIZE) {
8073:
8074: assert(new_copy->cpy_npages !=
8075: VM_MAP_COPY_PAGE_LIST_MAX);
8076:
8077: /*
8078: * If the object is null, this is
8079: * zero fill data.
8080: */
8081: if (object == VM_OBJECT_NULL) {
8082: while ((m = vm_page_grab()) == VM_PAGE_NULL) {
8083: VM_PAGE_WAIT();
8084: }
8085: vm_page_zero_fill(m);
8086: vm_page_gobble(m);
8087: new_copy->cpy_page_list[
8088: new_copy->cpy_npages++] = m;
8089: continue;
8090: }
8091:
8092: /*
8093: * Try to find the page of data.
8094: */
8095:
8096: vm_object_lock(object);
8097: if (((m = vm_page_lookup(object, offset)) !=
8098: VM_PAGE_NULL) && !m->busy && !m->fictitious &&
8099: !m->unusual) {
8100:
8101: /*
8102: * This is the page. Mark it busy.
8103: * Remove it from its old object.
8104: */
8105: m->busy = TRUE;
8106: vm_page_lock_queues();
8107: VM_PAGE_QUEUES_REMOVE(m);
8108: vm_page_remove(m);
8109: vm_page_unlock_queues();
8110: vm_object_unlock(object);
8111: new_copy->cpy_page_list[new_copy->cpy_npages++]
8112: = m;
8113: continue;
8114: }
8115:
8116: retry:
8117: result_prot = VM_PROT_READ;
8118: vm_object_paging_begin(object);
8119: XPR(XPR_VM_FAULT,
8120: "vm_map_convert_to_page_list -> vm_fault_page\n",
8121: 0,0,0,0,0);
8122: kr = vm_fault_page(object, offset,
8123: VM_PROT_READ, FALSE, THREAD_UNINT,
8124: entry->offset,
8125: entry->offset +
8126: (entry->vme_end -
8127: entry->vme_start),
8128: VM_BEHAVIOR_SEQUENTIAL,
8129: &result_prot, &m, &top_page,
8130: (int *)0,
8131: FALSE, FALSE, FALSE);
8132: if (kr == VM_FAULT_MEMORY_SHORTAGE) {
8133: VM_PAGE_WAIT();
8134: vm_object_lock(object);
8135: goto retry;
8136: }
8137: if (kr == VM_FAULT_FICTITIOUS_SHORTAGE) {
8138: vm_page_more_fictitious();
8139: vm_object_lock(object);
8140: goto retry;
8141: }
8142: if (kr != VM_FAULT_SUCCESS) {
8143: /* XXX what about data_error? */
8144: vm_object_lock(object);
8145: goto retry;
8146: }
8147:
8148: assert(m != VM_PAGE_NULL);
8149: m->busy = TRUE;
8150: vm_page_lock_queues();
8151: VM_PAGE_QUEUES_REMOVE(m);
8152: vm_page_remove(m);
8153: vm_page_unlock_queues();
8154: vm_object_paging_end(object);
8155: vm_object_unlock(object);
8156: new_copy->cpy_page_list[new_copy->cpy_npages++] = m;
8157:
8158: if (top_page != VM_PAGE_NULL) {
8159: assert(top_page->object == object);
8160: vm_object_lock(object);
8161: VM_PAGE_FREE(top_page);
8162: vm_object_paging_end(object);
8163: vm_object_unlock(object);
8164: }
8165: }
8166: }
8167:
8168: *caller_copy = new_copy;
8169: return KERN_SUCCESS;
8170: }
8171:
8172:
8173: /*
8174: * Continue converting pages from an object-flavor
8175: * copy object into a page-list flavor copy object.
8176: * The parameters in the copy object were updated
8177: * by the last invocation of vm_map_object_to_page_list
8178: * so there's no work to be done other than calling
8179: * back into that routine. Note that the contents
8180: * of the underlying object itself never change
8181: * during the conversion process.
8182: */
8183: kern_return_t
8184: vm_map_object_to_page_list_cont(
8185: vm_map_copy_t cont_args,
8186: vm_map_copy_t *copy_result) /* OUT */
8187: {
8188: boolean_t abort;
8189:
8190: abort = (copy_result == (vm_map_copy_t *) 0);
8191: if (abort) {
8192: printf("vm_map_object_to_page_list_cont: abort\n");
8193: vm_map_copy_discard(cont_args);
8194: }
8195:
8196: assert(cont_args->type == VM_MAP_COPY_OBJECT);
8197: *copy_result = cont_args;
8198: return vm_map_object_to_page_list(copy_result);
8199: }
8200:
8201:
8202: /*
8203: * Convert a copy object from object flavor to
8204: * page list flavor. For objects containing more
8205: * than the allowable maximum number of pages, we
8206: * perform the conversion a piece at a time.
8207: *
8208: * The object flavor copy object contains a vm_object_t
8209: * that has all the pages; the type, offset and size
8210: * fields always present in a vm_map_copy_t; and an
8211: * index field unique to the object flavor. This index
8212: * field MUST be zero when first calling this routine.
8213: * It is used to record progress converting pages from
8214: * the object to the page list.
8215: *
8216: * Assumptions:
8217: * - This routine always returns KERN_SUCCESS.
8218: */
8219: kern_return_t
8220: vm_map_object_to_page_list(
8221: vm_map_copy_t *caller_copy)
8222: {
8223: vm_object_t object;
8224: vm_offset_t offset;
8225: vm_map_copy_t copy, new_copy;
8226: vm_size_t index;
8227: vm_size_t copy_size;
8228: vm_page_t m;
8229: vm_prot_t result_prot;
8230: vm_page_t top_page;
8231: kern_return_t kr;
8232:
8233: assert(caller_copy != (vm_map_copy_t *) 0);
8234: assert(*caller_copy != VM_MAP_COPY_NULL);
8235: assert((*caller_copy)->type == VM_MAP_COPY_OBJECT);
8236:
8237: copy = *caller_copy;
8238: object = copy->cpy_object;
8239:
8240: /*
8241: * Allocate the new copy. Set its continuation to
8242: * discard the old one.
8243: */
8244: new_copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
8245: new_copy->type = VM_MAP_COPY_PAGE_LIST;
8246: new_copy->cpy_npages = 0;
8247: new_copy->cpy_page_loose = FALSE;
8248: new_copy->offset = copy->offset - trunc_page(copy->offset);
8249: new_copy->size = copy->size;
8250: assert((long)new_copy->size >= 0);
8251: if (new_copy->size == 0)
8252: printf("vm_object_to_page_list: zero size\n");
8253: new_copy->cpy_cont = vm_map_copy_discard_cont;
8254: new_copy->cpy_cont_args = (vm_map_copyin_args_t) copy;
8255:
8256: /*
8257: * Compute range of object to extract.
8258: */
8259: index = (vm_size_t)copy->cpy_index; /* XXX!XXX! */
8260: assert(copy->offset < page_size);
8261: copy_size = round_page(copy->offset + copy->size);
8262: assert(page_aligned(copy_size));
8263:
8264: /*
8265: * Detect an object larger than the maximum permitted
8266: * for an individual page list block. Save the rest
8267: * for later.
8268: */
8269: if (copy_size > VM_MAP_COPY_PAGE_LIST_MAX_SIZE) {
8270: /*
8271: * Only the first copy object in the chain
8272: * has the unaligned offset and total size.
8273: * Each succeeding copy object has an offset
8274: * of zero and a size decreased by the amount
8275: * contained in the previous copy object.
8276: * These values will be used when creating the
8277: * next page list copy object.
8278: *
8279: * Reset the continuation because there are
8280: * more pages left to extract.
8281: */
8282: assert(trunc_page(copy->offset) == 0);
8283: copy->size = copy->size -
8284: (VM_MAP_COPY_PAGE_LIST_MAX_SIZE - copy->offset);
8285: copy->offset = 0;
8286: copy_size = VM_MAP_COPY_PAGE_LIST_MAX_SIZE;
8287: new_copy->cpy_cont = (vm_map_copy_cont_t)
8288: vm_map_object_to_page_list_cont;
8289: assert(vm_map_copy_cont_is_valid(new_copy));
8290: }
8291:
8292: /*
8293: * Fault in all pages that aren't present.
8294: * Modelled on vm_map_copyin_page_list.
8295: */
8296: for (offset = index; offset < index + copy_size; offset += PAGE_SIZE) {
8297: vm_object_lock(object);
8298: vm_object_paging_begin(object);
8299:
8300: m = vm_page_lookup(object, offset);
8301: if ((m != VM_PAGE_NULL) && !m->busy && !m->fictitious &&
8302: !m->unusual) {
8303: m->busy = TRUE;
8304: } else {
8305: retry:
8306: result_prot = VM_PROT_READ;
8307: XPR(XPR_VM_FAULT,
8308: "vm_object_to_page_list -> vm_fault_page\n",
8309: 0,0,0,0,0);
8310: kr = vm_fault_page(object, offset,
8311: VM_PROT_READ, FALSE, THREAD_UNINT,
8312: offset, index + copy_size,/* XXX ? */
8313: VM_BEHAVIOR_SEQUENTIAL,
8314: &result_prot, &m, &top_page,
8315: (int *)0,
8316: 0, FALSE, FALSE);
8317: switch (kr) {
8318: case VM_FAULT_SUCCESS:
8319: break;
8320: case VM_FAULT_MEMORY_SHORTAGE:
8321: VM_PAGE_WAIT();
8322: vm_object_lock(object);
8323: vm_object_paging_begin(object);
8324: goto retry;
8325: case VM_FAULT_FICTITIOUS_SHORTAGE:
8326: vm_page_more_fictitious();
8327: /* fall through... */
8328: case VM_FAULT_INTERRUPTED:
8329: case VM_FAULT_RETRY:
8330: vm_object_lock(object);
8331: vm_object_paging_begin(object);
8332: goto retry;
8333: case VM_FAULT_MEMORY_ERROR:
8334: panic("vm_map_object_to_page_list");
8335: break;
8336: }
8337:
8338: if (top_page != VM_PAGE_NULL) {
8339: VM_PAGE_FREE(top_page);
8340: vm_object_paging_end(object);
8341: }
8342: }
8343:
8344: assert(m);
8345: assert(m->busy);
8346: /* assert(m->wire_count == 0); XXX */
8347:
8348: /*
8349: * Got the page. Save it in the page list
8350: * and rip it away from the object.
8351: */
8352: new_copy->cpy_page_list[new_copy->cpy_npages++] = m;
8353: vm_page_lock_queues();
8354: VM_PAGE_QUEUES_REMOVE(m);
8355: vm_page_remove(m);
8356: vm_page_unlock_queues();
8357:
8358: vm_object_paging_end(object);
8359: vm_object_unlock(object);
8360: }
8361:
8362: /*
8363: * Update index for next pass through the object.
8364: */
8365: copy->cpy_index += copy_size;
8366:
8367: *caller_copy = new_copy;
8368: assert(vm_map_copy_cont_is_valid(new_copy));
8369: return (KERN_SUCCESS);
8370: }
8371:
8372: /*
8373: * When allocating a new entry, vm_map_entry_list_from_object must
8374: * use the pageable v. non-pageable entry zone based on the
8375: * attribute of the map into which the entry will be pasted.
8376: * This information must be supplied by the caller, as there is
8377: * no way to obtain it from the object.
8378: *
8379: * N.B. Caller donates a reference.
8380: */
8381: vm_map_copy_t
8382: vm_map_entry_list_from_object(
8383: vm_object_t object,
8384: vm_offset_t offset,
8385: vm_size_t size,
8386: boolean_t pageable)
8387: {
8388: vm_map_entry_t new_entry;
8389: vm_map_copy_t copy;
8390:
8391: assert(object != VM_OBJECT_NULL);
8392: assert(size != 0);
8393:
8394: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone);
8395: assert(copy != VM_MAP_COPY_NULL);
8396:
8397: copy->type = VM_MAP_COPY_ENTRY_LIST;
8398: vm_map_copy_first_entry(copy) =
8399: vm_map_copy_last_entry(copy) = vm_map_copy_to_entry(copy);
8400: copy->cpy_hdr.nentries = 0;
8401: copy->cpy_hdr.entries_pageable = pageable;
8402: copy->offset = offset;
8403: copy->size = size;
8404:
8405: /*
8406: * Allocate and initialize an entry for the object.
8407: */
8408: new_entry = vm_map_copy_entry_create(copy);
8409: new_entry->vme_start = trunc_page(copy->offset);
8410: new_entry->vme_end = round_page(copy->offset + copy->size);
8411: new_entry->object.vm_object = object;
8412: new_entry->offset = offset;
8413: new_entry->is_shared = FALSE;
8414: new_entry->is_sub_map = FALSE;
8415: new_entry->needs_copy = FALSE;
8416: new_entry->protection = VM_PROT_DEFAULT;
8417: new_entry->max_protection = VM_PROT_ALL;
8418: new_entry->inheritance = VM_INHERIT_DEFAULT;
8419: new_entry->wired_count = 0;
8420: new_entry->user_wired_count = 0;
8421: new_entry->in_transition = FALSE;
8422:
8423: /*
8424: * Insert entry into copy object, and return.
8425: */
8426: vm_map_copy_entry_link(copy, vm_map_copy_last_entry(copy), new_entry);
8427: assert(copy->type == VM_MAP_COPY_ENTRY_LIST);
8428: return (copy);
8429: }
8430:
8431: /*
8432: * Convert a page list copy object to an entry list
8433: * flavor copy object.
8434: */
8435: kern_return_t
8436: vm_map_convert_to_entry_list(
8437: vm_map_copy_t copy,
8438: boolean_t pageable)
8439: {
8440: vm_object_t object;
8441: int i;
8442: vm_map_entry_t new_entry;
8443: vm_page_t *page_list;
8444: vm_map_copy_t cur_copy, new_copy;
8445: vm_offset_t offset;
8446: kern_return_t result;
8447:
8448: /*
8449: * Check type of copy object.
8450: */
8451: if (copy->type != VM_MAP_COPY_PAGE_LIST) {
8452: panic("vm_map_convert_to_entry_list 0x%x %d", copy, copy->type);
8453: }
8454:
8455: /*
8456: * Insert all the pages into a new object.
8457: */
8458: object = vm_object_allocate(round_page(copy->offset + copy->size) -
8459: trunc_page(copy->offset));
8460: offset = (vm_offset_t) 0;
8461: cur_copy = copy;
8462:
8463: while (cur_copy) {
8464:
8465: /*
8466: * Make sure the pages are loose. This may be
8467: * a "Can't Happen", but just to be safe ...
8468: */
8469: page_list = &cur_copy->cpy_page_list[0];
8470: if (!copy->cpy_page_loose)
8471: vm_map_copy_steal_pages(cur_copy);
8472:
8473: /*
8474: * Stuff this set of pages into the object, removing
8475: * them from the page list.
8476: */
8477: vm_object_lock(object);
8478: vm_page_lock_queues();
8479: for (i = 0; i < cur_copy->cpy_npages;
8480: i++, offset += PAGE_SIZE) {
8481: register vm_page_t m = *page_list;
8482:
8483: vm_page_insert(m, object, offset);
8484: m->busy = FALSE;
8485: m->dirty = TRUE;
8486: vm_page_activate(m);
8487: *page_list++ = VM_PAGE_NULL;
8488: }
8489: vm_page_unlock_queues();
8490: vm_object_unlock(object);
8491:
8492: /*
8493: * Invoke continuation if present.
8494: */
8495: if (vm_map_copy_has_cont(cur_copy)) {
8496: vm_map_copy_invoke_cont(cur_copy, &new_copy, &result);
8497:
8498: if (result != KERN_SUCCESS)
8499: panic("%s: %s",
8500: "vm_map_convert_to_entry_list",
8501: "continuation failure");
8502: } else {
8503: new_copy = VM_MAP_COPY_NULL;
8504: }
8505: if (cur_copy != copy)
8506: vm_map_copy_discard(cur_copy);
8507:
8508: cur_copy = new_copy;
8509: }
8510:
8511: /*
8512: * Change type of copy object
8513: */
8514: vm_map_copy_first_entry(copy) =
8515: vm_map_copy_last_entry(copy) = vm_map_copy_to_entry(copy);
8516: copy->type = VM_MAP_COPY_ENTRY_LIST;
8517: copy->cpy_hdr.nentries = 0;
8518: copy->cpy_hdr.entries_pageable = pageable;
8519:
8520: /*
8521: * Allocate and initialize an entry for object
8522: */
8523: new_entry = vm_map_copy_entry_create(copy);
8524: new_entry->vme_start = trunc_page(copy->offset);
8525: new_entry->vme_end = round_page(copy->offset + copy->size);
8526: new_entry->object.vm_object = object;
8527: new_entry->offset = 0;
8528: new_entry->is_shared = FALSE;
8529: new_entry->is_sub_map = FALSE;
8530: new_entry->needs_copy = FALSE;
8531: new_entry->protection = VM_PROT_DEFAULT;
8532: new_entry->max_protection = VM_PROT_ALL;
8533: new_entry->behavior = VM_BEHAVIOR_DEFAULT;
8534: new_entry->inheritance = VM_INHERIT_DEFAULT;
8535: new_entry->wired_count = 0;
8536: new_entry->user_wired_count = 0;
8537:
8538: /*
8539: * Insert entry into copy object, and return.
8540: */
8541: vm_map_copy_entry_link(copy, vm_map_copy_last_entry(copy), new_entry);
8542: return(KERN_SUCCESS);
8543: }
8544:
8545: #endif /* DIPC */
8546:
8547: int
8548: vm_map_copy_cont_is_valid(
8549: vm_map_copy_t copy)
8550: {
8551: vm_map_copy_cont_t cont;
8552:
8553: assert(copy->type == VM_MAP_COPY_PAGE_LIST);
8554: cont = copy->cpy_cont;
8555: if (
8556: cont != vm_map_copy_discard_cont &&
8557: cont != vm_map_copyin_page_list_cont ) {
8558: printf("vm_map_copy_cont_is_valid: bogus cont 0x%x\n", cont);
8559: assert((integer_t) cont == 0xdeadbeef);
8560: }
8561: return 1;
8562: }
8563:
8564: #include <mach_kdb.h>
8565: #if MACH_KDB
8566: #include <ddb/db_output.h>
8567: #include <vm/vm_print.h>
8568:
8569: #define printf db_printf
8570:
8571: /*
8572: * Forward declarations for internal functions.
8573: */
8574: extern void vm_map_links_print(
8575: struct vm_map_links *links);
8576:
8577: extern void vm_map_header_print(
8578: struct vm_map_header *header);
8579:
8580: extern void vm_map_entry_print(
8581: vm_map_entry_t entry);
8582:
8583: extern void vm_follow_entry(
8584: vm_map_entry_t entry);
8585:
8586: extern void vm_follow_map(
8587: vm_map_t map);
8588:
8589: /*
8590: * vm_map_links_print: [ debug ]
8591: */
8592: void
8593: vm_map_links_print(
8594: struct vm_map_links *links)
8595: {
8596: iprintf("prev=0x%x, next=0x%x, start=0x%x, end=0x%x\n",
8597: links->prev,
8598: links->next,
8599: links->start,
8600: links->end);
8601: }
8602:
8603: /*
8604: * vm_map_header_print: [ debug ]
8605: */
8606: void
8607: vm_map_header_print(
8608: struct vm_map_header *header)
8609: {
8610: vm_map_links_print(&header->links);
8611: iprintf("nentries=0x%x, %sentries_pageable\n",
8612: header->nentries,
8613: (header->entries_pageable ? "" : "!"));
8614: }
8615:
8616: /*
8617: * vm_follow_entry: [ debug ]
8618: */
8619: void
8620: vm_follow_entry(
8621: vm_map_entry_t entry)
8622: {
8623: extern int db_indent;
8624: int shadows;
8625:
8626: iprintf("map entry 0x%x:\n", entry);
8627:
8628: db_indent += 2;
8629:
8630: shadows = vm_follow_object(entry->object.vm_object);
8631: iprintf("Total objects : %d\n",shadows);
8632:
8633: db_indent -= 2;
8634: }
8635:
8636: /*
8637: * vm_map_entry_print: [ debug ]
8638: */
8639: void
8640: vm_map_entry_print(
8641: register vm_map_entry_t entry)
8642: {
8643: extern int db_indent;
8644: static char *inheritance_name[4] = { "share", "copy", "none", "?"};
8645: static char *behavior_name[4] = { "dflt", "rand", "seqtl", "rseqntl" };
8646:
8647: iprintf("map entry 0x%x:\n", entry);
8648:
8649: db_indent += 2;
8650:
8651: vm_map_links_print(&entry->links);
8652:
8653: iprintf("start=0x%x, end=0x%x, prot=%x/%x/%s\n",
8654: entry->vme_start,
8655: entry->vme_end,
8656: entry->protection,
8657: entry->max_protection,
8658: inheritance_name[(entry->inheritance & 0x3)]);
8659:
8660: iprintf("behavior=%s, wired_count=%d, user_wired_count=%d\n",
8661: behavior_name[(entry->behavior & 0x3)],
8662: entry->wired_count,
8663: entry->user_wired_count);
8664: iprintf("%sin_transition, %sneeds_wakeup\n",
8665: (entry->in_transition ? "" : "!"),
8666: (entry->needs_wakeup ? "" : "!"));
8667:
8668: if (entry->is_sub_map) {
8669: iprintf("submap=0x%x, offset=0x%x\n",
8670: entry->object.sub_map,
8671: entry->offset);
8672: } else {
8673: iprintf("object=0x%x, offset=0x%x, ",
8674: entry->object.vm_object,
8675: entry->offset);
8676: printf("%sis_shared, %sneeds_copy\n",
8677: (entry->is_shared ? "" : "!"),
8678: (entry->needs_copy ? "" : "!"));
8679: }
8680:
8681: db_indent -= 2;
8682: }
8683:
8684: /*
8685: * vm_follow_map: [ debug ]
8686: */
8687: void
8688: vm_follow_map(
8689: vm_map_t map)
8690: {
8691: register vm_map_entry_t entry;
8692: extern int db_indent;
8693:
8694: iprintf("task map 0x%x:\n", map);
8695:
8696: db_indent += 2;
8697:
8698: for (entry = vm_map_first_entry(map);
8699: entry && entry != vm_map_to_entry(map);
8700: entry = entry->vme_next) {
8701: vm_follow_entry(entry);
8702: }
8703:
8704: db_indent -= 2;
8705: }
8706:
8707: /*
8708: * vm_map_print: [ debug ]
8709: */
8710: void
8711: vm_map_print(
8712: register vm_map_t map)
8713: {
8714: register vm_map_entry_t entry;
8715: extern int db_indent;
8716: char *swstate;
8717:
8718: iprintf("task map 0x%x:\n", map);
8719:
8720: db_indent += 2;
8721:
8722: vm_map_header_print(&map->hdr);
8723:
8724: iprintf("pmap=0x%x, size=%d, ref=%d, hint=0x%x, first_free=0x%x\n",
8725: map->pmap,
8726: map->size,
8727: map->ref_count,
8728: map->hint,
8729: map->first_free);
8730:
8731: iprintf("%swait_for_space, %swiring_required, timestamp=%d\n",
8732: (map->wait_for_space ? "" : "!"),
8733: (map->wiring_required ? "" : "!"),
8734: map->timestamp);
8735:
8736: #if TASK_SWAPPER
8737: switch (map->sw_state) {
8738: case MAP_SW_IN:
8739: swstate = "SW_IN";
8740: break;
8741: case MAP_SW_OUT:
8742: swstate = "SW_OUT";
8743: break;
8744: default:
8745: swstate = "????";
8746: break;
8747: }
8748: iprintf("res=%d, sw_state=%s\n", map->res_count, swstate);
8749: #endif /* TASK_SWAPPER */
8750:
8751: for (entry = vm_map_first_entry(map);
8752: entry && entry != vm_map_to_entry(map);
8753: entry = entry->vme_next) {
8754: vm_map_entry_print(entry);
8755: }
8756:
8757: db_indent -= 2;
8758: }
8759:
8760: /*
8761: * Routine: vm_map_copy_print
8762: * Purpose:
8763: * Pretty-print a copy object for ddb.
8764: */
8765:
8766: void
8767: vm_map_copy_print(
8768: vm_map_copy_t copy)
8769: {
8770: extern int db_indent;
8771: int i, npages;
8772: vm_map_entry_t entry;
8773:
8774: printf("copy object 0x%x\n", copy);
8775:
8776: db_indent += 2;
8777:
8778: iprintf("type=%d", copy->type);
8779: switch (copy->type) {
8780: case VM_MAP_COPY_ENTRY_LIST:
8781: printf("[entry_list]");
8782: break;
8783:
8784: case VM_MAP_COPY_OBJECT:
8785: printf("[object]");
8786: break;
8787:
8788: case VM_MAP_COPY_PAGE_LIST:
8789: printf("[page_list]");
8790: break;
8791:
8792: case VM_MAP_COPY_KERNEL_BUFFER:
8793: printf("[kernel_buffer]");
8794: break;
8795:
8796: default:
8797: printf("[bad type]");
8798: break;
8799: }
8800: printf(", offset=0x%x", copy->offset);
8801: printf(", size=0x%x\n", copy->size);
8802:
8803: switch (copy->type) {
8804: case VM_MAP_COPY_ENTRY_LIST:
8805: vm_map_header_print(©->cpy_hdr);
8806: for (entry = vm_map_copy_first_entry(copy);
8807: entry && entry != vm_map_copy_to_entry(copy);
8808: entry = entry->vme_next) {
8809: vm_map_entry_print(entry);
8810: }
8811: break;
8812:
8813: case VM_MAP_COPY_OBJECT:
8814: iprintf("object=0x%x\n", copy->cpy_object);
8815: break;
8816:
8817: case VM_MAP_COPY_KERNEL_BUFFER:
8818: iprintf("kernel buffer=0x%x", copy->cpy_kdata);
8819: printf(", kalloc_size=0x%x\n", copy->cpy_kalloc_size);
8820: break;
8821:
8822: case VM_MAP_COPY_PAGE_LIST:
8823: iprintf("npages=%d", copy->cpy_npages);
8824: printf(", cont=%x", copy->cpy_cont);
8825: printf(", cont_args=%x\n", copy->cpy_cont_args);
8826: if (copy->cpy_npages < 0) {
8827: npages = 0;
8828: } else if (copy->cpy_npages > VM_MAP_COPY_PAGE_LIST_MAX) {
8829: npages = VM_MAP_COPY_PAGE_LIST_MAX;
8830: } else {
8831: npages = copy->cpy_npages;
8832: }
8833: iprintf("copy->cpy_page_list[0..%d] = {", npages);
8834: for (i = 0; i < npages - 1; i++) {
8835: printf("0x%x, ", copy->cpy_page_list[i]);
8836: }
8837: if (npages > 0) {
8838: printf("0x%x", copy->cpy_page_list[npages - 1]);
8839: }
8840: printf("}\n");
8841: break;
8842: }
8843:
8844: db_indent -=2;
8845: }
8846:
8847: /*
8848: * db_vm_map_total_size(map) [ debug ]
8849: *
8850: * return the total virtual size (in bytes) of the map
8851: */
8852: vm_size_t
8853: db_vm_map_total_size(
8854: vm_map_t map)
8855: {
8856: vm_map_entry_t entry;
8857: vm_size_t total;
8858:
8859: total = 0;
8860: for (entry = vm_map_first_entry(map);
8861: entry != vm_map_to_entry(map);
8862: entry = entry->vme_next) {
8863: total += entry->vme_end - entry->vme_start;
8864: }
8865:
8866: return total;
8867: }
8868:
8869: #endif /* MACH_KDB */
8870:
8871: /*
8872: * Routine: vm_map_entry_insert
8873: *
8874: * Descritpion: This routine inserts a new vm_entry in a locked map.
8875: */
8876: vm_map_entry_t
8877: vm_map_entry_insert(
8878: vm_map_t map,
8879: vm_map_entry_t insp_entry,
8880: vm_offset_t start,
8881: vm_offset_t end,
8882: vm_object_t object,
8883: vm_offset_t offset,
8884: boolean_t needs_copy,
8885: boolean_t is_shared,
8886: boolean_t in_transition,
8887: vm_prot_t cur_protection,
8888: vm_prot_t max_protection,
8889: vm_behavior_t behavior,
8890: vm_inherit_t inheritance,
8891: unsigned wired_count)
8892: {
8893: vm_map_entry_t new_entry;
8894:
8895: assert(insp_entry != (vm_map_entry_t)0);
8896:
8897: new_entry = vm_map_entry_create(map);
8898:
8899: new_entry->vme_start = start;
8900: new_entry->vme_end = end;
8901: assert(page_aligned(new_entry->vme_start));
8902: assert(page_aligned(new_entry->vme_end));
8903:
8904: new_entry->object.vm_object = object;
8905: new_entry->offset = offset;
8906: new_entry->is_shared = is_shared;
8907: new_entry->is_sub_map = FALSE;
8908: new_entry->needs_copy = needs_copy;
8909: new_entry->in_transition = in_transition;
8910: new_entry->needs_wakeup = FALSE;
8911: new_entry->inheritance = inheritance;
8912: new_entry->protection = cur_protection;
8913: new_entry->max_protection = max_protection;
8914: new_entry->behavior = behavior;
8915: new_entry->wired_count = wired_count;
8916: new_entry->user_wired_count = 0;
8917:
8918: /*
8919: * Insert the new entry into the list.
8920: */
8921:
8922: vm_map_entry_link(map, insp_entry, new_entry);
8923: map->size += end - start;
8924:
8925: /*
8926: * Update the free space hint and the lookup hint.
8927: */
8928:
8929: SAVE_HINT(map, new_entry);
8930: return new_entry;
8931: }
8932:
8933: /*
8934: * Routine: vm_remap_extract
8935: *
8936: * Descritpion: This routine returns a vm_entry list from a map.
8937: */
8938: kern_return_t
8939: vm_remap_extract(
8940: vm_map_t map,
8941: vm_offset_t addr,
8942: vm_size_t size,
8943: boolean_t copy,
8944: struct vm_map_header *map_header,
8945: vm_prot_t *cur_protection,
8946: vm_prot_t *max_protection,
8947: /* What, no behavior? */
8948: vm_inherit_t inheritance,
8949: boolean_t pageable)
8950: {
8951: kern_return_t result;
8952: vm_size_t mapped_size;
8953: vm_size_t tmp_size;
8954: vm_map_entry_t src_entry; /* result of last map lookup */
8955: vm_map_entry_t new_entry;
8956: vm_offset_t offset;
8957: vm_offset_t map_address;
8958: vm_offset_t src_start; /* start of entry to map */
8959: vm_offset_t src_end; /* end of region to be mapped */
8960: vm_object_t object;
8961: vm_map_version_t version;
8962: boolean_t src_needs_copy;
8963: boolean_t new_entry_needs_copy;
8964:
8965: assert(map != VM_MAP_NULL);
8966: assert(size != 0 && size == round_page(size));
8967: assert(inheritance == VM_INHERIT_NONE ||
8968: inheritance == VM_INHERIT_COPY ||
8969: inheritance == VM_INHERIT_SHARE);
8970:
8971: /*
8972: * Compute start and end of region.
8973: */
8974: src_start = trunc_page(addr);
8975: src_end = round_page(src_start + size);
8976:
8977: /*
8978: * Initialize map_header.
8979: */
8980: map_header->links.next = (struct vm_map_entry *)&map_header->links;
8981: map_header->links.prev = (struct vm_map_entry *)&map_header->links;
8982: map_header->nentries = 0;
8983: map_header->entries_pageable = pageable;
8984:
8985: *cur_protection = VM_PROT_ALL;
8986: *max_protection = VM_PROT_ALL;
8987:
8988: map_address = 0;
8989: mapped_size = 0;
8990: result = KERN_SUCCESS;
8991:
8992: /*
8993: * The specified source virtual space might correspond to
8994: * multiple map entries, need to loop on them.
8995: */
8996: vm_map_lock(map);
8997: while (mapped_size != size) {
8998: vm_size_t entry_size;
8999:
9000: /*
9001: * Find the beginning of the region.
9002: */
9003: if (! vm_map_lookup_entry(map, src_start, &src_entry)) {
9004: result = KERN_INVALID_ADDRESS;
9005: break;
9006: }
9007:
9008: if (src_start < src_entry->vme_start ||
9009: (mapped_size && src_start != src_entry->vme_start)) {
9010: result = KERN_INVALID_ADDRESS;
9011: break;
9012: }
9013:
9014: if(src_entry->is_sub_map) {
9015: result = KERN_INVALID_ADDRESS;
9016: break;
9017: }
9018:
9019: tmp_size = size - mapped_size;
9020: if (src_end > src_entry->vme_end)
9021: tmp_size -= (src_end - src_entry->vme_end);
9022:
9023: entry_size = (vm_size_t)(src_entry->vme_end -
9024: src_entry->vme_start);
9025:
9026: if(src_entry->is_sub_map) {
9027: vm_map_reference(src_entry->object.sub_map);
9028: } else {
9029: object = src_entry->object.vm_object;
9030:
9031: if (object == VM_OBJECT_NULL) {
9032: object = vm_object_allocate(entry_size);
9033: src_entry->offset = 0;
9034: src_entry->object.vm_object = object;
9035: } else if (object->copy_strategy !=
9036: MEMORY_OBJECT_COPY_SYMMETRIC) {
9037: /*
9038: * We are already using an asymmetric
9039: * copy, and therefore we already have
9040: * the right object.
9041: */
9042: assert(!src_entry->needs_copy);
9043: } else if (src_entry->needs_copy || object->shadowed ||
9044: (object->internal && !object->true_share &&
9045: !src_entry->is_shared &&
9046: object->size > entry_size)) {
9047:
9048: vm_object_shadow(&src_entry->object.vm_object,
9049: &src_entry->offset,
9050: entry_size);
9051:
9052: if (!src_entry->needs_copy &&
9053: (src_entry->protection & VM_PROT_WRITE)) {
9054: pmap_protect(vm_map_pmap(map),
9055: src_entry->vme_start,
9056: src_entry->vme_end,
9057: src_entry->protection &
9058: ~VM_PROT_WRITE);
9059: }
9060:
9061: object = src_entry->object.vm_object;
9062: src_entry->needs_copy = FALSE;
9063: }
9064:
9065:
9066: vm_object_lock(object);
9067: object->ref_count++; /* object ref. for new entry */
9068: VM_OBJ_RES_INCR(object);
9069: if (object->copy_strategy ==
9070: MEMORY_OBJECT_COPY_SYMMETRIC) {
9071: object->copy_strategy =
9072: MEMORY_OBJECT_COPY_DELAY;
9073: }
9074: vm_object_unlock(object);
9075: }
9076:
9077: offset = src_entry->offset + (src_start - src_entry->vme_start);
9078:
9079: new_entry = _vm_map_entry_create(map_header);
9080: vm_map_entry_copy(new_entry, src_entry);
9081:
9082: new_entry->vme_start = map_address;
9083: new_entry->vme_end = map_address + tmp_size;
9084: new_entry->inheritance = inheritance;
9085: new_entry->offset = offset;
9086:
9087: /*
9088: * The new region has to be copied now if required.
9089: */
9090: RestartCopy:
9091: if (!copy) {
9092: src_entry->is_shared = TRUE;
9093: new_entry->is_shared = TRUE;
9094: if (!(new_entry->is_sub_map))
9095: new_entry->needs_copy = FALSE;
9096:
9097: } else if (src_entry->is_sub_map) {
9098: /* make this a COW sub_map if not already */
9099: new_entry->needs_copy = TRUE;
9100: } else if (src_entry->wired_count == 0 &&
9101: vm_object_copy_quickly(&new_entry->object.vm_object,
9102: new_entry->offset,
9103: (new_entry->vme_end -
9104: new_entry->vme_start),
9105: &src_needs_copy,
9106: &new_entry_needs_copy)) {
9107:
9108: new_entry->needs_copy = new_entry_needs_copy;
9109: new_entry->is_shared = FALSE;
9110:
9111: /*
9112: * Handle copy_on_write semantics.
9113: */
9114: if (src_needs_copy && !src_entry->needs_copy) {
9115: vm_object_pmap_protect(object,
9116: offset,
9117: entry_size,
9118: (src_entry->is_shared ?
9119: PMAP_NULL : map->pmap),
9120: src_entry->vme_start,
9121: src_entry->protection &
9122: ~VM_PROT_WRITE);
9123:
9124: src_entry->needs_copy = TRUE;
9125: }
9126: /*
9127: * Throw away the old object reference of the new entry.
9128: */
9129: vm_object_deallocate(object);
9130:
9131: } else {
9132: new_entry->is_shared = FALSE;
9133:
9134: /*
9135: * The map can be safely unlocked since we
9136: * already hold a reference on the object.
9137: *
9138: * Record the timestamp of the map for later
9139: * verification, and unlock the map.
9140: */
9141: version.main_timestamp = map->timestamp;
9142: vm_map_unlock(map);
9143:
9144: /*
9145: * Perform the copy.
9146: */
9147: if (src_entry->wired_count > 0) {
9148: vm_object_lock(object);
9149: result = vm_object_copy_slowly(
9150: object,
9151: offset,
9152: entry_size,
9153: THREAD_UNINT,
9154: &new_entry->object.vm_object);
9155:
9156: new_entry->offset = 0;
9157: new_entry->needs_copy = FALSE;
9158: } else {
9159: result = vm_object_copy_strategically(
9160: object,
9161: offset,
9162: entry_size,
9163: &new_entry->object.vm_object,
9164: &new_entry->offset,
9165: &new_entry_needs_copy);
9166:
9167: new_entry->needs_copy = new_entry_needs_copy;
9168: }
9169:
9170: /*
9171: * Throw away the old object reference of the new entry.
9172: */
9173: vm_object_deallocate(object);
9174:
9175: if (result != KERN_SUCCESS &&
9176: result != KERN_MEMORY_RESTART_COPY) {
9177: _vm_map_entry_dispose(map_header, new_entry);
9178: break;
9179: }
9180:
9181: /*
9182: * Verify that the map has not substantially
9183: * changed while the copy was being made.
9184: */
9185:
9186: vm_map_lock(map); /* Increments timestamp once! */
9187: if (version.main_timestamp + 1 != map->timestamp) {
9188: /*
9189: * Simple version comparison failed.
9190: *
9191: * Retry the lookup and verify that the
9192: * same object/offset are still present.
9193: */
9194: vm_object_deallocate(new_entry->
9195: object.vm_object);
9196: _vm_map_entry_dispose(map_header, new_entry);
9197: if (result == KERN_MEMORY_RESTART_COPY)
9198: result = KERN_SUCCESS;
9199: continue;
9200: }
9201:
9202: if (result == KERN_MEMORY_RESTART_COPY) {
9203: vm_object_reference(object);
9204: goto RestartCopy;
9205: }
9206: }
9207:
9208: _vm_map_entry_link(map_header,
9209: map_header->links.prev, new_entry);
9210:
9211: *cur_protection &= src_entry->protection;
9212: *max_protection &= src_entry->max_protection;
9213:
9214: map_address += tmp_size;
9215: mapped_size += tmp_size;
9216: src_start += tmp_size;
9217:
9218: } /* end while */
9219:
9220: vm_map_unlock(map);
9221: if (result != KERN_SUCCESS) {
9222: /*
9223: * Free all allocated elements.
9224: */
9225: for (src_entry = map_header->links.next;
9226: src_entry != (struct vm_map_entry *)&map_header->links;
9227: src_entry = new_entry) {
9228: new_entry = src_entry->vme_next;
9229: _vm_map_entry_unlink(map_header, src_entry);
9230: vm_object_deallocate(src_entry->object.vm_object);
9231: _vm_map_entry_dispose(map_header, src_entry);
9232: }
9233: }
9234: return result;
9235: }
9236:
9237: /*
9238: * Routine: vm_remap
9239: *
9240: * Map portion of a task's address space.
9241: * Mapped region must not overlap more than
9242: * one vm memory object. Protections and
9243: * inheritance attributes remain the same
9244: * as in the original task and are out parameters.
9245: * Source and Target task can be identical
9246: * Other attributes are identical as for vm_map()
9247: */
9248: kern_return_t
9249: vm_remap(
9250: vm_map_t target_map,
9251: vm_offset_t *address,
9252: vm_size_t size,
9253: vm_offset_t mask,
9254: boolean_t anywhere,
9255: vm_map_t src_map,
9256: vm_offset_t memory_address,
9257: boolean_t copy,
9258: vm_prot_t *cur_protection,
9259: vm_prot_t *max_protection,
9260: vm_inherit_t inheritance)
9261: {
9262: kern_return_t result;
9263: vm_map_entry_t entry;
9264: vm_map_entry_t insp_entry;
9265: vm_map_entry_t new_entry;
9266: struct vm_map_header map_header;
9267:
9268: if (target_map == VM_MAP_NULL)
9269: return KERN_INVALID_ARGUMENT;
9270:
9271: switch (inheritance) {
9272: case VM_INHERIT_NONE:
9273: case VM_INHERIT_COPY:
9274: case VM_INHERIT_SHARE:
9275: if (size != 0 && src_map != VM_MAP_NULL)
9276: break;
9277: /*FALL THRU*/
9278: default:
9279: return KERN_INVALID_ARGUMENT;
9280: }
9281:
9282: size = round_page(size);
9283:
9284: result = vm_remap_extract(src_map, memory_address,
9285: size, copy, &map_header,
9286: cur_protection,
9287: max_protection,
9288: inheritance,
9289: target_map->hdr.
9290: entries_pageable);
9291: vm_map_deallocate(src_map);
9292:
9293: if (result != KERN_SUCCESS) {
9294: return result;
9295: }
9296:
9297: /*
9298: * Allocate/check a range of free virtual address
9299: * space for the target
9300: */
9301: *address = trunc_page(*address);
9302: vm_map_lock(target_map);
9303: result = vm_remap_range_allocate(target_map, address, size,
9304: mask, anywhere, &insp_entry);
9305:
9306: for (entry = map_header.links.next;
9307: entry != (struct vm_map_entry *)&map_header.links;
9308: entry = new_entry) {
9309: new_entry = entry->vme_next;
9310: _vm_map_entry_unlink(&map_header, entry);
9311: if (result == KERN_SUCCESS) {
9312: entry->vme_start += *address;
9313: entry->vme_end += *address;
9314: vm_map_entry_link(target_map, insp_entry, entry);
9315: insp_entry = entry;
9316: } else {
9317: if (!entry->is_sub_map) {
9318: vm_object_deallocate(entry->object.vm_object);
9319: } else {
9320: vm_map_deallocate(entry->object.sub_map);
9321: }
9322: _vm_map_entry_dispose(&map_header, entry);
9323: }
9324: }
9325:
9326: if (result == KERN_SUCCESS) {
9327: target_map->size += size;
9328: SAVE_HINT(target_map, insp_entry);
9329: }
9330: vm_map_unlock(target_map);
9331:
9332: if (result == KERN_SUCCESS && target_map->wiring_required)
9333: result = vm_map_wire(target_map, *address,
9334: *address + size, *cur_protection, TRUE);
9335: return result;
9336: }
9337:
9338: /*
9339: * Routine: vm_remap_range_allocate
9340: *
9341: * Description:
9342: * Allocate a range in the specified virtual address map.
9343: * returns the address and the map entry just before the allocated
9344: * range
9345: *
9346: * Map must be locked.
9347: */
9348:
9349: kern_return_t
9350: vm_remap_range_allocate(
9351: vm_map_t map,
9352: vm_offset_t *address, /* IN/OUT */
9353: vm_size_t size,
9354: vm_offset_t mask,
9355: boolean_t anywhere,
9356: vm_map_entry_t *map_entry) /* OUT */
9357: {
9358: register vm_map_entry_t entry;
9359: register vm_offset_t start;
9360: register vm_offset_t end;
9361: kern_return_t result = KERN_SUCCESS;
9362:
9363: StartAgain: ;
9364:
9365: start = *address;
9366:
9367: if (anywhere)
9368: {
9369: /*
9370: * Calculate the first possible address.
9371: */
9372:
9373: if (start < map->min_offset)
9374: start = map->min_offset;
9375: if (start > map->max_offset)
9376: return(KERN_NO_SPACE);
9377:
9378: /*
9379: * Look for the first possible address;
9380: * if there's already something at this
9381: * address, we have to start after it.
9382: */
9383:
9384: assert(first_free_is_valid(map));
9385: if (start == map->min_offset) {
9386: if ((entry = map->first_free) != vm_map_to_entry(map))
9387: start = entry->vme_end;
9388: } else {
9389: vm_map_entry_t tmp_entry;
9390: if (vm_map_lookup_entry(map, start, &tmp_entry))
9391: start = tmp_entry->vme_end;
9392: entry = tmp_entry;
9393: }
9394:
9395: /*
9396: * In any case, the "entry" always precedes
9397: * the proposed new region throughout the
9398: * loop:
9399: */
9400:
9401: while (TRUE) {
9402: register vm_map_entry_t next;
9403:
9404: /*
9405: * Find the end of the proposed new region.
9406: * Be sure we didn't go beyond the end, or
9407: * wrap around the address.
9408: */
9409:
9410: end = ((start + mask) & ~mask);
9411: if (end < start)
9412: return(KERN_NO_SPACE);
9413: start = end;
9414: end += size;
9415:
9416: if ((end > map->max_offset) || (end < start)) {
9417: if (map->wait_for_space) {
9418: if (size <= (map->max_offset -
9419: map->min_offset)) {
9420: assert_wait((event_t) map, THREAD_INTERRUPTIBLE);
9421: vm_map_unlock(map);
9422: thread_block((void (*)(void))0);
9423: vm_map_lock(map);
9424: goto StartAgain;
9425: }
9426: }
9427:
9428: return(KERN_NO_SPACE);
9429: }
9430:
9431: /*
9432: * If there are no more entries, we must win.
9433: */
9434:
9435: next = entry->vme_next;
9436: if (next == vm_map_to_entry(map))
9437: break;
9438:
9439: /*
9440: * If there is another entry, it must be
9441: * after the end of the potential new region.
9442: */
9443:
9444: if (next->vme_start >= end)
9445: break;
9446:
9447: /*
9448: * Didn't fit -- move to the next entry.
9449: */
9450:
9451: entry = next;
9452: start = entry->vme_end;
9453: }
9454: *address = start;
9455: } else {
9456: vm_map_entry_t temp_entry;
9457:
9458: /*
9459: * Verify that:
9460: * the address doesn't itself violate
9461: * the mask requirement.
9462: */
9463:
9464: if ((start & mask) != 0)
9465: return(KERN_NO_SPACE);
9466:
9467:
9468: /*
9469: * ... the address is within bounds
9470: */
9471:
9472: end = start + size;
9473:
9474: if ((start < map->min_offset) ||
9475: (end > map->max_offset) ||
9476: (start >= end)) {
9477: return(KERN_INVALID_ADDRESS);
9478: }
9479:
9480: /*
9481: * ... the starting address isn't allocated
9482: */
9483:
9484: if (vm_map_lookup_entry(map, start, &temp_entry))
9485: return(KERN_NO_SPACE);
9486:
9487: entry = temp_entry;
9488:
9489: /*
9490: * ... the next region doesn't overlap the
9491: * end point.
9492: */
9493:
9494: if ((entry->vme_next != vm_map_to_entry(map)) &&
9495: (entry->vme_next->vme_start < end))
9496: return(KERN_NO_SPACE);
9497: }
9498: *map_entry = entry;
9499: return(KERN_SUCCESS);
9500: }
9501:
9502: /*
9503: * vm_map_switch:
9504: *
9505: * Set the address map for the current thr_act to the specified map
9506: */
9507:
9508: vm_map_t
9509: vm_map_switch(
9510: vm_map_t map)
9511: {
9512: int mycpu;
9513: thread_act_t thr_act = current_act();
9514: vm_map_t oldmap = thr_act->map;
9515:
9516: mp_disable_preemption();
9517: mycpu = cpu_number();
9518:
9519: /*
9520: * Deactivate the current map and activate the requested map
9521: */
9522: PMAP_SWITCH_USER(thr_act, map, mycpu);
9523:
9524: mp_enable_preemption();
9525: return(oldmap);
9526: }
9527:
9528:
9529: /*
9530: * Routine: vm_map_write_user
9531: *
9532: * Description:
9533: * Copy out data from a kernel space into space in the
9534: * destination map. The space must already exist in the
9535: * destination map.
9536: * NOTE: This routine should only be called by threads
9537: * which can block on a page fault. i.e. kernel mode user
9538: * threads.
9539: *
9540: */
9541: kern_return_t
9542: vm_map_write_user(
9543: vm_map_t map,
9544: vm_offset_t src_addr,
9545: vm_offset_t dst_addr,
9546: vm_size_t size)
9547: {
9548: thread_act_t thr_act = current_act();
9549: kern_return_t kr = KERN_SUCCESS;
9550:
9551: if(thr_act->map == map) {
9552: if (copyout((char *)src_addr, (char *)dst_addr, size)) {
9553: kr = KERN_INVALID_ADDRESS;
9554: }
9555: } else {
9556: vm_map_t oldmap;
9557:
9558: /* take on the identity of the target map while doing */
9559: /* the transfer */
9560:
9561: vm_map_reference(map);
9562: oldmap = vm_map_switch(map);
9563: if (copyout((char *)src_addr, (char *)dst_addr, size)) {
9564: kr = KERN_INVALID_ADDRESS;
9565: }
9566: vm_map_switch(oldmap);
9567: vm_map_deallocate(map);
9568: }
9569: return kr;
9570: }
9571:
9572: /*
9573: * Routine: vm_map_read_user
9574: *
9575: * Description:
9576: * Copy in data from a user space source map into the
9577: * kernel map. The space must already exist in the
9578: * kernel map.
9579: * NOTE: This routine should only be called by threads
9580: * which can block on a page fault. i.e. kernel mode user
9581: * threads.
9582: *
9583: */
9584: kern_return_t
9585: vm_map_read_user(
9586: vm_map_t map,
9587: vm_offset_t src_addr,
9588: vm_offset_t dst_addr,
9589: vm_size_t size)
9590: {
9591: thread_act_t thr_act = current_act();
9592: kern_return_t kr = KERN_SUCCESS;
9593:
9594: if(thr_act->map == map) {
9595: if (copyin((char *)src_addr, (char *)dst_addr, size)) {
9596: kr = KERN_INVALID_ADDRESS;
9597: }
9598: } else {
9599: vm_map_t oldmap;
9600:
9601: /* take on the identity of the target map while doing */
9602: /* the transfer */
9603:
9604: vm_map_reference(map);
9605: oldmap = vm_map_switch(map);
9606: if (copyin((char *)src_addr, (char *)dst_addr, size)) {
9607: kr = KERN_INVALID_ADDRESS;
9608: }
9609: vm_map_switch(oldmap);
9610: vm_map_deallocate(map);
9611: }
9612: return kr;
9613: }
9614:
9615: /*
9616: * Export routines to other components for the things we access locally through
9617: * macros.
9618: */
9619: #undef current_map
9620: vm_map_t
9621: current_map(void)
9622: {
9623: return (current_map_fast());
9624: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.