1 | /* |
2 | * Copyright (c) 2008-2016 Apple Inc. All rights reserved. |
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 | |
93 | #ifdef VM32_SUPPORT |
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; |
117 | result = mach_vm_allocate_external(map, &maddr, size, flags); |
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; |
268 | result = mach_vm_map_external(target_map, &maddress, size, mask, |
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; |
313 | result = mach_vm_remap_external(target_map, &maddress, size, mask, |
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, |
487 | vm_map_trunc_page(address, PAGE_MASK), |
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 | |
502 | return vm_map_page_query_internal( |
503 | map, |
504 | vm_map_trunc_page(offset, PAGE_MASK), |
505 | disposition, |
506 | ref_count); |
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 | |
550 | vm_map_lock(map); |
551 | map->wiring_required = (must_wire == TRUE); |
552 | vm_map_unlock(map); |
553 | |
554 | return(KERN_SUCCESS); |
555 | } |
556 | |
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 | |
572 | #endif /* VM32_SUPPORT */ |
573 | |