]>
Commit | Line | Data |
---|---|---|
b0d623f7 | 1 | /* |
39037602 | 2 | * Copyright (c) 2008-2016 Apple Inc. All rights reserved. |
b0d623f7 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | /* | |
32 | * Mach Operating System | |
33 | * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
35 | * | |
36 | * Permission to use, copy, modify and distribute this software and its | |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
41 | * | |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
45 | * | |
46 | * Carnegie Mellon requests users of this software to return to | |
47 | * | |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
52 | * | |
53 | * any improvements or extensions that they make and grant Carnegie Mellon | |
54 | * the rights to redistribute these changes. | |
55 | */ | |
56 | /* | |
57 | */ | |
58 | /* | |
59 | * File: vm/vm32_user.c | |
60 | * Author: Avadis Tevanian, Jr., Michael Wayne Young | |
61 | * | |
62 | * User-exported virtual memory functions. | |
63 | */ | |
64 | ||
65 | #include <debug.h> | |
66 | ||
67 | #include <mach/boolean.h> | |
68 | #include <mach/kern_return.h> | |
69 | #include <mach/mach_types.h> /* to get vm_address_t */ | |
70 | #include <mach/memory_object.h> | |
71 | #include <mach/std_types.h> /* to get pointer_t */ | |
72 | #include <mach/vm_attributes.h> | |
73 | #include <mach/vm_param.h> | |
74 | #include <mach/vm_statistics.h> | |
75 | #include <mach/mach_syscalls.h> | |
76 | ||
77 | #include <mach/host_priv_server.h> | |
78 | #include <mach/mach_vm_server.h> | |
79 | #include <mach/vm32_map_server.h> | |
80 | ||
81 | #include <kern/host.h> | |
82 | #include <kern/kalloc.h> | |
83 | #include <kern/task.h> | |
84 | #include <kern/misc_protos.h> | |
85 | #include <vm/vm_fault.h> | |
86 | #include <vm/vm_map.h> | |
87 | #include <vm/vm_object.h> | |
88 | #include <vm/vm_page.h> | |
89 | #include <vm/memory_object.h> | |
90 | #include <vm/vm_pageout.h> | |
91 | #include <vm/vm_protos.h> | |
92 | ||
39037602 | 93 | #ifdef VM32_SUPPORT |
b0d623f7 A |
94 | |
95 | /* | |
96 | * See vm_user.c for the real implementation of all of these functions. | |
97 | * We call through to the mach_ "wide" versions of the routines, and trust | |
98 | * that the VM system verifies the arguments and only returns address that | |
99 | * are appropriate for the task's address space size. | |
100 | * | |
101 | * New VM call implementations should not be added here, because they would | |
102 | * be available only to 32-bit userspace clients. Add them to vm_user.c | |
103 | * and the corresponding prototype to mach_vm.defs (subsystem 4800). | |
104 | */ | |
105 | ||
106 | kern_return_t | |
107 | vm32_allocate( | |
108 | vm_map_t map, | |
109 | vm32_offset_t *addr, | |
110 | vm32_size_t size, | |
111 | int flags) | |
112 | { | |
113 | mach_vm_offset_t maddr; | |
114 | kern_return_t result; | |
115 | ||
116 | maddr = *addr; | |
5ba3f43e | 117 | result = mach_vm_allocate_external(map, &maddr, size, flags); |
b0d623f7 A |
118 | *addr = CAST_DOWN_EXPLICIT(vm32_offset_t, maddr); |
119 | ||
120 | return result; | |
121 | } | |
122 | ||
123 | kern_return_t | |
124 | vm32_deallocate( | |
125 | vm_map_t map, | |
126 | vm32_offset_t start, | |
127 | vm32_size_t size) | |
128 | { | |
129 | if ((map == VM_MAP_NULL) || (start + size < start)) | |
130 | return(KERN_INVALID_ARGUMENT); | |
131 | ||
132 | return mach_vm_deallocate(map, start, size); | |
133 | } | |
134 | ||
135 | kern_return_t | |
136 | vm32_inherit( | |
137 | vm_map_t map, | |
138 | vm32_offset_t start, | |
139 | vm32_size_t size, | |
140 | vm_inherit_t new_inheritance) | |
141 | { | |
142 | if ((map == VM_MAP_NULL) || (start + size < start)) | |
143 | return(KERN_INVALID_ARGUMENT); | |
144 | ||
145 | return mach_vm_inherit(map, start, size, new_inheritance); | |
146 | } | |
147 | ||
148 | kern_return_t | |
149 | vm32_protect( | |
150 | vm_map_t map, | |
151 | vm32_offset_t start, | |
152 | vm32_size_t size, | |
153 | boolean_t set_maximum, | |
154 | vm_prot_t new_protection) | |
155 | { | |
156 | if ((map == VM_MAP_NULL) || (start + size < start)) | |
157 | return(KERN_INVALID_ARGUMENT); | |
158 | ||
159 | return mach_vm_protect(map, start, size, set_maximum, new_protection); | |
160 | } | |
161 | ||
162 | kern_return_t | |
163 | vm32_machine_attribute( | |
164 | vm_map_t map, | |
165 | vm32_address_t addr, | |
166 | vm32_size_t size, | |
167 | vm_machine_attribute_t attribute, | |
168 | vm_machine_attribute_val_t* value) /* IN/OUT */ | |
169 | { | |
170 | if ((map == VM_MAP_NULL) || (addr + size < addr)) | |
171 | return(KERN_INVALID_ARGUMENT); | |
172 | ||
173 | return mach_vm_machine_attribute(map, addr, size, attribute, value); | |
174 | } | |
175 | ||
176 | kern_return_t | |
177 | vm32_read( | |
178 | vm_map_t map, | |
179 | vm32_address_t addr, | |
180 | vm32_size_t size, | |
181 | pointer_t *data, | |
182 | mach_msg_type_number_t *data_size) | |
183 | { | |
184 | return mach_vm_read(map, addr, size, data, data_size); | |
185 | } | |
186 | ||
187 | kern_return_t | |
188 | vm32_read_list( | |
189 | vm_map_t map, | |
190 | vm32_read_entry_t data_list, | |
191 | natural_t count) | |
192 | { | |
193 | mach_vm_read_entry_t mdata_list; | |
194 | mach_msg_type_number_t i; | |
195 | kern_return_t result; | |
196 | ||
197 | for (i=0; i < VM_MAP_ENTRY_MAX; i++) { | |
198 | mdata_list[i].address = data_list[i].address; | |
199 | mdata_list[i].size = data_list[i].size; | |
200 | } | |
201 | ||
202 | result = mach_vm_read_list(map, mdata_list, count); | |
203 | ||
204 | for (i=0; i < VM_MAP_ENTRY_MAX; i++) { | |
205 | data_list[i].address = CAST_DOWN_EXPLICIT(vm32_address_t, mdata_list[i].address); | |
206 | data_list[i].size = CAST_DOWN_EXPLICIT(vm32_size_t, mdata_list[i].size); | |
207 | } | |
208 | ||
209 | return result; | |
210 | } | |
211 | ||
212 | kern_return_t | |
213 | vm32_read_overwrite( | |
214 | vm_map_t map, | |
215 | vm32_address_t address, | |
216 | vm32_size_t size, | |
217 | vm32_address_t data, | |
218 | vm32_size_t *data_size) | |
219 | { | |
220 | kern_return_t result; | |
221 | mach_vm_size_t mdata_size; | |
222 | ||
223 | mdata_size = *data_size; | |
224 | result = mach_vm_read_overwrite(map, address, size, data, &mdata_size); | |
225 | *data_size = CAST_DOWN_EXPLICIT(vm32_size_t, mdata_size); | |
226 | ||
227 | return result; | |
228 | } | |
229 | ||
230 | kern_return_t | |
231 | vm32_write( | |
232 | vm_map_t map, | |
233 | vm32_address_t address, | |
234 | pointer_t data, | |
235 | mach_msg_type_number_t size) | |
236 | { | |
237 | return mach_vm_write(map, address, data, size); | |
238 | } | |
239 | ||
240 | kern_return_t | |
241 | vm32_copy( | |
242 | vm_map_t map, | |
243 | vm32_address_t source_address, | |
244 | vm32_size_t size, | |
245 | vm32_address_t dest_address) | |
246 | { | |
247 | return mach_vm_copy(map, source_address, size, dest_address); | |
248 | } | |
249 | ||
250 | kern_return_t | |
251 | vm32_map_64( | |
252 | vm_map_t target_map, | |
253 | vm32_offset_t *address, | |
254 | vm32_size_t size, | |
255 | vm32_offset_t mask, | |
256 | int flags, | |
257 | ipc_port_t port, | |
258 | vm_object_offset_t offset, | |
259 | boolean_t copy, | |
260 | vm_prot_t cur_protection, | |
261 | vm_prot_t max_protection, | |
262 | vm_inherit_t inheritance) | |
263 | { | |
264 | mach_vm_offset_t maddress; | |
265 | kern_return_t result; | |
266 | ||
267 | maddress = *address; | |
5ba3f43e | 268 | result = mach_vm_map_external(target_map, &maddress, size, mask, |
b0d623f7 A |
269 | flags, port, offset, copy, |
270 | cur_protection, max_protection, inheritance); | |
271 | *address = CAST_DOWN_EXPLICIT(vm32_offset_t, maddress); | |
272 | ||
273 | return result; | |
274 | } | |
275 | ||
276 | kern_return_t | |
277 | vm32_map( | |
278 | vm_map_t target_map, | |
279 | vm32_offset_t *address, | |
280 | vm32_size_t size, | |
281 | vm32_offset_t mask, | |
282 | int flags, | |
283 | ipc_port_t port, | |
284 | vm32_offset_t offset, | |
285 | boolean_t copy, | |
286 | vm_prot_t cur_protection, | |
287 | vm_prot_t max_protection, | |
288 | vm_inherit_t inheritance) | |
289 | { | |
290 | return vm32_map_64(target_map, address, size, mask, | |
291 | flags, port, offset, copy, | |
292 | cur_protection, max_protection, inheritance); | |
293 | } | |
294 | ||
295 | kern_return_t | |
296 | vm32_remap( | |
297 | vm_map_t target_map, | |
298 | vm32_offset_t *address, | |
299 | vm32_size_t size, | |
300 | vm32_offset_t mask, | |
301 | boolean_t anywhere, | |
302 | vm_map_t src_map, | |
303 | vm32_offset_t memory_address, | |
304 | boolean_t copy, | |
305 | vm_prot_t *cur_protection, | |
306 | vm_prot_t *max_protection, | |
307 | vm_inherit_t inheritance) | |
308 | { | |
309 | mach_vm_offset_t maddress; | |
310 | kern_return_t result; | |
311 | ||
312 | maddress = *address; | |
5ba3f43e | 313 | result = mach_vm_remap_external(target_map, &maddress, size, mask, |
b0d623f7 A |
314 | anywhere, src_map, memory_address, copy, |
315 | cur_protection, max_protection, inheritance); | |
316 | *address = CAST_DOWN_EXPLICIT(vm32_offset_t, maddress); | |
317 | ||
318 | return result; | |
319 | } | |
320 | ||
321 | kern_return_t | |
322 | vm32_msync( | |
323 | vm_map_t map, | |
324 | vm32_address_t address, | |
325 | vm32_size_t size, | |
326 | vm_sync_t sync_flags) | |
327 | { | |
328 | return mach_vm_msync(map, address, size, sync_flags); | |
329 | } | |
330 | ||
331 | kern_return_t | |
332 | vm32_behavior_set( | |
333 | vm_map_t map, | |
334 | vm32_offset_t start, | |
335 | vm32_size_t size, | |
336 | vm_behavior_t new_behavior) | |
337 | { | |
338 | if ((map == VM_MAP_NULL) || (start + size < start)) | |
339 | return(KERN_INVALID_ARGUMENT); | |
340 | ||
341 | return mach_vm_behavior_set(map, start, size, new_behavior); | |
342 | } | |
343 | ||
344 | kern_return_t | |
345 | vm32_region_64( | |
346 | vm_map_t map, | |
347 | vm32_offset_t *address, /* IN/OUT */ | |
348 | vm32_size_t *size, /* OUT */ | |
349 | vm_region_flavor_t flavor, /* IN */ | |
350 | vm_region_info_t info, /* OUT */ | |
351 | mach_msg_type_number_t *count, /* IN/OUT */ | |
352 | mach_port_t *object_name) /* OUT */ | |
353 | { | |
354 | mach_vm_offset_t maddress; | |
355 | mach_vm_size_t msize; | |
356 | kern_return_t result; | |
357 | ||
358 | maddress = *address; | |
359 | msize = *size; | |
360 | result = mach_vm_region(map, &maddress, &msize, flavor, info, count, object_name); | |
361 | *size = CAST_DOWN_EXPLICIT(vm32_size_t, msize); | |
362 | *address = CAST_DOWN_EXPLICIT(vm32_offset_t, maddress); | |
363 | ||
364 | return result; | |
365 | } | |
366 | ||
367 | kern_return_t | |
368 | vm32_region( | |
369 | vm_map_t map, | |
370 | vm32_address_t *address, /* IN/OUT */ | |
371 | vm32_size_t *size, /* OUT */ | |
372 | vm_region_flavor_t flavor, /* IN */ | |
373 | vm_region_info_t info, /* OUT */ | |
374 | mach_msg_type_number_t *count, /* IN/OUT */ | |
375 | mach_port_t *object_name) /* OUT */ | |
376 | { | |
377 | vm_map_address_t map_addr; | |
378 | vm_map_size_t map_size; | |
379 | kern_return_t kr; | |
380 | ||
381 | if (VM_MAP_NULL == map) | |
382 | return KERN_INVALID_ARGUMENT; | |
383 | ||
384 | map_addr = (vm_map_address_t)*address; | |
385 | map_size = (vm_map_size_t)*size; | |
386 | ||
387 | kr = vm_map_region(map, | |
388 | &map_addr, &map_size, | |
389 | flavor, info, count, | |
390 | object_name); | |
391 | ||
392 | *address = CAST_DOWN_EXPLICIT(vm32_address_t, map_addr); | |
393 | *size = CAST_DOWN_EXPLICIT(vm32_size_t, map_size); | |
394 | ||
395 | if (KERN_SUCCESS == kr && map_addr + map_size > VM32_MAX_ADDRESS) | |
396 | return KERN_INVALID_ADDRESS; | |
397 | return kr; | |
398 | } | |
399 | ||
400 | kern_return_t | |
401 | vm32_region_recurse_64( | |
402 | vm_map_t map, | |
403 | vm32_address_t *address, | |
404 | vm32_size_t *size, | |
405 | uint32_t *depth, | |
406 | vm_region_recurse_info_64_t info, | |
407 | mach_msg_type_number_t *infoCnt) | |
408 | { | |
409 | mach_vm_address_t maddress; | |
410 | mach_vm_size_t msize; | |
411 | kern_return_t result; | |
412 | ||
413 | maddress = *address; | |
414 | msize = *size; | |
415 | result = mach_vm_region_recurse(map, &maddress, &msize, depth, info, infoCnt); | |
416 | *address = CAST_DOWN_EXPLICIT(vm32_address_t, maddress); | |
417 | *size = CAST_DOWN_EXPLICIT(vm32_size_t, msize); | |
418 | ||
419 | return result; | |
420 | } | |
421 | ||
422 | kern_return_t | |
423 | vm32_region_recurse( | |
424 | vm_map_t map, | |
425 | vm32_offset_t *address, /* IN/OUT */ | |
426 | vm32_size_t *size, /* OUT */ | |
427 | natural_t *depth, /* IN/OUT */ | |
428 | vm_region_recurse_info_t info32, /* IN/OUT */ | |
429 | mach_msg_type_number_t *infoCnt) /* IN/OUT */ | |
430 | { | |
431 | vm_region_submap_info_data_64_t info64; | |
432 | vm_region_submap_info_t info; | |
433 | vm_map_address_t map_addr; | |
434 | vm_map_size_t map_size; | |
435 | kern_return_t kr; | |
436 | ||
437 | if (VM_MAP_NULL == map || *infoCnt < VM_REGION_SUBMAP_INFO_COUNT) | |
438 | return KERN_INVALID_ARGUMENT; | |
439 | ||
440 | ||
441 | map_addr = (vm_map_address_t)*address; | |
442 | map_size = (vm_map_size_t)*size; | |
443 | info = (vm_region_submap_info_t)info32; | |
444 | *infoCnt = VM_REGION_SUBMAP_INFO_COUNT_64; | |
445 | ||
446 | kr = vm_map_region_recurse_64(map, &map_addr,&map_size, | |
447 | depth, &info64, infoCnt); | |
448 | ||
449 | info->protection = info64.protection; | |
450 | info->max_protection = info64.max_protection; | |
451 | info->inheritance = info64.inheritance; | |
452 | info->offset = (uint32_t)info64.offset; /* trouble-maker */ | |
453 | info->user_tag = info64.user_tag; | |
454 | info->pages_resident = info64.pages_resident; | |
455 | info->pages_shared_now_private = info64.pages_shared_now_private; | |
456 | info->pages_swapped_out = info64.pages_swapped_out; | |
457 | info->pages_dirtied = info64.pages_dirtied; | |
458 | info->ref_count = info64.ref_count; | |
459 | info->shadow_depth = info64.shadow_depth; | |
460 | info->external_pager = info64.external_pager; | |
461 | info->share_mode = info64.share_mode; | |
462 | info->is_submap = info64.is_submap; | |
463 | info->behavior = info64.behavior; | |
464 | info->object_id = info64.object_id; | |
465 | info->user_wired_count = info64.user_wired_count; | |
466 | ||
467 | *address = CAST_DOWN_EXPLICIT(vm32_address_t, map_addr); | |
468 | *size = CAST_DOWN_EXPLICIT(vm32_size_t, map_size); | |
469 | *infoCnt = VM_REGION_SUBMAP_INFO_COUNT; | |
470 | ||
471 | if (KERN_SUCCESS == kr && map_addr + map_size > VM32_MAX_ADDRESS) | |
472 | return KERN_INVALID_ADDRESS; | |
473 | return kr; | |
474 | } | |
475 | ||
476 | kern_return_t | |
477 | vm32_purgable_control( | |
478 | vm_map_t map, | |
479 | vm32_offset_t address, | |
480 | vm_purgable_t control, | |
481 | int *state) | |
482 | { | |
483 | if (VM_MAP_NULL == map) | |
484 | return KERN_INVALID_ARGUMENT; | |
485 | ||
486 | return vm_map_purgable_control(map, | |
39236c6e | 487 | vm_map_trunc_page(address, PAGE_MASK), |
b0d623f7 A |
488 | control, |
489 | state); | |
490 | } | |
491 | ||
492 | kern_return_t | |
493 | vm32_map_page_query( | |
494 | vm_map_t map, | |
495 | vm32_offset_t offset, | |
496 | int *disposition, | |
497 | int *ref_count) | |
498 | { | |
499 | if (VM_MAP_NULL == map) | |
500 | return KERN_INVALID_ARGUMENT; | |
501 | ||
39236c6e A |
502 | return vm_map_page_query_internal( |
503 | map, | |
504 | vm_map_trunc_page(offset, PAGE_MASK), | |
505 | disposition, | |
506 | ref_count); | |
b0d623f7 A |
507 | } |
508 | ||
509 | kern_return_t | |
510 | vm32_make_memory_entry_64( | |
511 | vm_map_t target_map, | |
512 | memory_object_size_t *size, | |
513 | memory_object_offset_t offset, | |
514 | vm_prot_t permission, | |
515 | ipc_port_t *object_handle, | |
516 | ipc_port_t parent_handle) | |
517 | { | |
518 | // use the existing entrypoint | |
519 | return _mach_make_memory_entry(target_map, size, offset, permission, object_handle, parent_handle); | |
520 | } | |
521 | ||
522 | kern_return_t | |
523 | vm32_make_memory_entry( | |
524 | vm_map_t target_map, | |
525 | vm32_size_t *size, | |
526 | vm32_offset_t offset, | |
527 | vm_prot_t permission, | |
528 | ipc_port_t *object_handle, | |
529 | ipc_port_t parent_entry) | |
530 | { | |
531 | memory_object_size_t mo_size; | |
532 | kern_return_t kr; | |
533 | ||
534 | mo_size = (memory_object_size_t)*size; | |
535 | kr = _mach_make_memory_entry(target_map, &mo_size, | |
536 | (memory_object_offset_t)offset, permission, object_handle, | |
537 | parent_entry); | |
538 | *size = CAST_DOWN_EXPLICIT(vm32_size_t, mo_size); | |
539 | return kr; | |
540 | } | |
541 | ||
542 | kern_return_t | |
543 | vm32__task_wire( | |
544 | vm_map_t map, | |
545 | boolean_t must_wire) | |
546 | { | |
547 | if (map == VM_MAP_NULL) | |
548 | return(KERN_INVALID_ARGUMENT); | |
549 | ||
d9a64523 A |
550 | vm_map_lock(map); |
551 | map->wiring_required = (must_wire == TRUE); | |
552 | vm_map_unlock(map); | |
b0d623f7 A |
553 | |
554 | return(KERN_SUCCESS); | |
555 | } | |
556 | ||
a39ff7e2 A |
557 | kern_return_t |
558 | vm32__map_exec_lockdown( | |
559 | vm_map_t map) | |
560 | { | |
561 | if (map == VM_MAP_NULL) | |
562 | return(KERN_INVALID_ARGUMENT); | |
563 | ||
564 | vm_map_lock(map); | |
565 | map->map_disallow_new_exec = TRUE; | |
566 | vm_map_unlock(map); | |
567 | ||
568 | return(KERN_SUCCESS); | |
569 | } | |
570 | ||
571 | ||
b0d623f7 | 572 | #endif /* VM32_SUPPORT */ |