|
|
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 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_user.c
54: * Author: Avadis Tevanian, Jr., Michael Wayne Young
55: *
56: * User-exported virtual memory functions.
57: */
58: #ifdef MACH_BSD
59: /* remove after component interface available */
60: extern int vnode_pager_workaround;
61: #endif
62:
63: #include <vm_cpm.h>
64: #include <mach/boolean.h>
65: #include <mach/kern_return.h>
66: #include <mach/mach_types.h> /* to get vm_address_t */
67: #include <mach/memory_object.h>
68: #include <mach/std_types.h> /* to get pointer_t */
69: #include <mach/vm_attributes.h>
70: #include <mach/vm_param.h>
71: #include <mach/vm_statistics.h>
72: #include <mach/vm_task_server.h>
73: #include <mach/mach_syscalls.h>
74: #include <mach/shared_memory_server.h>
75:
76: #include <kern/host.h>
77: #include <kern/task.h>
78: #include <kern/misc_protos.h>
79: #include <vm/vm_map.h>
80: #include <vm/vm_object.h>
81: #include <vm/vm_page.h>
82: #include <vm/memory_object.h>
83: #include <vm/vm_pageout.h>
84:
85:
86:
87: vm_size_t upl_offset_to_pagelist = 0;
88:
89: #if VM_CPM
90: #include <vm/cpm.h>
91: #endif /* VM_CPM */
92:
93: ipc_port_t dynamic_pager_control_port=NULL;
94:
95: /*
96: * vm_allocate allocates "zero fill" memory in the specfied
97: * map.
98: */
99: kern_return_t
100: vm_allocate(
101: register vm_map_t map,
102: register vm_offset_t *addr,
103: register vm_size_t size,
104: int flags)
105: {
106: kern_return_t result;
107: boolean_t anywhere = VM_FLAGS_ANYWHERE & flags;
108:
109: if (map == VM_MAP_NULL)
110: return(KERN_INVALID_ARGUMENT);
111: if (size == 0) {
112: *addr = 0;
113: return(KERN_SUCCESS);
114: }
115:
116: if (anywhere)
117: *addr = vm_map_min(map);
118: else
119: *addr = trunc_page(*addr);
120: size = round_page(size);
121:
122: result = vm_map_enter(
123: map,
124: addr,
125: size,
126: (vm_offset_t)0,
127: flags,
128: VM_OBJECT_NULL,
129: (vm_offset_t)0,
130: FALSE,
131: VM_PROT_DEFAULT,
132: VM_PROT_ALL,
133: VM_INHERIT_DEFAULT);
134:
135: return(result);
136: }
137:
138: /*
139: * vm_deallocate deallocates the specified range of addresses in the
140: * specified address map.
141: */
142: kern_return_t
143: vm_deallocate(
144: register vm_map_t map,
145: vm_offset_t start,
146: vm_size_t size)
147: {
148: if (map == VM_MAP_NULL)
149: return(KERN_INVALID_ARGUMENT);
150:
151: if (size == (vm_offset_t) 0)
152: return(KERN_SUCCESS);
153:
154: return(vm_map_remove(map, trunc_page(start),
155: round_page(start+size), VM_MAP_NO_FLAGS));
156: }
157:
158: /*
159: * vm_inherit sets the inheritance of the specified range in the
160: * specified map.
161: */
162: kern_return_t
163: vm_inherit(
164: register vm_map_t map,
165: vm_offset_t start,
166: vm_size_t size,
167: vm_inherit_t new_inheritance)
168: {
169: if (map == VM_MAP_NULL)
170: return(KERN_INVALID_ARGUMENT);
171:
172: if (new_inheritance > VM_INHERIT_LAST_VALID)
173: return(KERN_INVALID_ARGUMENT);
174:
175: return(vm_map_inherit(map,
176: trunc_page(start),
177: round_page(start+size),
178: new_inheritance));
179: }
180:
181: /*
182: * vm_protect sets the protection of the specified range in the
183: * specified map.
184: */
185:
186: kern_return_t
187: vm_protect(
188: register vm_map_t map,
189: vm_offset_t start,
190: vm_size_t size,
191: boolean_t set_maximum,
192: vm_prot_t new_protection)
193: {
194: if ((map == VM_MAP_NULL) || (new_protection & ~VM_PROT_ALL))
195: return(KERN_INVALID_ARGUMENT);
196:
197: return(vm_map_protect(map,
198: trunc_page(start),
199: round_page(start+size),
200: new_protection,
201: set_maximum));
202: }
203:
204: /*
205: * Handle machine-specific attributes for a mapping, such
206: * as cachability, migrability, etc.
207: */
208: kern_return_t
209: vm_machine_attribute(
210: vm_map_t map,
211: vm_address_t address,
212: vm_size_t size,
213: vm_machine_attribute_t attribute,
214: vm_machine_attribute_val_t* value) /* IN/OUT */
215: {
216: if (map == VM_MAP_NULL)
217: return(KERN_INVALID_ARGUMENT);
218:
219: return vm_map_machine_attribute(map, address, size, attribute, value);
220: }
221:
222: kern_return_t
223: vm_read(
224: vm_map_t map,
225: vm_address_t address,
226: vm_size_t size,
227: pointer_t *data,
228: mach_msg_type_number_t *data_size)
229: {
230: kern_return_t error;
231: vm_map_copy_t ipc_address;
232:
233: if (map == VM_MAP_NULL)
234: return(KERN_INVALID_ARGUMENT);
235:
236: if ((error = vm_map_copyin(map,
237: address,
238: size,
239: FALSE, /* src_destroy */
240: &ipc_address)) == KERN_SUCCESS) {
241: *data = (pointer_t) ipc_address;
242: *data_size = size;
243: }
244: return(error);
245: }
246:
247: kern_return_t
248: vm_read_list(
249: vm_map_t map,
250: vm_read_entry_t data_list,
251: mach_msg_type_number_t count)
252: {
253: mach_msg_type_number_t i;
254: kern_return_t error;
255: vm_map_copy_t ipc_address;
256:
257: if (map == VM_MAP_NULL)
258: return(KERN_INVALID_ARGUMENT);
259:
260: for(i=0; i<count; i++) {
261: error = vm_map_copyin(map,
262: data_list[i].address,
263: data_list[i].size,
264: FALSE, /* src_destroy */
265: &ipc_address);
266: if(error != KERN_SUCCESS) {
267: data_list[i].address = (vm_address_t)0;
268: data_list[i].size = (vm_size_t)0;
269: break;
270: }
271: if(data_list[i].size != 0) {
272: error = vm_map_copyout(current_task()->map,
273: &(data_list[i].address),
274: (vm_map_copy_t) ipc_address);
275: if(error != KERN_SUCCESS) {
276: data_list[i].address = (vm_address_t)0;
277: data_list[i].size = (vm_size_t)0;
278: break;
279: }
280: }
281: }
282: return(error);
283: }
284:
285: /*
286: * This routine reads from the specified map and overwrites part of the current
287: * activation's map. In making an assumption that the current thread is local,
288: * it is no longer cluster-safe without a fully supportive local proxy thread/
289: * task (but we don't support cluster's anymore so this is moot).
290: */
291:
292: #define VM_OVERWRITE_SMALL 512
293:
294: kern_return_t
295: vm_read_overwrite(
296: vm_map_t map,
297: vm_address_t address,
298: vm_size_t size,
299: vm_address_t data,
300: vm_size_t *data_size)
301: {
302: struct {
303: long align;
304: char buf[VM_OVERWRITE_SMALL];
305: } inbuf;
306: vm_map_t oldmap;
307: kern_return_t error = KERN_SUCCESS;
308: vm_map_copy_t copy;
309:
310: if (map == VM_MAP_NULL)
311: return(KERN_INVALID_ARGUMENT);
312:
313: if (size <= VM_OVERWRITE_SMALL) {
314: if(vm_map_read_user(map, (vm_offset_t)address,
315: (vm_offset_t)&inbuf, size)) {
316: error = KERN_INVALID_ADDRESS;
317: } else {
318: if(vm_map_write_user(current_map(),
319: (vm_offset_t)&inbuf, (vm_offset_t)data, size))
320: error = KERN_INVALID_ADDRESS;
321: }
322: }
323: else {
324: if ((error = vm_map_copyin(map,
325: address,
326: size,
327: FALSE, /* src_destroy */
328: ©)) == KERN_SUCCESS) {
329: if ((error = vm_map_copy_overwrite(
330: current_act()->map,
331: data,
332: copy,
333: FALSE)) == KERN_SUCCESS) {
334: }
335: else {
336: vm_map_copy_discard(copy);
337: }
338: }
339: }
340: *data_size = size;
341: return(error);
342: }
343:
344:
345:
346:
347: /*ARGSUSED*/
348: kern_return_t
349: vm_write(
350: vm_map_t map,
351: vm_address_t address,
352: vm_offset_t data,
353: mach_msg_type_number_t size)
354: {
355: if (map == VM_MAP_NULL)
356: return KERN_INVALID_ARGUMENT;
357:
358: return vm_map_copy_overwrite(map, address, (vm_map_copy_t) data,
359: FALSE /* interruptible XXX */);
360: }
361:
362: kern_return_t
363: vm_copy(
364: vm_map_t map,
365: vm_address_t source_address,
366: vm_size_t size,
367: vm_address_t dest_address)
368: {
369: vm_map_copy_t copy;
370: kern_return_t kr;
371:
372: if (map == VM_MAP_NULL)
373: return KERN_INVALID_ARGUMENT;
374:
375: kr = vm_map_copyin(map, source_address, size,
376: FALSE, ©);
377: if (kr != KERN_SUCCESS)
378: return kr;
379:
380: kr = vm_map_copy_overwrite(map, dest_address, copy,
381: FALSE /* interruptible XXX */);
382: if (kr != KERN_SUCCESS) {
383: vm_map_copy_discard(copy);
384: return kr;
385: }
386:
387: return KERN_SUCCESS;
388: }
389:
390: /*
391: * Routine: vm_map
392: */
393: kern_return_t
394: vm_map(
395: vm_map_t target_map,
396: vm_offset_t *address,
397: vm_size_t size,
398: vm_offset_t mask,
399: int flags,
400: ipc_port_t port,
401: vm_offset_t offset,
402: boolean_t copy,
403: vm_prot_t cur_protection,
404: vm_prot_t max_protection,
405: vm_inherit_t inheritance)
406: {
407: register
408: vm_object_t object;
409: vm_prot_t prot;
410: kern_return_t result;
411:
412: /*
413: * Check arguments for validity
414: */
415: if ((target_map == VM_MAP_NULL) ||
416: (cur_protection & ~VM_PROT_ALL) ||
417: (max_protection & ~VM_PROT_ALL) ||
418: (inheritance > VM_INHERIT_LAST_VALID) ||
419: size == 0)
420: return(KERN_INVALID_ARGUMENT);
421:
422: /*
423: * Find the vm object (if any) corresponding to this port.
424: */
425: if (!IP_VALID(port)) {
426: object = VM_OBJECT_NULL;
427: offset = 0;
428: copy = FALSE;
429: } else if (ip_kotype(port) == IKOT_NAMED_ENTRY) {
430: vm_named_entry_t named_entry;
431:
432: named_entry = (vm_named_entry_t)port->ip_kobject;
433: /* a few checks to make sure user is obeying rules */
434: if(size == 0)
435: size = named_entry->size;
436: if((named_entry->protection & max_protection) != max_protection)
437: return(KERN_INVALID_RIGHT);
438: if((named_entry->protection & cur_protection) != cur_protection)
439: return(KERN_INVALID_RIGHT);
440: if(named_entry->size < (offset + size))
441: return(KERN_INVALID_ARGUMENT);
442:
443: /* the callers parameter offset is defined to be the */
444: /* offset from beginning of named entry offset in object */
445: offset = offset + named_entry->offset;
446:
447: named_entry_lock(named_entry);
448: if(named_entry->is_sub_map) {
449: vm_map_entry_t map_entry;
450:
451: named_entry_unlock(named_entry);
452: *address = trunc_page(*address);
453: size = round_page(size);
454: vm_object_reference(vm_submap_object);
455: if ((result = vm_map_enter(target_map,
456: address, size, mask, flags,
457: vm_submap_object, 0,
458: FALSE,
459: cur_protection, max_protection, inheritance
460: )) != KERN_SUCCESS) {
461: vm_object_deallocate(vm_submap_object);
462: } else {
463: vm_map_submap(target_map, *address,
464: (*address) + size,
465: named_entry->backing.map,
466: offset);
467: if(copy) {
468: if(vm_map_lookup_entry(
469: target_map, *address, &map_entry)) {
470: map_entry->needs_copy = TRUE;
471: }
472: }
473: }
474: return(result);
475:
476: } else if(named_entry->object) {
477: /* This is the case where we are going to map */
478: /* an already mapped object. If the object is */
479: /* not ready it is internal. An external */
480: /* object cannot be mapped until it is ready */
481: /* we can therefore avoid the ready check */
482: /* in this case. */
483: copy = FALSE;
484: named_entry_unlock(named_entry);
485: vm_object_reference(named_entry->object);
486: object = named_entry->object;
487: } else {
488: object = vm_object_enter(named_entry->backing.pager,
489: named_entry->size,
490: named_entry->internal,
491: FALSE);
492: if (object == VM_OBJECT_NULL) {
493: named_entry_unlock(named_entry);
494: return(KERN_INVALID_OBJECT);
495: }
496: named_entry->object = object;
497: named_entry_unlock(named_entry);
498: /* create an extra reference for the named entry */
499: vm_object_reference(named_entry->object);
500: /* wait for object (if any) to be ready */
501: if (object != VM_OBJECT_NULL) {
502: vm_object_lock(object);
503: while (!object->pager_ready) {
504: vm_object_wait(object,
505: VM_OBJECT_EVENT_PAGER_READY,
506: THREAD_UNINT);
507: vm_object_lock(object);
508: }
509: vm_object_unlock(object);
510: }
511: }
512: } else {
513: if ((object = vm_object_enter(port, size, FALSE, FALSE))
514: == VM_OBJECT_NULL)
515: return(KERN_INVALID_OBJECT);
516:
517: /* wait for object (if any) to be ready */
518: if (object != VM_OBJECT_NULL) {
519: vm_object_lock(object);
520: while (!object->pager_ready) {
521: vm_object_wait(object,
522: VM_OBJECT_EVENT_PAGER_READY,
523: THREAD_UNINT);
524: vm_object_lock(object);
525: }
526: vm_object_unlock(object);
527: }
528: }
529:
530: *address = trunc_page(*address);
531: size = round_page(size);
532:
533: /*
534: * Perform the copy if requested
535: */
536:
537: if (copy) {
538: vm_object_t new_object;
539: vm_offset_t new_offset;
540:
541: result = vm_object_copy_strategically(object, offset, size,
542: &new_object, &new_offset,
543: ©);
544:
545:
546: if (result == KERN_MEMORY_RESTART_COPY) {
547: boolean_t success;
548: boolean_t src_needs_copy;
549:
550: /*
551: * XXX
552: * We currently ignore src_needs_copy.
553: * This really is the issue of how to make
554: * MEMORY_OBJECT_COPY_SYMMETRIC safe for
555: * non-kernel users to use. Solution forthcoming.
556: * In the meantime, since we don't allow non-kernel
557: * memory managers to specify symmetric copy,
558: * we won't run into problems here.
559: */
560: new_object = object;
561: new_offset = offset;
562: success = vm_object_copy_quickly(&new_object,
563: new_offset, size,
564: &src_needs_copy,
565: ©);
566: assert(success);
567: result = KERN_SUCCESS;
568: }
569: /*
570: * Throw away the reference to the
571: * original object, as it won't be mapped.
572: */
573:
574: vm_object_deallocate(object);
575:
576: if (result != KERN_SUCCESS)
577: return (result);
578:
579: object = new_object;
580: offset = new_offset;
581: }
582:
583: if ((result = vm_map_enter(target_map,
584: address, size, mask, flags,
585: object, offset,
586: copy,
587: cur_protection, max_protection, inheritance
588: )) != KERN_SUCCESS)
589: vm_object_deallocate(object);
590: return(result);
591: }
592:
593:
594: /*
595: * NOTE: this routine (and this file) will no longer require mach_host_server.h
596: * when vm_wire is changed to use ledgers.
597: */
598: #include <mach/mach_host_server.h>
599: /*
600: * Specify that the range of the virtual address space
601: * of the target task must not cause page faults for
602: * the indicated accesses.
603: *
604: * [ To unwire the pages, specify VM_PROT_NONE. ]
605: */
606: kern_return_t
607: vm_wire(
608: host_t host,
609: register vm_map_t map,
610: vm_offset_t start,
611: vm_size_t size,
612: vm_prot_t access)
613: {
614: kern_return_t rc;
615:
616: if (host == HOST_NULL)
617: return KERN_INVALID_HOST;
618:
619: if (map == VM_MAP_NULL)
620: return KERN_INVALID_TASK;
621:
622: if (access & ~VM_PROT_ALL)
623: return KERN_INVALID_ARGUMENT;
624:
625: if (access != VM_PROT_NONE) {
626: rc = vm_map_wire(map, trunc_page(start),
627: round_page(start+size), access, TRUE);
628: } else {
629: rc = vm_map_unwire(map, trunc_page(start),
630: round_page(start+size), TRUE);
631: }
632: return rc;
633: }
634:
635: /*
636: * vm_msync
637: *
638: * Synchronises the memory range specified with its backing store
639: * image by either flushing or cleaning the contents to the appropriate
640: * memory manager engaging in a memory object synchronize dialog with
641: * the manager. The client doesn't return until the manager issues
642: * m_o_s_completed message. MIG Magically converts user task parameter
643: * to the task's address map.
644: *
645: * interpretation of sync_flags
646: * VM_SYNC_INVALIDATE - discard pages, only return precious
647: * pages to manager.
648: *
649: * VM_SYNC_INVALIDATE & (VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS)
650: * - discard pages, write dirty or precious
651: * pages back to memory manager.
652: *
653: * VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS
654: * - write dirty or precious pages back to
655: * the memory manager.
656: *
657: * NOTE
658: * The memory object attributes have not yet been implemented, this
659: * function will have to deal with the invalidate attribute
660: *
661: * RETURNS
662: * KERN_INVALID_TASK Bad task parameter
663: * KERN_INVALID_ARGUMENT both sync and async were specified.
664: * KERN_SUCCESS The usual.
665: */
666:
667: kern_return_t
668: vm_msync(
669: vm_map_t map,
670: vm_address_t address,
671: vm_size_t size,
672: vm_sync_t sync_flags)
673: {
674: msync_req_t msr;
675: msync_req_t new_msr;
676: queue_chain_t req_q; /* queue of requests for this msync */
677: vm_map_entry_t entry;
678: vm_size_t amount_left;
679: vm_offset_t offset;
680: boolean_t do_sync_req;
681: boolean_t modifiable;
682:
683:
684: if ((sync_flags & VM_SYNC_ASYNCHRONOUS) &&
685: (sync_flags & VM_SYNC_SYNCHRONOUS))
686: return(KERN_INVALID_ARGUMENT);
687:
688: /*
689: * align address and size on page boundaries
690: */
691: size = round_page(address + size) - trunc_page(address);
692: address = trunc_page(address);
693:
694: if (map == VM_MAP_NULL)
695: return(KERN_INVALID_TASK);
696:
697: if (size == 0)
698: return(KERN_SUCCESS);
699:
700: queue_init(&req_q);
701: amount_left = size;
702:
703: while (amount_left > 0) {
704: vm_size_t flush_size;
705: vm_object_t object;
706:
707: vm_map_lock(map);
708: if (!vm_map_lookup_entry(map, address, &entry)) {
709: vm_size_t skip;
710:
711: /*
712: * hole in the address map.
713: */
714:
715: /*
716: * Check for empty map.
717: */
718: if (entry == vm_map_to_entry(map) &&
719: entry->vme_next == entry) {
720: vm_map_unlock(map);
721: break;
722: }
723: /*
724: * Check that we don't wrap and that
725: * we have at least one real map entry.
726: */
727: if ((map->hdr.nentries == 0) ||
728: (entry->vme_next->vme_start < address)) {
729: vm_map_unlock(map);
730: break;
731: }
732: /*
733: * Move up to the next entry if needed
734: */
735: skip = (entry->vme_next->vme_start - address);
736: if (skip >= amount_left)
737: amount_left = 0;
738: else
739: amount_left -= skip;
740: address = entry->vme_next->vme_start;
741: vm_map_unlock(map);
742: continue;
743: }
744:
745: offset = address - entry->vme_start;
746:
747: /*
748: * do we have more to flush than is contained in this
749: * entry ?
750: */
751: if (amount_left + entry->vme_start + offset > entry->vme_end) {
752: flush_size = entry->vme_end -
753: (entry->vme_start + offset);
754: } else {
755: flush_size = amount_left;
756: }
757: amount_left -= flush_size;
758: address += flush_size;
759:
760: object = entry->object.vm_object;
761:
762: /*
763: * We can't sync this object if the object has not been
764: * created yet
765: */
766: if (object == VM_OBJECT_NULL) {
767: vm_map_unlock(map);
768: continue;
769: }
770: offset += entry->offset;
771: modifiable = (entry->protection & VM_PROT_WRITE)
772: != VM_PROT_NONE;
773:
774: vm_object_lock(object);
775:
776: if (sync_flags & VM_SYNC_KILLPAGES) {
777: if (object->ref_count == 1 && !object->shadow && !entry->needs_copy)
778: memory_object_kill_pages(object, offset, flush_size);
779:
780: vm_object_unlock(object);
781: vm_map_unlock(map);
782: continue;
783: }
784: /*
785: * We can't sync this object if there isn't a pager.
786: * Don't bother to sync internal objects, since there can't
787: * be any "permanent" storage for these objects anyway.
788: */
789: if ((object->pager == IP_NULL) || (object->internal) ||
790: (object->private)) {
791: vm_object_unlock(object);
792: vm_map_unlock(map);
793: continue;
794: }
795: /*
796: * keep reference on the object until syncing is done
797: */
798: assert(object->ref_count > 0);
799: object->ref_count++;
800: vm_object_res_reference(object);
801: vm_object_unlock(object);
802:
803: vm_map_unlock(map);
804:
805: do_sync_req = memory_object_sync(object,
806: offset,
807: flush_size,
808: sync_flags & VM_SYNC_INVALIDATE,
809: (modifiable &&
810: (sync_flags & VM_SYNC_SYNCHRONOUS ||
811: sync_flags & VM_SYNC_ASYNCHRONOUS)));
812:
813: /*
814: * only send a m_o_s if we returned pages or if the entry
815: * is writable (ie dirty pages may have already been sent back)
816: */
817: if (!do_sync_req && !modifiable) {
818: vm_object_deallocate(object);
819: continue;
820: }
821: msync_req_alloc(new_msr);
822:
823: vm_object_lock(object);
824: offset += object->paging_offset;
825:
826: new_msr->offset = offset;
827: new_msr->length = flush_size;
828: new_msr->object = object;
829: new_msr->flag = VM_MSYNC_SYNCHRONIZING;
830: re_iterate:
831: queue_iterate(&object->msr_q, msr, msync_req_t, msr_q) {
832: /*
833: * need to check for overlapping entry, if found, wait
834: * on overlapping msr to be done, then reiterate
835: */
836: msr_lock(msr);
837: if (msr->flag == VM_MSYNC_SYNCHRONIZING &&
838: ((offset >= msr->offset &&
839: offset < (msr->offset + msr->length)) ||
840: (msr->offset >= offset &&
841: msr->offset < (offset + flush_size))))
842: {
843: assert_wait((event_t) msr,THREAD_INTERRUPTIBLE);
844: msr_unlock(msr);
845: vm_object_unlock(object);
846: thread_block((void (*)(void))0);
847: if (current_act()->handlers)
848: act_execute_returnhandlers();
849: vm_object_lock(object);
850: goto re_iterate;
851: }
852: msr_unlock(msr);
853: }/* queue_iterate */
854:
855: queue_enter(&object->msr_q, new_msr, msync_req_t, msr_q);
856: vm_object_unlock(object);
857:
858: queue_enter(&req_q, new_msr, msync_req_t, req_q);
859:
860: #ifdef MACH_BSD
861: if(((rpc_subsystem_t)pager_mux_hash_lookup(object->pager)) ==
862: ((rpc_subsystem_t) &vnode_pager_workaround)) {
863: (void) vnode_pager_synchronize(
864: object->pager,
865: object->pager_request,
866: offset,
867: flush_size,
868: sync_flags);
869: } else {
870: (void) memory_object_synchronize(
871: object->pager,
872: object->pager_request,
873: offset,
874: flush_size,
875: sync_flags);
876: }
877: #else
878: (void) memory_object_synchronize(
879: object->pager,
880: object->pager_request,
881: offset,
882: flush_size,
883: sync_flags);
884: #endif
885: }/* while */
886:
887: /*
888: * wait for memory_object_sychronize_completed messages from pager(s)
889: */
890:
891: while (!queue_empty(&req_q)) {
892: msr = (msync_req_t)queue_first(&req_q);
893: msr_lock(msr);
894: while(msr->flag != VM_MSYNC_DONE) {
895: assert_wait((event_t) msr, THREAD_INTERRUPTIBLE);
896: msr_unlock(msr);
897: thread_block((void (*)(void))0);
898: if (current_act()->handlers)
899: act_execute_returnhandlers();
900: msr_lock(msr);
901: }/* while */
902: queue_remove(&req_q, msr, msync_req_t, req_q);
903: msr_unlock(msr);
904: vm_object_deallocate(msr->object);
905: msync_req_free(msr);
906: }/* queue_iterate */
907:
908: return(KERN_SUCCESS);
909: }/* vm_msync */
910:
911:
912: /*
913: * task_wire
914: *
915: * Set or clear the map's wiring_required flag. This flag, if set,
916: * will cause all future virtual memory allocation to allocate
917: * user wired memory. Unwiring pages wired down as a result of
918: * this routine is done with the vm_wire interface.
919: */
920: kern_return_t
921: task_wire(
922: vm_map_t map,
923: boolean_t must_wire)
924: {
925: if (map == VM_MAP_NULL)
926: return(KERN_INVALID_ARGUMENT);
927:
928: if (must_wire)
929: map->wiring_required = TRUE;
930: else
931: map->wiring_required = FALSE;
932:
933: return(KERN_SUCCESS);
934: }
935:
936: /*
937: * vm_behavior_set sets the paging behavior attribute for the
938: * specified range in the specified map. This routine will fail
939: * with KERN_INVALID_ADDRESS if any address in [start,start+size)
940: * is not a valid allocated or reserved memory region.
941: */
942: kern_return_t
943: vm_behavior_set(
944: vm_map_t map,
945: vm_offset_t start,
946: vm_size_t size,
947: vm_behavior_t new_behavior)
948: {
949: if (map == VM_MAP_NULL)
950: return(KERN_INVALID_ARGUMENT);
951:
952: return(vm_map_behavior_set(map, trunc_page(start),
953: round_page(start+size), new_behavior));
954: }
955:
956: #if VM_CPM
957: /*
958: * Control whether the kernel will permit use of
959: * vm_allocate_cpm at all.
960: */
961: unsigned int vm_allocate_cpm_enabled = 1;
962:
963: /*
964: * Ordinarily, the right to allocate CPM is restricted
965: * to privileged applications (those that can gain access
966: * to the host port). Set this variable to zero if you
967: * want to let any application allocate CPM.
968: */
969: unsigned int vm_allocate_cpm_privileged = 0;
970:
971: /*
972: * Allocate memory in the specified map, with the caveat that
973: * the memory is physically contiguous. This call may fail
974: * if the system can't find sufficient contiguous memory.
975: * This call may cause or lead to heart-stopping amounts of
976: * paging activity.
977: *
978: * Memory obtained from this call should be freed in the
979: * normal way, viz., via vm_deallocate.
980: */
981: kern_return_t
982: vm_allocate_cpm(
983: host_t host,
984: register vm_map_t map,
985: register vm_offset_t *addr,
986: register vm_size_t size,
987: int flags)
988: {
989: vm_object_t cpm_obj;
990: pmap_t pmap;
991: vm_page_t m, pages;
992: kern_return_t kr;
993: vm_offset_t va, start, end, offset;
994: #if MACH_ASSERT
995: extern vm_offset_t avail_start, avail_end;
996: vm_offset_t prev_addr;
997: #endif /* MACH_ASSERT */
998:
999: boolean_t anywhere = VM_FLAGS_ANYWHERE & flags;
1000:
1001: if (!vm_allocate_cpm_enabled)
1002: return KERN_FAILURE;
1003:
1004: if (vm_allocate_cpm_privileged && host == HOST_NULL)
1005: return KERN_INVALID_HOST;
1006:
1007: if (map == VM_MAP_NULL)
1008: return KERN_INVALID_ARGUMENT;
1009:
1010: if (size == 0) {
1011: *addr = 0;
1012: return KERN_SUCCESS;
1013: }
1014:
1015: if (anywhere)
1016: *addr = vm_map_min(map);
1017: else
1018: *addr = trunc_page(*addr);
1019: size = round_page(size);
1020:
1021: if ((kr = cpm_allocate(size, &pages, TRUE)) != KERN_SUCCESS)
1022: return kr;
1023:
1024: cpm_obj = vm_object_allocate(size);
1025: assert(cpm_obj != VM_OBJECT_NULL);
1026: assert(cpm_obj->internal);
1027: assert(cpm_obj->size == size);
1028: assert(cpm_obj->can_persist == FALSE);
1029: assert(cpm_obj->pager_created == FALSE);
1030: assert(cpm_obj->pageout == FALSE);
1031: assert(cpm_obj->shadow == VM_OBJECT_NULL);
1032:
1033: /*
1034: * Insert pages into object.
1035: */
1036:
1037: vm_object_lock(cpm_obj);
1038: for (offset = 0; offset < size; offset += PAGE_SIZE) {
1039: m = pages;
1040: pages = NEXT_PAGE(m);
1041:
1042: assert(!m->gobbled);
1043: assert(!m->wanted);
1044: assert(!m->pageout);
1045: assert(!m->tabled);
1046: assert(m->busy);
1047: assert(m->phys_addr>=avail_start && m->phys_addr<=avail_end);
1048:
1049: m->busy = FALSE;
1050: vm_page_insert(m, cpm_obj, offset);
1051: }
1052: assert(cpm_obj->resident_page_count == size / PAGE_SIZE);
1053: vm_object_unlock(cpm_obj);
1054:
1055: /*
1056: * Hang onto a reference on the object in case a
1057: * multi-threaded application for some reason decides
1058: * to deallocate the portion of the address space into
1059: * which we will insert this object.
1060: *
1061: * Unfortunately, we must insert the object now before
1062: * we can talk to the pmap module about which addresses
1063: * must be wired down. Hence, the race with a multi-
1064: * threaded app.
1065: */
1066: vm_object_reference(cpm_obj);
1067:
1068: /*
1069: * Insert object into map.
1070: */
1071:
1072: kr = vm_map_enter(
1073: map,
1074: addr,
1075: size,
1076: (vm_offset_t)0,
1077: flags,
1078: cpm_obj,
1079: (vm_offset_t)0,
1080: FALSE,
1081: VM_PROT_ALL,
1082: VM_PROT_ALL,
1083: VM_INHERIT_DEFAULT);
1084:
1085: if (kr != KERN_SUCCESS) {
1086: /*
1087: * A CPM object doesn't have can_persist set,
1088: * so all we have to do is deallocate it to
1089: * free up these pages.
1090: */
1091: assert(cpm_obj->pager_created == FALSE);
1092: assert(cpm_obj->can_persist == FALSE);
1093: assert(cpm_obj->pageout == FALSE);
1094: assert(cpm_obj->shadow == VM_OBJECT_NULL);
1095: vm_object_deallocate(cpm_obj); /* kill acquired ref */
1096: vm_object_deallocate(cpm_obj); /* kill creation ref */
1097: }
1098:
1099: /*
1100: * Inform the physical mapping system that the
1101: * range of addresses may not fault, so that
1102: * page tables and such can be locked down as well.
1103: */
1104: start = *addr;
1105: end = start + size;
1106: pmap = vm_map_pmap(map);
1107: pmap_pageable(pmap, start, end, FALSE);
1108:
1109: /*
1110: * Enter each page into the pmap, to avoid faults.
1111: * Note that this loop could be coded more efficiently,
1112: * if the need arose, rather than looking up each page
1113: * again.
1114: */
1115: for (offset = 0, va = start; offset < size;
1116: va += PAGE_SIZE, offset += PAGE_SIZE) {
1117: vm_object_lock(cpm_obj);
1118: m = vm_page_lookup(cpm_obj, offset);
1119: vm_object_unlock(cpm_obj);
1120: assert(m != VM_PAGE_NULL);
1121: PMAP_ENTER(pmap, va, m, VM_PROT_ALL, TRUE);
1122: }
1123:
1124: #if MACH_ASSERT
1125: /*
1126: * Verify ordering in address space.
1127: */
1128: for (offset = 0; offset < size; offset += PAGE_SIZE) {
1129: vm_object_lock(cpm_obj);
1130: m = vm_page_lookup(cpm_obj, offset);
1131: vm_object_unlock(cpm_obj);
1132: if (m == VM_PAGE_NULL)
1133: panic("vm_allocate_cpm: obj 0x%x off 0x%x no page",
1134: cpm_obj, offset);
1135: assert(m->tabled);
1136: assert(!m->busy);
1137: assert(!m->wanted);
1138: assert(!m->fictitious);
1139: assert(!m->private);
1140: assert(!m->absent);
1141: assert(!m->error);
1142: assert(!m->cleaning);
1143: assert(!m->precious);
1144: assert(!m->clustered);
1145: if (offset != 0) {
1146: if (m->phys_addr != prev_addr + PAGE_SIZE) {
1147: printf("start 0x%x end 0x%x va 0x%x\n",
1148: start, end, va);
1149: printf("obj 0x%x off 0x%x\n", cpm_obj, offset);
1150: printf("m 0x%x prev_address 0x%x\n", m,
1151: prev_addr);
1152: panic("vm_allocate_cpm: pages not contig!");
1153: }
1154: }
1155: prev_addr = m->phys_addr;
1156: }
1157: #endif /* MACH_ASSERT */
1158:
1159: vm_object_deallocate(cpm_obj); /* kill extra ref */
1160:
1161: return kr;
1162: }
1163:
1164:
1165: #else /* VM_CPM */
1166:
1167: /*
1168: * Interface is defined in all cases, but unless the kernel
1169: * is built explicitly for this option, the interface does
1170: * nothing.
1171: */
1172:
1173: kern_return_t
1174: vm_allocate_cpm(
1175: host_t host,
1176: register vm_map_t map,
1177: register vm_offset_t *addr,
1178: register vm_size_t size,
1179: int flags)
1180: {
1181: return KERN_FAILURE;
1182: }
1183:
1184: /*
1185: */
1186: kern_return_t
1187: mach_memory_object_memory_entry(
1188: host_t host,
1189: boolean_t internal,
1190: vm_size_t size,
1191: vm_prot_t permission,
1192: ipc_port_t pager,
1193: ipc_port_t *entry_handle)
1194: {
1195: vm_named_entry_t user_object;
1196: ipc_port_t user_handle;
1197: ipc_port_t previous;
1198: kern_return_t kr;
1199:
1200: if (host == HOST_NULL)
1201: return(KERN_INVALID_HOST);
1202:
1203: user_object = (vm_named_entry_t)
1204: kalloc(sizeof (struct vm_named_entry));
1205: if(user_object == NULL)
1206: return KERN_FAILURE;
1207: named_entry_lock_init(user_object);
1208: user_handle = ipc_port_alloc_kernel();
1209: ip_lock(user_handle);
1210:
1211: /* make a sonce right */
1212: user_handle->ip_sorights++;
1213: ip_reference(user_handle);
1214:
1215: user_handle->ip_destination = IP_NULL;
1216: user_handle->ip_receiver_name = MACH_PORT_NULL;
1217: user_handle->ip_receiver = ipc_space_kernel;
1218:
1219: /* make a send right */
1220: user_handle->ip_mscount++;
1221: user_handle->ip_srights++;
1222: ip_reference(user_handle);
1223:
1224: ipc_port_nsrequest(user_handle, 1, user_handle, &previous);
1225: /* nsrequest unlocks user_handle */
1226:
1227: user_object->object = NULL;
1228: user_object->size = size;
1229: user_object->offset = 0;
1230: user_object->backing.pager = pager;
1231: user_object->protection = permission;
1232: user_object->internal = internal;
1233: user_object->is_sub_map = FALSE;
1234: user_object->ref_count = 1;
1235:
1236: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object,
1237: IKOT_NAMED_ENTRY);
1238: *entry_handle = user_handle;
1239: return KERN_SUCCESS;
1240: }
1241:
1242:
1243:
1244: /*
1245: */
1246:
1247: kern_return_t
1248: mach_make_memory_entry(
1249: vm_map_t target_map,
1250: vm_size_t *size,
1251: vm_offset_t offset,
1252: vm_prot_t permission,
1253: ipc_port_t *object_handle,
1254: ipc_port_t parent_entry)
1255: {
1256: vm_map_version_t version;
1257: vm_named_entry_t user_object;
1258: ipc_port_t user_handle;
1259: ipc_port_t previous;
1260: kern_return_t kr;
1261:
1262: /* needed for call to vm_map_lookup_locked */
1263: boolean_t wired;
1264: vm_offset_t obj_off;
1265: vm_prot_t prot;
1266: vm_offset_t lo_offset, hi_offset;
1267: vm_behavior_t behavior;
1268: vm_object_t object;
1269:
1270: /* needed for direct map entry manipulation */
1271: vm_map_entry_t map_entry;
1272: vm_map_t local_map;
1273: vm_size_t mappable_size;
1274:
1275:
1276: user_object = (vm_named_entry_t)
1277: kalloc(sizeof (struct vm_named_entry));
1278: if(user_object == NULL)
1279: return KERN_FAILURE;
1280: named_entry_lock_init(user_object);
1281: user_handle = ipc_port_alloc_kernel();
1282: ip_lock(user_handle);
1283:
1284: /* make a sonce right */
1285: user_handle->ip_sorights++;
1286: ip_reference(user_handle);
1287:
1288: user_handle->ip_destination = IP_NULL;
1289: user_handle->ip_receiver_name = MACH_PORT_NULL;
1290: user_handle->ip_receiver = ipc_space_kernel;
1291:
1292: /* make a send right */
1293: user_handle->ip_mscount++;
1294: user_handle->ip_srights++;
1295: ip_reference(user_handle);
1296:
1297: ipc_port_nsrequest(user_handle, 1, user_handle, &previous);
1298: /* nsrequest unlocks user_handle */
1299:
1300: user_object->backing.pager = NULL;
1301: user_object->ref_count = 1;
1302:
1303: if(parent_entry == NULL) {
1304: /* Create a named object based on address range within the task map */
1305: /* Go find the object at given address */
1306:
1307: permission &= VM_PROT_ALL;
1308: vm_map_lock_read(target_map);
1309:
1310: /* get the object associated with the target address */
1311: /* note we check the permission of the range against */
1312: /* that requested by the caller */
1313:
1314: kr = vm_map_lookup_locked(&target_map, offset,
1315: permission, &version,
1316: &object, &obj_off, &prot, &wired, &behavior,
1317: &lo_offset, &hi_offset);
1318: if (kr != KERN_SUCCESS) {
1319: vm_map_unlock_read(target_map);
1320: goto make_mem_done;
1321: }
1322: if ((prot & permission) != permission) {
1323: kr = KERN_INVALID_RIGHT;
1324: vm_object_unlock(object);
1325: vm_map_unlock_read(target_map);
1326: goto make_mem_done;
1327: }
1328:
1329: /* We have an object, now check to see if this object */
1330: /* is suitable. If not, create a shadow and share that */
1331:
1332: local_map = target_map;
1333: redo_lookup:
1334: while(TRUE) {
1335: if(!vm_map_lookup_entry(local_map, offset, &map_entry)) {
1336: kr = KERN_INVALID_ARGUMENT;
1337: vm_object_unlock(object);
1338: vm_map_unlock_read(target_map);
1339: goto make_mem_done;
1340: }
1341: if(!(map_entry->is_sub_map)) {
1342: if(map_entry->object.vm_object != object) {
1343: kr = KERN_INVALID_ARGUMENT;
1344: vm_object_unlock(object);
1345: vm_map_unlock_read(target_map);
1346: goto make_mem_done;
1347: }
1348: break;
1349: } else {
1350: local_map = map_entry->object.sub_map;
1351: vm_map_lock_read(local_map);
1352: vm_map_unlock_read(target_map);
1353: target_map = local_map;
1354: }
1355: }
1356: if(((map_entry->max_protection) & permission) != permission) {
1357: kr = KERN_INVALID_RIGHT;
1358: vm_object_unlock(object);
1359: vm_map_unlock_read(target_map);
1360: goto make_mem_done;
1361: }
1362: if(object->internal) {
1363: /* vm_map_lookup_locked will create a shadow if */
1364: /* needs_copy is set but does not check for the */
1365: /* other two conditions shown. It is important to */
1366: /* set up an object which will not be pulled from */
1367: /* under us. */
1368:
1369: if (map_entry->needs_copy || object->shadowed ||
1370: (object->size > ((vm_size_t)map_entry->vme_end -
1371: map_entry->vme_start))) {
1372: if (vm_map_lock_read_to_write(target_map)) {
1373: vm_map_lock_read(target_map);
1374: goto redo_lookup;
1375: }
1376:
1377:
1378: /* create a shadow object */
1379:
1380: vm_object_shadow(&map_entry->object.vm_object,
1381: &map_entry->offset,
1382: (map_entry->vme_end
1383: - map_entry->vme_start));
1384: map_entry->needs_copy = FALSE;
1385: vm_object_unlock(object);
1386: object = map_entry->object.vm_object;
1387: vm_object_lock(object);
1388: object->size = map_entry->vme_end
1389: - map_entry->vme_start;
1390: obj_off = (offset - map_entry->vme_start) +
1391: map_entry->offset;
1392: lo_offset = map_entry->offset;
1393: hi_offset = (map_entry->vme_end -
1394: map_entry->vme_start) +
1395: map_entry->offset;
1396:
1397: vm_map_lock_write_to_read(target_map);
1398:
1399: }
1400: }
1401:
1402: /* note: in the future we can (if necessary) allow for */
1403: /* memory object lists, this will better support */
1404: /* fragmentation, but is it necessary? The user should */
1405: /* be encouraged to create address space oriented */
1406: /* shared objects from CLEAN memory regions which have */
1407: /* a known and defined history. i.e. no inheritence */
1408: /* share, make this call before making the region the */
1409: /* target of ipc's, etc. The code above, protecting */
1410: /* against delayed copy, etc. is mostly defensive. */
1411:
1412:
1413:
1414: object->true_share = TRUE;
1415: user_object->object = object;
1416: user_object->internal = object->internal;
1417: user_object->is_sub_map = FALSE;
1418: user_object->offset = obj_off;
1419: user_object->protection = permission;
1420:
1421: /* the size of mapped entry that overlaps with our region */
1422: /* which is targeted for share. */
1423: /* (entry_end - entry_start) - */
1424: /* offset of our beg addr within entry */
1425: /* it corresponds to this: */
1426:
1427: mappable_size = hi_offset - obj_off;
1428: if(*size > mappable_size)
1429: *size = mappable_size;
1430:
1431: user_object->size = *size;
1432:
1433: /* user_object pager and internal fields are not used */
1434: /* when the object field is filled in. */
1435:
1436: object->ref_count++; /* we now point to this object, hold on */
1437: vm_object_res_reference(object);
1438: vm_object_unlock(object);
1439: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object,
1440: IKOT_NAMED_ENTRY);
1441: *size = user_object->size;
1442: *object_handle = user_handle;
1443: vm_map_unlock_read(target_map);
1444: return KERN_SUCCESS;
1445: } else {
1446:
1447: vm_named_entry_t parent_object;
1448:
1449: /* The new object will be base on an existing named object */
1450: if(ip_kotype(parent_entry) != IKOT_NAMED_ENTRY) {
1451: kr = KERN_INVALID_ARGUMENT;
1452: goto make_mem_done;
1453: }
1454: parent_object = (vm_named_entry_t)parent_entry->ip_kobject;
1455: if(permission & parent_object->protection != permission) {
1456: kr = KERN_INVALID_ARGUMENT;
1457: goto make_mem_done;
1458: }
1459: if((offset + *size) > parent_object->size) {
1460: kr = KERN_INVALID_ARGUMENT;
1461: goto make_mem_done;
1462: }
1463:
1464: user_object->object = parent_object->object;
1465: user_object->size = *size;
1466: user_object->offset = parent_object->offset + offset;
1467: user_object->protection = permission;
1468: if(parent_object->is_sub_map) {
1469: user_object->backing.map = parent_object->backing.map;
1470: vm_map_lock(user_object->backing.map);
1471: user_object->backing.map->ref_count++;
1472: vm_map_unlock(user_object->backing.map);
1473: }
1474: else {
1475: user_object->backing.pager = parent_object->backing.pager;
1476: }
1477: user_object->internal = parent_object->internal;
1478: user_object->is_sub_map = parent_object->is_sub_map;
1479:
1480: if(parent_object->object != NULL) {
1481: /* we now point to this object, hold on */
1482: vm_object_reference(parent_object->object);
1483: vm_object_lock(parent_object->object);
1484: parent_object->object->true_share = TRUE;
1485: vm_object_unlock(parent_object->object);
1486: }
1487: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object,
1488: IKOT_NAMED_ENTRY);
1489: *object_handle = user_handle;
1490: return KERN_SUCCESS;
1491: }
1492:
1493:
1494:
1495: make_mem_done:
1496: ipc_port_dealloc_kernel(user_handle);
1497: kfree((vm_offset_t)user_object, sizeof (struct vm_named_entry));
1498: return kr;
1499: }
1500:
1501: /*
1502: */
1503:
1504: kern_return_t
1505: vm_region_object_create(
1506: vm_map_t target_map,
1507: vm_size_t size,
1508: ipc_port_t *object_handle)
1509: {
1510: vm_named_entry_t user_object;
1511: ipc_port_t user_handle;
1512: kern_return_t kr;
1513:
1514: pmap_t new_pmap = pmap_create((vm_size_t) 0);
1515: ipc_port_t previous;
1516: vm_map_t new_map;
1517:
1518: if(new_pmap == PMAP_NULL)
1519: return KERN_FAILURE;
1520: user_object = (vm_named_entry_t)
1521: kalloc(sizeof (struct vm_named_entry));
1522: if(user_object == NULL) {
1523: pmap_destroy(new_pmap);
1524: return KERN_FAILURE;
1525: }
1526: named_entry_lock_init(user_object);
1527: user_handle = ipc_port_alloc_kernel();
1528:
1529:
1530: ip_lock(user_handle);
1531:
1532: /* make a sonce right */
1533: user_handle->ip_sorights++;
1534: ip_reference(user_handle);
1535:
1536: user_handle->ip_destination = IP_NULL;
1537: user_handle->ip_receiver_name = MACH_PORT_NULL;
1538: user_handle->ip_receiver = ipc_space_kernel;
1539:
1540: /* make a send right */
1541: user_handle->ip_mscount++;
1542: user_handle->ip_srights++;
1543: ip_reference(user_handle);
1544:
1545: ipc_port_nsrequest(user_handle, 1, user_handle, &previous);
1546: /* nsrequest unlocks user_handle */
1547:
1548: /* Create a named object based on a submap of specified size */
1549:
1550: new_map = vm_map_create(new_pmap, 0, size, TRUE);
1551: user_object->backing.map = new_map;
1552:
1553:
1554: user_object->object = VM_OBJECT_NULL;
1555: user_object->internal = TRUE;
1556: user_object->is_sub_map = TRUE;
1557: user_object->offset = 0;
1558: user_object->protection = VM_PROT_ALL;
1559: user_object->size = size;
1560: user_object->ref_count = 1;
1561:
1562: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object,
1563: IKOT_NAMED_ENTRY);
1564: *object_handle = user_handle;
1565: return KERN_SUCCESS;
1566:
1567: }
1568:
1569: void
1570: mach_destroy_memory_entry(
1571: ipc_port_t port)
1572: {
1573: vm_named_entry_t named_entry;
1574: #if MACH_ASSERT
1575: assert(ip_kotype(port) == IKOT_NAMED_ENTRY);
1576: #endif /* MACH_ASSERT */
1577: named_entry = (vm_named_entry_t)port->ip_kobject;
1578: mutex_lock(&(named_entry)->Lock);
1579: named_entry->ref_count-=1;
1580: if(named_entry->ref_count == 0) {
1581: if(named_entry->object) {
1582: /* release the memory object we've been pointing to */
1583: vm_object_deallocate(named_entry->object);
1584: }
1585: if(named_entry->is_sub_map) {
1586: vm_map_deallocate(named_entry->backing.map);
1587: }
1588: kfree((vm_offset_t)port->ip_kobject,
1589: sizeof (struct vm_named_entry));
1590: } else
1591: mutex_unlock(&(named_entry)->Lock);
1592: }
1593:
1594:
1595: kern_return_t
1596: vm_map_page_query(
1597: vm_map_t target_map,
1598: vm_offset_t offset,
1599: int *disposition,
1600: int *ref_count)
1601: {
1602: vm_map_entry_t map_entry;
1603: vm_object_t object;
1604: vm_page_t m;
1605:
1606: restart_page_query:
1607: *disposition = 0;
1608: *ref_count = 0;
1609: vm_map_lock(target_map);
1610: if(!vm_map_lookup_entry(target_map, offset, &map_entry)) {
1611: vm_map_unlock(target_map);
1612: return KERN_FAILURE;
1613: }
1614: offset -= map_entry->vme_start; /* adjust to offset within entry */
1615: offset += map_entry->offset; /* adjust to target object offset */
1616: if(map_entry->object.vm_object != VM_OBJECT_NULL) {
1617: if(!map_entry->is_sub_map) {
1618: object = map_entry->object.vm_object;
1619: } else {
1620: vm_map_unlock(target_map);
1621: target_map = map_entry->object.sub_map;
1622: goto restart_page_query;
1623: }
1624: } else {
1625: vm_map_unlock(target_map);
1626: return KERN_FAILURE;
1627: }
1628: vm_object_lock(object);
1629: vm_map_unlock(target_map);
1630: while(TRUE) {
1631: m = vm_page_lookup(object, offset);
1632: if (m != VM_PAGE_NULL) {
1633: *disposition |= VM_PAGE_QUERY_PAGE_PRESENT;
1634: break;
1635: } else {
1636: if(object->shadow) {
1637: offset += object->shadow_offset;
1638: vm_object_unlock(object);
1639: object = object->shadow;
1640: vm_object_lock(object);
1641: continue;
1642: }
1643: vm_object_unlock(object);
1644: return KERN_FAILURE;
1645: }
1646: }
1647:
1648: /* The ref_count is not strictly accurate, it measures the number */
1649: /* of entities holding a ref on the object, they may not be mapping */
1650: /* the object or may not be mapping the section holding the */
1651: /* target page but its still a ball park number and though an over- */
1652: /* count, it picks up the copy-on-write cases */
1653:
1654: /* We could also get a picture of page sharing from pmap_attributes */
1655: /* but this would under count as only faulted-in mappings would */
1656: /* show up. */
1657:
1658: *ref_count = object->ref_count;
1659:
1660: if (m->fictitious) {
1661: *disposition |= VM_PAGE_QUERY_PAGE_FICTITIOUS;
1662: vm_object_unlock(object);
1663: return KERN_SUCCESS;
1664: }
1665:
1666: if (m->dirty)
1667: *disposition |= VM_PAGE_QUERY_PAGE_DIRTY;
1668: else if(pmap_is_modified(m->phys_addr))
1669: *disposition |= VM_PAGE_QUERY_PAGE_DIRTY;
1670:
1671: if (m->reference)
1672: *disposition |= VM_PAGE_QUERY_PAGE_REF;
1673: else if(pmap_is_referenced(m->phys_addr))
1674: *disposition |= VM_PAGE_QUERY_PAGE_REF;
1675:
1676: vm_object_unlock(object);
1677: return KERN_SUCCESS;
1678:
1679: }
1680:
1681: kern_return_t
1682: set_dp_control_port(
1683: host_t host,
1684: ipc_port_t control_port)
1685: {
1686: if (host == HOST_NULL)
1687: return (KERN_INVALID_HOST);
1688: dynamic_pager_control_port = control_port;
1689: return KERN_SUCCESS;
1690: }
1691:
1692: kern_return_t
1693: get_dp_control_port(
1694: host_t host,
1695: ipc_port_t *control_port)
1696: {
1697: if (host == HOST_NULL)
1698: return (KERN_INVALID_HOST);
1699: *control_port = dynamic_pager_control_port;
1700: return KERN_SUCCESS;
1701:
1702: }
1703:
1704: void
1705: mach_destroy_upl(
1706: ipc_port_t port)
1707: {
1708: upl_t upl;
1709: #if MACH_ASSERT
1710: assert(ip_kotype(port) == IKOT_NAMED_ENTRY);
1711: #endif /* MACH_ASSERT */
1712: upl = (upl_t)port->ip_kobject;
1713: mutex_lock(&(upl)->Lock);
1714: upl->ref_count-=1;
1715: if(upl->ref_count == 0) {
1716: mutex_unlock(&(upl)->Lock);
1717: upl_abort(upl, UPL_ABORT_ERROR);
1718: } else
1719: mutex_unlock(&(upl)->Lock);
1720: }
1721:
1722: kern_return_t
1723: vm_object_upl_request(
1724: vm_object_t object,
1725: vm_object_offset_t offset,
1726: vm_size_t size,
1727: ipc_port_t *upl,
1728: upl_page_info_t *page_list,
1729: mach_msg_type_number_t *count,
1730: int cntrl_flags)
1731: {
1732: upl_t upl_object;
1733: ipc_port_t upl_port;
1734: ipc_port_t previous;
1735: upl_page_info_t *pl;
1736: kern_return_t kr;
1737:
1738: pl = page_list;
1739: kr = vm_fault_list_request(object, offset, size, &upl_object,
1740: &pl, *count, cntrl_flags);
1741:
1742:
1743: if(kr != KERN_SUCCESS) {
1744: *upl = MACH_PORT_NULL;
1745: return KERN_FAILURE;
1746: }
1747:
1748: upl_port = ipc_port_alloc_kernel();
1749:
1750:
1751: ip_lock(upl_port);
1752:
1753: /* make a sonce right */
1754: upl_port->ip_sorights++;
1755: ip_reference(upl_port);
1756:
1757: upl_port->ip_destination = IP_NULL;
1758: upl_port->ip_receiver_name = MACH_PORT_NULL;
1759: upl_port->ip_receiver = ipc_space_kernel;
1760:
1761: /* make a send right */
1762: upl_port->ip_mscount++;
1763: upl_port->ip_srights++;
1764: ip_reference(upl_port);
1765:
1766: ipc_port_nsrequest(upl_port, 1, upl_port, &previous);
1767: /* nsrequest unlocks user_handle */
1768:
1769: /* Create a named object based on a submap of specified size */
1770:
1771:
1772: ipc_kobject_set(upl_port, (ipc_kobject_t) upl_object, IKOT_UPL);
1773: *upl = upl_port;
1774: return KERN_SUCCESS;
1775: }
1776:
1777: kern_return_t
1778: vm_pager_upl_request(
1779: vm_object_t object,
1780: vm_object_offset_t offset,
1781: vm_size_t size,
1782: vm_size_t super_size,
1783: ipc_port_t *upl,
1784: upl_page_info_t *page_list,
1785: mach_msg_type_number_t *count,
1786: int cntrl_flags)
1787: {
1788: upl_t upl_object;
1789: ipc_port_t upl_port;
1790: ipc_port_t previous;
1791: upl_page_info_t *pl;
1792: kern_return_t kr;
1793:
1794: pl = page_list;
1795: kr = upl_system_list_request(object, offset, size, super_size,
1796: &upl_object, &pl, *count, cntrl_flags);
1797:
1798: if(kr != KERN_SUCCESS) {
1799: *upl = MACH_PORT_NULL;
1800: return KERN_FAILURE;
1801: }
1802:
1803:
1804: upl_port = ipc_port_alloc_kernel();
1805:
1806:
1807: ip_lock(upl_port);
1808:
1809: /* make a sonce right */
1810: upl_port->ip_sorights++;
1811: ip_reference(upl_port);
1812:
1813: upl_port->ip_destination = IP_NULL;
1814: upl_port->ip_receiver_name = MACH_PORT_NULL;
1815: upl_port->ip_receiver = ipc_space_kernel;
1816:
1817: /* make a send right */
1818: upl_port->ip_mscount++;
1819: upl_port->ip_srights++;
1820: ip_reference(upl_port);
1821:
1822: ipc_port_nsrequest(upl_port, 1, upl_port, &previous);
1823: /* nsrequest unlocks user_handle */
1824:
1825: /* Create a named object based on a submap of specified size */
1826:
1827:
1828: ipc_kobject_set(upl_port, (ipc_kobject_t) upl_object, IKOT_UPL);
1829: *upl = upl_port;
1830: return KERN_SUCCESS;
1831: }
1832:
1833: kern_return_t
1834: vm_upl_map(
1835: vm_map_t map,
1836: ipc_port_t upl_port,
1837: vm_offset_t *dst_addr)
1838: {
1839: upl_t upl;
1840: kern_return_t kr;
1841:
1842: if (!IP_VALID(upl_port)) {
1843: return KERN_INVALID_ARGUMENT;
1844: } else if (ip_kotype(upl_port) == IKOT_UPL) {
1845: upl_lock(upl);
1846: upl = (upl_t)upl_port->ip_kobject;
1847: kr = upl_map(map, upl, dst_addr);
1848: upl_unlock(upl);
1849: return kr;
1850: } else {
1851: return KERN_FAILURE;
1852: }
1853: }
1854:
1855:
1856: kern_return_t
1857: vm_upl_unmap(
1858: vm_map_t map,
1859: ipc_port_t upl_port)
1860: {
1861: upl_t upl;
1862: kern_return_t kr;
1863:
1864: if (!IP_VALID(upl_port)) {
1865: return KERN_INVALID_ARGUMENT;
1866: } else if (ip_kotype(upl_port) == IKOT_UPL) {
1867: upl_lock(upl);
1868: upl = (upl_t)upl_port->ip_kobject;
1869: kr = upl_un_map(map, upl);
1870: upl_unlock(upl);
1871: return kr;
1872: } else {
1873: return KERN_FAILURE;
1874: }
1875: }
1876:
1877: kern_return_t
1878: vm_upl_commit(
1879: upl_t upl,
1880: upl_page_list_ptr_t page_list,
1881: mach_msg_type_number_t count)
1882: {
1883: kern_return_t kr;
1884: upl_lock(upl);
1885: if(count) {
1886: kr = upl_commit(upl, (upl_page_info_t *)page_list);
1887: } else {
1888: kr = upl_commit(upl, (upl_page_info_t *) NULL);
1889: }
1890: upl_unlock(upl);
1891: return kr;
1892: }
1893:
1894: kern_return_t
1895: vm_upl_commit_range(
1896: upl_t upl,
1897: vm_offset_t offset,
1898: vm_size_t size,
1899: upl_page_list_ptr_t page_list,
1900: boolean_t free_on_empty,
1901: mach_msg_type_number_t count)
1902: {
1903: kern_return_t kr;
1904: upl_lock(upl);
1905: if(count) {
1906: kr = upl_commit_range(upl, offset, size, free_on_empty,
1907: (upl_page_info_t *)page_list);
1908: } else {
1909: kr = upl_commit_range(upl, offset, size, free_on_empty,
1910: (upl_page_info_t *) NULL);
1911: }
1912: upl_unlock(upl);
1913: return kr;
1914: }
1915:
1916: kern_return_t
1917: vm_upl_abort_range(
1918: upl_t upl,
1919: vm_offset_t offset,
1920: vm_size_t size,
1921: int abort_flags)
1922: {
1923: kern_return_t kr;
1924: upl_lock(upl);
1925: kr = upl_abort_range(upl, offset, size, abort_flags);
1926: upl_unlock(upl);
1927: return kr;
1928: }
1929:
1930: kern_return_t
1931: vm_upl_abort(
1932: upl_t upl,
1933: int abort_type)
1934: {
1935: kern_return_t kr;
1936: upl_lock(upl);
1937: kr = upl_abort(upl, abort_type);
1938: upl_unlock(upl);
1939: return kr;
1940: }
1941:
1942: #endif /* VM_CPM */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.