]> git.saurik.com Git - apple/xnu.git/blob - osfmk/vm/vm_fourk_pager.c
xnu-7195.60.75.tar.gz
[apple/xnu.git] / osfmk / vm / vm_fourk_pager.c
1 /*
2 * Copyright (c) 2014-2020 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 #include <sys/errno.h>
30
31 #include <mach/mach_types.h>
32 #include <mach/mach_traps.h>
33 #include <mach/host_priv.h>
34 #include <mach/kern_return.h>
35 #include <mach/memory_object_control.h>
36 #include <mach/memory_object_types.h>
37 #include <mach/port.h>
38 #include <mach/policy.h>
39 #include <mach/upl.h>
40 #include <mach/thread_act.h>
41 #include <mach/mach_vm.h>
42
43 #include <kern/host.h>
44 #include <kern/kalloc.h>
45 #include <kern/page_decrypt.h>
46 #include <kern/queue.h>
47 #include <kern/thread.h>
48 #include <kern/ipc_kobject.h>
49
50 #include <ipc/ipc_port.h>
51 #include <ipc/ipc_space.h>
52
53 #include <vm/vm_fault.h>
54 #include <vm/vm_map.h>
55 #include <vm/vm_pageout.h>
56 #include <vm/memory_object.h>
57 #include <vm/vm_pageout.h>
58 #include <vm/vm_protos.h>
59 #include <vm/vm_kern.h>
60
61
62 /*
63 * 4K MEMORY PAGER
64 *
65 * This external memory manager (EMM) handles memory mappings that are
66 * 4K-aligned but not page-aligned and can therefore not be mapped directly.
67 *
68 * It mostly handles page-in requests (from memory_object_data_request()) by
69 * getting the data needed to fill in each 4K-chunk. That can require
70 * getting data from one or two pages from its backing VM object
71 * (a file or a "apple-protected" pager backed by an encrypted file), and
72 * copies the data to another page so that it is aligned as expected by
73 * the mapping.
74 *
75 * Returned pages can never be dirtied and must always be mapped copy-on-write,
76 * so the memory manager does not need to handle page-out requests (from
77 * memory_object_data_return()).
78 *
79 */
80
81 /* forward declarations */
82 void fourk_pager_reference(memory_object_t mem_obj);
83 void fourk_pager_deallocate(memory_object_t mem_obj);
84 kern_return_t fourk_pager_init(memory_object_t mem_obj,
85 memory_object_control_t control,
86 memory_object_cluster_size_t pg_size);
87 kern_return_t fourk_pager_terminate(memory_object_t mem_obj);
88 kern_return_t fourk_pager_data_request(memory_object_t mem_obj,
89 memory_object_offset_t offset,
90 memory_object_cluster_size_t length,
91 vm_prot_t protection_required,
92 memory_object_fault_info_t fault_info);
93 kern_return_t fourk_pager_data_return(memory_object_t mem_obj,
94 memory_object_offset_t offset,
95 memory_object_cluster_size_t data_cnt,
96 memory_object_offset_t *resid_offset,
97 int *io_error,
98 boolean_t dirty,
99 boolean_t kernel_copy,
100 int upl_flags);
101 kern_return_t fourk_pager_data_initialize(memory_object_t mem_obj,
102 memory_object_offset_t offset,
103 memory_object_cluster_size_t data_cnt);
104 kern_return_t fourk_pager_data_unlock(memory_object_t mem_obj,
105 memory_object_offset_t offset,
106 memory_object_size_t size,
107 vm_prot_t desired_access);
108 kern_return_t fourk_pager_synchronize(memory_object_t mem_obj,
109 memory_object_offset_t offset,
110 memory_object_size_t length,
111 vm_sync_t sync_flags);
112 kern_return_t fourk_pager_map(memory_object_t mem_obj,
113 vm_prot_t prot);
114 kern_return_t fourk_pager_last_unmap(memory_object_t mem_obj);
115
116 /*
117 * Vector of VM operations for this EMM.
118 * These routines are invoked by VM via the memory_object_*() interfaces.
119 */
120 const struct memory_object_pager_ops fourk_pager_ops = {
121 .memory_object_reference = fourk_pager_reference,
122 .memory_object_deallocate = fourk_pager_deallocate,
123 .memory_object_init = fourk_pager_init,
124 .memory_object_terminate = fourk_pager_terminate,
125 .memory_object_data_request = fourk_pager_data_request,
126 .memory_object_data_return = fourk_pager_data_return,
127 .memory_object_data_initialize = fourk_pager_data_initialize,
128 .memory_object_data_unlock = fourk_pager_data_unlock,
129 .memory_object_synchronize = fourk_pager_synchronize,
130 .memory_object_map = fourk_pager_map,
131 .memory_object_last_unmap = fourk_pager_last_unmap,
132 .memory_object_data_reclaim = NULL,
133 .memory_object_pager_name = "fourk_pager"
134 };
135
136 /*
137 * The "fourk_pager" describes a memory object backed by
138 * the "4K" EMM.
139 */
140 #define FOURK_PAGER_SLOTS 4 /* 16K / 4K */
141 typedef struct fourk_pager_backing {
142 vm_object_t backing_object;
143 vm_object_offset_t backing_offset;
144 } *fourk_pager_backing_t;
145 typedef struct fourk_pager {
146 /* mandatory generic header */
147 struct memory_object fourk_pgr_hdr;
148
149 /* pager-specific data */
150 queue_chain_t pager_queue; /* next & prev pagers */
151 unsigned int ref_count; /* reference count */
152 int is_ready; /* is this pager ready ? */
153 int is_mapped; /* is this mem_obj mapped ? */
154 struct fourk_pager_backing slots[FOURK_PAGER_SLOTS]; /* backing for each
155 * 4K-chunk */
156 } *fourk_pager_t;
157 #define FOURK_PAGER_NULL ((fourk_pager_t) NULL)
158
159 /*
160 * List of memory objects managed by this EMM.
161 * The list is protected by the "fourk_pager_lock" lock.
162 */
163 int fourk_pager_count = 0; /* number of pagers */
164 int fourk_pager_count_mapped = 0; /* number of unmapped pagers */
165 queue_head_t fourk_pager_queue = QUEUE_HEAD_INITIALIZER(fourk_pager_queue);
166 LCK_GRP_DECLARE(fourk_pager_lck_grp, "4K-pager");
167 LCK_MTX_DECLARE(fourk_pager_lock, &fourk_pager_lck_grp);
168
169 /*
170 * Maximum number of unmapped pagers we're willing to keep around.
171 */
172 int fourk_pager_cache_limit = 0;
173
174 /*
175 * Statistics & counters.
176 */
177 int fourk_pager_count_max = 0;
178 int fourk_pager_count_unmapped_max = 0;
179 int fourk_pager_num_trim_max = 0;
180 int fourk_pager_num_trim_total = 0;
181
182 /* internal prototypes */
183 fourk_pager_t fourk_pager_lookup(memory_object_t mem_obj);
184 void fourk_pager_dequeue(fourk_pager_t pager);
185 void fourk_pager_deallocate_internal(fourk_pager_t pager,
186 boolean_t locked);
187 void fourk_pager_terminate_internal(fourk_pager_t pager);
188 void fourk_pager_trim(void);
189
190
191 #if DEBUG
192 int fourk_pagerdebug = 0;
193 #define PAGER_ALL 0xffffffff
194 #define PAGER_INIT 0x00000001
195 #define PAGER_PAGEIN 0x00000002
196
197 #define PAGER_DEBUG(LEVEL, A) \
198 MACRO_BEGIN \
199 if ((fourk_pagerdebug & LEVEL)==LEVEL) { \
200 printf A; \
201 } \
202 MACRO_END
203 #else
204 #define PAGER_DEBUG(LEVEL, A)
205 #endif
206
207
208 /*
209 * fourk_pager_init()
210 *
211 * Initialize the memory object and makes it ready to be used and mapped.
212 */
213 kern_return_t
214 fourk_pager_init(
215 memory_object_t mem_obj,
216 memory_object_control_t control,
217 #if !DEBUG
218 __unused
219 #endif
220 memory_object_cluster_size_t pg_size)
221 {
222 fourk_pager_t pager;
223 kern_return_t kr;
224 memory_object_attr_info_data_t attributes;
225
226 PAGER_DEBUG(PAGER_ALL,
227 ("fourk_pager_init: %p, %p, %x\n",
228 mem_obj, control, pg_size));
229
230 if (control == MEMORY_OBJECT_CONTROL_NULL) {
231 return KERN_INVALID_ARGUMENT;
232 }
233
234 pager = fourk_pager_lookup(mem_obj);
235
236 memory_object_control_reference(control);
237
238 pager->fourk_pgr_hdr.mo_control = control;
239
240 attributes.copy_strategy = MEMORY_OBJECT_COPY_DELAY;
241 /* attributes.cluster_size = (1 << (CLUSTER_SHIFT + PAGE_SHIFT));*/
242 attributes.cluster_size = (1 << (PAGE_SHIFT));
243 attributes.may_cache_object = FALSE;
244 attributes.temporary = TRUE;
245
246 kr = memory_object_change_attributes(
247 control,
248 MEMORY_OBJECT_ATTRIBUTE_INFO,
249 (memory_object_info_t) &attributes,
250 MEMORY_OBJECT_ATTR_INFO_COUNT);
251 if (kr != KERN_SUCCESS) {
252 panic("fourk_pager_init: "
253 "memory_object_change_attributes() failed");
254 }
255
256 #if CONFIG_SECLUDED_MEMORY
257 if (secluded_for_filecache) {
258 memory_object_mark_eligible_for_secluded(control, TRUE);
259 }
260 #endif /* CONFIG_SECLUDED_MEMORY */
261
262 return KERN_SUCCESS;
263 }
264
265 /*
266 * fourk_pager_data_return()
267 *
268 * Handles page-out requests from VM. This should never happen since
269 * the pages provided by this EMM are not supposed to be dirty or dirtied
270 * and VM should simply discard the contents and reclaim the pages if it
271 * needs to.
272 */
273 kern_return_t
274 fourk_pager_data_return(
275 __unused memory_object_t mem_obj,
276 __unused memory_object_offset_t offset,
277 __unused memory_object_cluster_size_t data_cnt,
278 __unused memory_object_offset_t *resid_offset,
279 __unused int *io_error,
280 __unused boolean_t dirty,
281 __unused boolean_t kernel_copy,
282 __unused int upl_flags)
283 {
284 panic("fourk_pager_data_return: should never get called");
285 return KERN_FAILURE;
286 }
287
288 kern_return_t
289 fourk_pager_data_initialize(
290 __unused memory_object_t mem_obj,
291 __unused memory_object_offset_t offset,
292 __unused memory_object_cluster_size_t data_cnt)
293 {
294 panic("fourk_pager_data_initialize: should never get called");
295 return KERN_FAILURE;
296 }
297
298 kern_return_t
299 fourk_pager_data_unlock(
300 __unused memory_object_t mem_obj,
301 __unused memory_object_offset_t offset,
302 __unused memory_object_size_t size,
303 __unused vm_prot_t desired_access)
304 {
305 return KERN_FAILURE;
306 }
307
308 /*
309 * fourk_pager_reference()
310 *
311 * Get a reference on this memory object.
312 * For external usage only. Assumes that the initial reference count is not 0,
313 * i.e one should not "revive" a dead pager this way.
314 */
315 void
316 fourk_pager_reference(
317 memory_object_t mem_obj)
318 {
319 fourk_pager_t pager;
320
321 pager = fourk_pager_lookup(mem_obj);
322
323 lck_mtx_lock(&fourk_pager_lock);
324 assert(pager->ref_count > 0);
325 pager->ref_count++;
326 lck_mtx_unlock(&fourk_pager_lock);
327 }
328
329
330 /*
331 * fourk_pager_dequeue:
332 *
333 * Removes a pager from the list of pagers.
334 *
335 * The caller must hold "fourk_pager_lock".
336 */
337 void
338 fourk_pager_dequeue(
339 fourk_pager_t pager)
340 {
341 assert(!pager->is_mapped);
342
343 queue_remove(&fourk_pager_queue,
344 pager,
345 fourk_pager_t,
346 pager_queue);
347 pager->pager_queue.next = NULL;
348 pager->pager_queue.prev = NULL;
349
350 fourk_pager_count--;
351 }
352
353 /*
354 * fourk_pager_terminate_internal:
355 *
356 * Trigger the asynchronous termination of the memory object associated
357 * with this pager.
358 * When the memory object is terminated, there will be one more call
359 * to memory_object_deallocate() (i.e. fourk_pager_deallocate())
360 * to finish the clean up.
361 *
362 * "fourk_pager_lock" should not be held by the caller.
363 * We don't need the lock because the pager has already been removed from
364 * the pagers' list and is now ours exclusively.
365 */
366 void
367 fourk_pager_terminate_internal(
368 fourk_pager_t pager)
369 {
370 int i;
371
372 assert(pager->is_ready);
373 assert(!pager->is_mapped);
374
375 for (i = 0; i < FOURK_PAGER_SLOTS; i++) {
376 if (pager->slots[i].backing_object != VM_OBJECT_NULL &&
377 pager->slots[i].backing_object != (vm_object_t) -1) {
378 vm_object_deallocate(pager->slots[i].backing_object);
379 pager->slots[i].backing_object = (vm_object_t) -1;
380 pager->slots[i].backing_offset = (vm_object_offset_t) -1;
381 }
382 }
383
384 /* trigger the destruction of the memory object */
385 memory_object_destroy(pager->fourk_pgr_hdr.mo_control, 0);
386 }
387
388 /*
389 * fourk_pager_deallocate_internal()
390 *
391 * Release a reference on this pager and free it when the last
392 * reference goes away.
393 * Can be called with fourk_pager_lock held or not but always returns
394 * with it unlocked.
395 */
396 void
397 fourk_pager_deallocate_internal(
398 fourk_pager_t pager,
399 boolean_t locked)
400 {
401 boolean_t needs_trimming;
402 int count_unmapped;
403
404 if (!locked) {
405 lck_mtx_lock(&fourk_pager_lock);
406 }
407
408 count_unmapped = (fourk_pager_count -
409 fourk_pager_count_mapped);
410 if (count_unmapped > fourk_pager_cache_limit) {
411 /* we have too many unmapped pagers: trim some */
412 needs_trimming = TRUE;
413 } else {
414 needs_trimming = FALSE;
415 }
416
417 /* drop a reference on this pager */
418 pager->ref_count--;
419
420 if (pager->ref_count == 1) {
421 /*
422 * Only the "named" reference is left, which means that
423 * no one is really holding on to this pager anymore.
424 * Terminate it.
425 */
426 fourk_pager_dequeue(pager);
427 /* the pager is all ours: no need for the lock now */
428 lck_mtx_unlock(&fourk_pager_lock);
429 fourk_pager_terminate_internal(pager);
430 } else if (pager->ref_count == 0) {
431 /*
432 * Dropped the existence reference; the memory object has
433 * been terminated. Do some final cleanup and release the
434 * pager structure.
435 */
436 lck_mtx_unlock(&fourk_pager_lock);
437 if (pager->fourk_pgr_hdr.mo_control != MEMORY_OBJECT_CONTROL_NULL) {
438 memory_object_control_deallocate(pager->fourk_pgr_hdr.mo_control);
439 pager->fourk_pgr_hdr.mo_control = MEMORY_OBJECT_CONTROL_NULL;
440 }
441 kfree(pager, sizeof(*pager));
442 pager = FOURK_PAGER_NULL;
443 } else {
444 /* there are still plenty of references: keep going... */
445 lck_mtx_unlock(&fourk_pager_lock);
446 }
447
448 if (needs_trimming) {
449 fourk_pager_trim();
450 }
451 /* caution: lock is not held on return... */
452 }
453
454 /*
455 * fourk_pager_deallocate()
456 *
457 * Release a reference on this pager and free it when the last
458 * reference goes away.
459 */
460 void
461 fourk_pager_deallocate(
462 memory_object_t mem_obj)
463 {
464 fourk_pager_t pager;
465
466 PAGER_DEBUG(PAGER_ALL, ("fourk_pager_deallocate: %p\n", mem_obj));
467 pager = fourk_pager_lookup(mem_obj);
468 fourk_pager_deallocate_internal(pager, FALSE);
469 }
470
471 /*
472 *
473 */
474 kern_return_t
475 fourk_pager_terminate(
476 #if !DEBUG
477 __unused
478 #endif
479 memory_object_t mem_obj)
480 {
481 PAGER_DEBUG(PAGER_ALL, ("fourk_pager_terminate: %p\n", mem_obj));
482
483 return KERN_SUCCESS;
484 }
485
486 /*
487 *
488 */
489 kern_return_t
490 fourk_pager_synchronize(
491 __unused memory_object_t mem_obj,
492 __unused memory_object_offset_t offset,
493 __unused memory_object_size_t length,
494 __unused vm_sync_t sync_flags)
495 {
496 panic("fourk_pager_synchronize: memory_object_synchronize no longer supported\n");
497 return KERN_FAILURE;
498 }
499
500 /*
501 * fourk_pager_map()
502 *
503 * This allows VM to let us, the EMM, know that this memory object
504 * is currently mapped one or more times. This is called by VM each time
505 * the memory object gets mapped and we take one extra reference on the
506 * memory object to account for all its mappings.
507 */
508 kern_return_t
509 fourk_pager_map(
510 memory_object_t mem_obj,
511 __unused vm_prot_t prot)
512 {
513 fourk_pager_t pager;
514
515 PAGER_DEBUG(PAGER_ALL, ("fourk_pager_map: %p\n", mem_obj));
516
517 pager = fourk_pager_lookup(mem_obj);
518
519 lck_mtx_lock(&fourk_pager_lock);
520 assert(pager->is_ready);
521 assert(pager->ref_count > 0); /* pager is alive */
522 if (pager->is_mapped == FALSE) {
523 /*
524 * First mapping of this pager: take an extra reference
525 * that will remain until all the mappings of this pager
526 * are removed.
527 */
528 pager->is_mapped = TRUE;
529 pager->ref_count++;
530 fourk_pager_count_mapped++;
531 }
532 lck_mtx_unlock(&fourk_pager_lock);
533
534 return KERN_SUCCESS;
535 }
536
537 /*
538 * fourk_pager_last_unmap()
539 *
540 * This is called by VM when this memory object is no longer mapped anywhere.
541 */
542 kern_return_t
543 fourk_pager_last_unmap(
544 memory_object_t mem_obj)
545 {
546 fourk_pager_t pager;
547 int count_unmapped;
548
549 PAGER_DEBUG(PAGER_ALL,
550 ("fourk_pager_last_unmap: %p\n", mem_obj));
551
552 pager = fourk_pager_lookup(mem_obj);
553
554 lck_mtx_lock(&fourk_pager_lock);
555 if (pager->is_mapped) {
556 /*
557 * All the mappings are gone, so let go of the one extra
558 * reference that represents all the mappings of this pager.
559 */
560 fourk_pager_count_mapped--;
561 count_unmapped = (fourk_pager_count -
562 fourk_pager_count_mapped);
563 if (count_unmapped > fourk_pager_count_unmapped_max) {
564 fourk_pager_count_unmapped_max = count_unmapped;
565 }
566 pager->is_mapped = FALSE;
567 fourk_pager_deallocate_internal(pager, TRUE);
568 /* caution: deallocate_internal() released the lock ! */
569 } else {
570 lck_mtx_unlock(&fourk_pager_lock);
571 }
572
573 return KERN_SUCCESS;
574 }
575
576
577 /*
578 *
579 */
580 fourk_pager_t
581 fourk_pager_lookup(
582 memory_object_t mem_obj)
583 {
584 fourk_pager_t pager;
585
586 assert(mem_obj->mo_pager_ops == &fourk_pager_ops);
587 pager = (fourk_pager_t) mem_obj;
588 assert(pager->ref_count > 0);
589 return pager;
590 }
591
592 void
593 fourk_pager_trim(void)
594 {
595 fourk_pager_t pager, prev_pager;
596 queue_head_t trim_queue;
597 int num_trim;
598 int count_unmapped;
599
600 lck_mtx_lock(&fourk_pager_lock);
601
602 /*
603 * We have too many pagers, try and trim some unused ones,
604 * starting with the oldest pager at the end of the queue.
605 */
606 queue_init(&trim_queue);
607 num_trim = 0;
608
609 for (pager = (fourk_pager_t)
610 queue_last(&fourk_pager_queue);
611 !queue_end(&fourk_pager_queue,
612 (queue_entry_t) pager);
613 pager = prev_pager) {
614 /* get prev elt before we dequeue */
615 prev_pager = (fourk_pager_t)
616 queue_prev(&pager->pager_queue);
617
618 if (pager->ref_count == 2 &&
619 pager->is_ready &&
620 !pager->is_mapped) {
621 /* this pager can be trimmed */
622 num_trim++;
623 /* remove this pager from the main list ... */
624 fourk_pager_dequeue(pager);
625 /* ... and add it to our trim queue */
626 queue_enter_first(&trim_queue,
627 pager,
628 fourk_pager_t,
629 pager_queue);
630
631 count_unmapped = (fourk_pager_count -
632 fourk_pager_count_mapped);
633 if (count_unmapped <= fourk_pager_cache_limit) {
634 /* we have enough pagers to trim */
635 break;
636 }
637 }
638 }
639 if (num_trim > fourk_pager_num_trim_max) {
640 fourk_pager_num_trim_max = num_trim;
641 }
642 fourk_pager_num_trim_total += num_trim;
643
644 lck_mtx_unlock(&fourk_pager_lock);
645
646 /* terminate the trimmed pagers */
647 while (!queue_empty(&trim_queue)) {
648 queue_remove_first(&trim_queue,
649 pager,
650 fourk_pager_t,
651 pager_queue);
652 pager->pager_queue.next = NULL;
653 pager->pager_queue.prev = NULL;
654 assert(pager->ref_count == 2);
655 /*
656 * We can't call deallocate_internal() because the pager
657 * has already been dequeued, but we still need to remove
658 * a reference.
659 */
660 pager->ref_count--;
661 fourk_pager_terminate_internal(pager);
662 }
663 }
664
665
666
667
668
669
670 vm_object_t
671 fourk_pager_to_vm_object(
672 memory_object_t mem_obj)
673 {
674 fourk_pager_t pager;
675 vm_object_t object;
676
677 pager = fourk_pager_lookup(mem_obj);
678 if (pager == NULL) {
679 return VM_OBJECT_NULL;
680 }
681
682 assert(pager->ref_count > 0);
683 assert(pager->fourk_pgr_hdr.mo_control != MEMORY_OBJECT_CONTROL_NULL);
684 object = memory_object_control_to_vm_object(pager->fourk_pgr_hdr.mo_control);
685 assert(object != VM_OBJECT_NULL);
686 return object;
687 }
688
689 memory_object_t
690 fourk_pager_create(void)
691 {
692 fourk_pager_t pager;
693 memory_object_control_t control;
694 kern_return_t kr;
695 int i;
696
697 #if 00
698 if (PAGE_SIZE_64 == FOURK_PAGE_SIZE) {
699 panic("fourk_pager_create: page size is 4K !?");
700 }
701 #endif
702
703 pager = (fourk_pager_t) kalloc(sizeof(*pager));
704 if (pager == FOURK_PAGER_NULL) {
705 return MEMORY_OBJECT_NULL;
706 }
707 bzero(pager, sizeof(*pager));
708
709 /*
710 * The vm_map call takes both named entry ports and raw memory
711 * objects in the same parameter. We need to make sure that
712 * vm_map does not see this object as a named entry port. So,
713 * we reserve the first word in the object for a fake ip_kotype
714 * setting - that will tell vm_map to use it as a memory object.
715 */
716 pager->fourk_pgr_hdr.mo_ikot = IKOT_MEMORY_OBJECT;
717 pager->fourk_pgr_hdr.mo_pager_ops = &fourk_pager_ops;
718 pager->fourk_pgr_hdr.mo_control = MEMORY_OBJECT_CONTROL_NULL;
719
720 pager->ref_count = 2; /* existence + setup reference */
721 pager->is_ready = FALSE;/* not ready until it has a "name" */
722 pager->is_mapped = FALSE;
723
724 for (i = 0; i < FOURK_PAGER_SLOTS; i++) {
725 pager->slots[i].backing_object = (vm_object_t) -1;
726 pager->slots[i].backing_offset = (vm_object_offset_t) -1;
727 }
728
729 lck_mtx_lock(&fourk_pager_lock);
730
731 /* enter new pager at the head of our list of pagers */
732 queue_enter_first(&fourk_pager_queue,
733 pager,
734 fourk_pager_t,
735 pager_queue);
736 fourk_pager_count++;
737 if (fourk_pager_count > fourk_pager_count_max) {
738 fourk_pager_count_max = fourk_pager_count;
739 }
740 lck_mtx_unlock(&fourk_pager_lock);
741
742 kr = memory_object_create_named((memory_object_t) pager,
743 0,
744 &control);
745 assert(kr == KERN_SUCCESS);
746
747 memory_object_mark_trusted(control);
748
749 lck_mtx_lock(&fourk_pager_lock);
750 /* the new pager is now ready to be used */
751 pager->is_ready = TRUE;
752 lck_mtx_unlock(&fourk_pager_lock);
753
754 /* wakeup anyone waiting for this pager to be ready */
755 thread_wakeup(&pager->is_ready);
756
757 return (memory_object_t) pager;
758 }
759
760 /*
761 * fourk_pager_data_request()
762 *
763 * Handles page-in requests from VM.
764 */
765 int fourk_pager_data_request_debug = 0;
766 kern_return_t
767 fourk_pager_data_request(
768 memory_object_t mem_obj,
769 memory_object_offset_t offset,
770 memory_object_cluster_size_t length,
771 #if !DEBUG
772 __unused
773 #endif
774 vm_prot_t protection_required,
775 memory_object_fault_info_t mo_fault_info)
776 {
777 fourk_pager_t pager;
778 memory_object_control_t mo_control;
779 upl_t upl;
780 int upl_flags;
781 upl_size_t upl_size;
782 upl_page_info_t *upl_pl;
783 unsigned int pl_count;
784 vm_object_t dst_object;
785 kern_return_t kr, retval;
786 vm_map_offset_t kernel_mapping;
787 vm_offset_t src_vaddr, dst_vaddr;
788 vm_offset_t cur_offset;
789 int sub_page;
790 int sub_page_idx, sub_page_cnt;
791
792 pager = fourk_pager_lookup(mem_obj);
793 assert(pager->is_ready);
794 assert(pager->ref_count > 1); /* pager is alive and mapped */
795
796 PAGER_DEBUG(PAGER_PAGEIN, ("fourk_pager_data_request: %p, %llx, %x, %x, pager %p\n", mem_obj, offset, length, protection_required, pager));
797
798 retval = KERN_SUCCESS;
799 kernel_mapping = 0;
800
801 offset = memory_object_trunc_page(offset);
802
803 /*
804 * Gather in a UPL all the VM pages requested by VM.
805 */
806 mo_control = pager->fourk_pgr_hdr.mo_control;
807
808 upl_size = length;
809 upl_flags =
810 UPL_RET_ONLY_ABSENT |
811 UPL_SET_LITE |
812 UPL_NO_SYNC |
813 UPL_CLEAN_IN_PLACE | /* triggers UPL_CLEAR_DIRTY */
814 UPL_SET_INTERNAL;
815 pl_count = 0;
816 kr = memory_object_upl_request(mo_control,
817 offset, upl_size,
818 &upl, NULL, NULL, upl_flags, VM_KERN_MEMORY_NONE);
819 if (kr != KERN_SUCCESS) {
820 retval = kr;
821 goto done;
822 }
823 dst_object = mo_control->moc_object;
824 assert(dst_object != VM_OBJECT_NULL);
825
826 #if __x86_64__ || __arm__ || __arm64__
827 /* use the 1-to-1 mapping of physical memory */
828 #else /* __x86_64__ || __arm__ || __arm64__ */
829 /*
830 * Reserve 2 virtual pages in the kernel address space to map the
831 * source and destination physical pages when it's their turn to
832 * be processed.
833 */
834 vm_map_entry_t map_entry;
835
836 vm_object_reference(kernel_object); /* ref. for mapping */
837 kr = vm_map_find_space(kernel_map,
838 &kernel_mapping,
839 2 * PAGE_SIZE_64,
840 0,
841 0,
842 VM_MAP_KERNEL_FLAGS_NONE,
843 &map_entry);
844 if (kr != KERN_SUCCESS) {
845 vm_object_deallocate(kernel_object);
846 retval = kr;
847 goto done;
848 }
849 map_entry->object.vm_object = kernel_object;
850 map_entry->offset = kernel_mapping;
851 vm_map_unlock(kernel_map);
852 src_vaddr = CAST_DOWN(vm_offset_t, kernel_mapping);
853 dst_vaddr = CAST_DOWN(vm_offset_t, kernel_mapping + PAGE_SIZE_64);
854 #endif /* __x86_64__ || __arm__ || __arm64__ */
855
856 /*
857 * Fill in the contents of the pages requested by VM.
858 */
859 upl_pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
860 pl_count = length / PAGE_SIZE;
861 for (cur_offset = 0;
862 retval == KERN_SUCCESS && cur_offset < length;
863 cur_offset += PAGE_SIZE) {
864 ppnum_t dst_pnum;
865 int num_subpg_signed, num_subpg_validated;
866 int num_subpg_tainted, num_subpg_nx;
867
868 if (!upl_page_present(upl_pl, (int)(cur_offset / PAGE_SIZE))) {
869 /* this page is not in the UPL: skip it */
870 continue;
871 }
872
873 /*
874 * Establish an explicit pmap mapping of the destination
875 * physical page.
876 * We can't do a regular VM mapping because the VM page
877 * is "busy".
878 */
879 dst_pnum = (ppnum_t)
880 upl_phys_page(upl_pl, (int)(cur_offset / PAGE_SIZE));
881 assert(dst_pnum != 0);
882 dst_vaddr = (vm_map_offset_t)
883 phystokv((pmap_paddr_t)dst_pnum << PAGE_SHIFT);
884
885 /* retrieve appropriate data for each 4K-page in this page */
886 if (PAGE_SHIFT == FOURK_PAGE_SHIFT &&
887 page_shift_user32 == SIXTEENK_PAGE_SHIFT) {
888 /*
889 * Find the slot for the requested 4KB page in
890 * the 16K page...
891 */
892 assert(PAGE_SHIFT == FOURK_PAGE_SHIFT);
893 assert(page_shift_user32 == SIXTEENK_PAGE_SHIFT);
894 sub_page_idx = ((offset & SIXTEENK_PAGE_MASK) /
895 PAGE_SIZE);
896 /*
897 * ... and provide only that one 4KB page.
898 */
899 sub_page_cnt = 1;
900 } else {
901 /*
902 * Iterate over all slots, i.e. retrieve all four 4KB
903 * pages in the requested 16KB page.
904 */
905 assert(PAGE_SHIFT == SIXTEENK_PAGE_SHIFT);
906 sub_page_idx = 0;
907 sub_page_cnt = FOURK_PAGER_SLOTS;
908 }
909
910 num_subpg_signed = 0;
911 num_subpg_validated = 0;
912 num_subpg_tainted = 0;
913 num_subpg_nx = 0;
914
915 /* retrieve appropriate data for each 4K-page in this page */
916 for (sub_page = sub_page_idx;
917 sub_page < sub_page_idx + sub_page_cnt;
918 sub_page++) {
919 vm_object_t src_object;
920 memory_object_offset_t src_offset;
921 vm_offset_t offset_in_src_page;
922 kern_return_t error_code;
923 vm_object_t src_page_object;
924 vm_page_t src_page;
925 vm_page_t top_page;
926 vm_prot_t prot;
927 int interruptible;
928 struct vm_object_fault_info fault_info;
929 boolean_t subpg_validated;
930 unsigned subpg_tainted;
931
932
933 if (offset < SIXTEENK_PAGE_SIZE) {
934 /*
935 * The 1st 16K-page can cover multiple
936 * sub-mappings, as described in the
937 * pager->slots[] array.
938 */
939 src_object =
940 pager->slots[sub_page].backing_object;
941 src_offset =
942 pager->slots[sub_page].backing_offset;
943 } else {
944 fourk_pager_backing_t slot;
945
946 /*
947 * Beyond the 1st 16K-page in the pager is
948 * an extension of the last "sub page" in
949 * the pager->slots[] array.
950 */
951 slot = &pager->slots[FOURK_PAGER_SLOTS - 1];
952 src_object = slot->backing_object;
953 src_offset = slot->backing_offset;
954 src_offset += FOURK_PAGE_SIZE;
955 src_offset +=
956 (vm_map_trunc_page(offset,
957 SIXTEENK_PAGE_MASK)
958 - SIXTEENK_PAGE_SIZE);
959 src_offset += sub_page * FOURK_PAGE_SIZE;
960 }
961 offset_in_src_page = src_offset & PAGE_MASK_64;
962 src_offset = vm_object_trunc_page(src_offset);
963
964 if (src_object == VM_OBJECT_NULL ||
965 src_object == (vm_object_t) -1) {
966 /* zero-fill */
967 bzero((char *)(dst_vaddr +
968 ((sub_page - sub_page_idx)
969 * FOURK_PAGE_SIZE)),
970 FOURK_PAGE_SIZE);
971 if (fourk_pager_data_request_debug) {
972 printf("fourk_pager_data_request"
973 "(%p,0x%llx+0x%lx+0x%04x): "
974 "ZERO\n",
975 pager,
976 offset,
977 cur_offset,
978 ((sub_page - sub_page_idx)
979 * FOURK_PAGE_SIZE));
980 }
981 continue;
982 }
983
984 /* fault in the source page from src_object */
985 retry_src_fault:
986 src_page = VM_PAGE_NULL;
987 top_page = VM_PAGE_NULL;
988 fault_info = *((struct vm_object_fault_info *)
989 (uintptr_t)mo_fault_info);
990 fault_info.stealth = TRUE;
991 fault_info.io_sync = FALSE;
992 fault_info.mark_zf_absent = FALSE;
993 fault_info.batch_pmap_op = FALSE;
994 interruptible = fault_info.interruptible;
995 prot = VM_PROT_READ;
996 error_code = 0;
997
998 vm_object_lock(src_object);
999 vm_object_paging_begin(src_object);
1000 kr = vm_fault_page(src_object,
1001 src_offset,
1002 VM_PROT_READ,
1003 FALSE,
1004 FALSE, /* src_page not looked up */
1005 &prot,
1006 &src_page,
1007 &top_page,
1008 NULL,
1009 &error_code,
1010 FALSE,
1011 FALSE,
1012 &fault_info);
1013 switch (kr) {
1014 case VM_FAULT_SUCCESS:
1015 break;
1016 case VM_FAULT_RETRY:
1017 goto retry_src_fault;
1018 case VM_FAULT_MEMORY_SHORTAGE:
1019 if (vm_page_wait(interruptible)) {
1020 goto retry_src_fault;
1021 }
1022 OS_FALLTHROUGH;
1023 case VM_FAULT_INTERRUPTED:
1024 retval = MACH_SEND_INTERRUPTED;
1025 goto src_fault_done;
1026 case VM_FAULT_SUCCESS_NO_VM_PAGE:
1027 /* success but no VM page: fail */
1028 vm_object_paging_end(src_object);
1029 vm_object_unlock(src_object);
1030 OS_FALLTHROUGH;
1031 case VM_FAULT_MEMORY_ERROR:
1032 /* the page is not there! */
1033 if (error_code) {
1034 retval = error_code;
1035 } else {
1036 retval = KERN_MEMORY_ERROR;
1037 }
1038 goto src_fault_done;
1039 default:
1040 panic("fourk_pager_data_request: "
1041 "vm_fault_page() unexpected error 0x%x\n",
1042 kr);
1043 }
1044 assert(src_page != VM_PAGE_NULL);
1045 assert(src_page->vmp_busy);
1046
1047 src_page_object = VM_PAGE_OBJECT(src_page);
1048
1049 if ((!VM_PAGE_PAGEABLE(src_page)) &&
1050 !VM_PAGE_WIRED(src_page)) {
1051 vm_page_lockspin_queues();
1052 if ((!VM_PAGE_PAGEABLE(src_page)) &&
1053 !VM_PAGE_WIRED(src_page)) {
1054 vm_page_deactivate(src_page);
1055 }
1056 vm_page_unlock_queues();
1057 }
1058
1059 src_vaddr = (vm_map_offset_t)
1060 phystokv((pmap_paddr_t)VM_PAGE_GET_PHYS_PAGE(src_page)
1061 << PAGE_SHIFT);
1062
1063 /*
1064 * Validate the 4K page we want from
1065 * this source page...
1066 */
1067 subpg_validated = FALSE;
1068 subpg_tainted = 0;
1069 if (src_page_object->code_signed) {
1070 vm_page_validate_cs_mapped_chunk(
1071 src_page,
1072 (const void *) src_vaddr,
1073 offset_in_src_page,
1074 FOURK_PAGE_SIZE,
1075 &subpg_validated,
1076 &subpg_tainted);
1077 num_subpg_signed++;
1078 if (subpg_validated) {
1079 num_subpg_validated++;
1080 }
1081 if (subpg_tainted & CS_VALIDATE_TAINTED) {
1082 num_subpg_tainted++;
1083 }
1084 if (subpg_tainted & CS_VALIDATE_NX) {
1085 /* subpg should not be executable */
1086 if (sub_page_cnt > 1) {
1087 /*
1088 * The destination page has
1089 * more than 1 subpage and its
1090 * other subpages might need
1091 * EXEC, so we do not propagate
1092 * CS_VALIDATE_NX to the
1093 * destination page...
1094 */
1095 } else {
1096 num_subpg_nx++;
1097 }
1098 }
1099 }
1100
1101 /*
1102 * Copy the relevant portion of the source page
1103 * into the appropriate part of the destination page.
1104 */
1105 bcopy((const char *)(src_vaddr + offset_in_src_page),
1106 (char *)(dst_vaddr +
1107 ((sub_page - sub_page_idx) *
1108 FOURK_PAGE_SIZE)),
1109 FOURK_PAGE_SIZE);
1110 if (fourk_pager_data_request_debug) {
1111 printf("fourk_data_request"
1112 "(%p,0x%llx+0x%lx+0x%04x): "
1113 "backed by [%p:0x%llx]: "
1114 "[0x%016llx 0x%016llx] "
1115 "code_signed=%d "
1116 "cs_valid=%d cs_tainted=%d cs_nx=%d\n",
1117 pager,
1118 offset, cur_offset,
1119 (sub_page - sub_page_idx) * FOURK_PAGE_SIZE,
1120 src_page_object,
1121 src_page->vmp_offset + offset_in_src_page,
1122 *(uint64_t *)(dst_vaddr +
1123 ((sub_page - sub_page_idx) *
1124 FOURK_PAGE_SIZE)),
1125 *(uint64_t *)(dst_vaddr +
1126 ((sub_page - sub_page_idx) *
1127 FOURK_PAGE_SIZE) +
1128 8),
1129 src_page_object->code_signed,
1130 subpg_validated,
1131 !!(subpg_tainted & CS_VALIDATE_TAINTED),
1132 !!(subpg_tainted & CS_VALIDATE_NX));
1133 }
1134
1135 #if __x86_64__ || __arm__ || __arm64__
1136 /* we used the 1-to-1 mapping of physical memory */
1137 src_vaddr = 0;
1138 #else /* __x86_64__ || __arm__ || __arm64__ */
1139 /*
1140 * Remove the pmap mapping of the source page
1141 * in the kernel.
1142 */
1143 pmap_remove(kernel_pmap,
1144 (addr64_t) src_vaddr,
1145 (addr64_t) src_vaddr + PAGE_SIZE_64);
1146 #endif /* __x86_64__ || __arm__ || __arm64__ */
1147
1148 src_fault_done:
1149 /*
1150 * Cleanup the result of vm_fault_page().
1151 */
1152 if (src_page) {
1153 assert(VM_PAGE_OBJECT(src_page) == src_page_object);
1154
1155 PAGE_WAKEUP_DONE(src_page);
1156 src_page = VM_PAGE_NULL;
1157 vm_object_paging_end(src_page_object);
1158 vm_object_unlock(src_page_object);
1159 if (top_page) {
1160 vm_object_t top_object;
1161
1162 top_object = VM_PAGE_OBJECT(top_page);
1163 vm_object_lock(top_object);
1164 VM_PAGE_FREE(top_page);
1165 top_page = VM_PAGE_NULL;
1166 vm_object_paging_end(top_object);
1167 vm_object_unlock(top_object);
1168 }
1169 }
1170 }
1171 if (num_subpg_signed > 0) {
1172 /* some code-signing involved with this 16K page */
1173 if (num_subpg_tainted > 0) {
1174 /* a tainted subpage taints entire 16K page */
1175 UPL_SET_CS_TAINTED(upl_pl,
1176 cur_offset / PAGE_SIZE,
1177 VMP_CS_ALL_TRUE);
1178 /* also mark as "validated" for consisteny */
1179 UPL_SET_CS_VALIDATED(upl_pl,
1180 cur_offset / PAGE_SIZE,
1181 VMP_CS_ALL_TRUE);
1182 } else if (num_subpg_validated == num_subpg_signed) {
1183 /*
1184 * All the code-signed 4K subpages of this
1185 * 16K page are validated: our 16K page is
1186 * considered validated.
1187 */
1188 UPL_SET_CS_VALIDATED(upl_pl,
1189 cur_offset / PAGE_SIZE,
1190 VMP_CS_ALL_TRUE);
1191 }
1192 if (num_subpg_nx > 0) {
1193 UPL_SET_CS_NX(upl_pl,
1194 cur_offset / PAGE_SIZE,
1195 VMP_CS_ALL_TRUE);
1196 }
1197 }
1198 }
1199
1200 done:
1201 if (upl != NULL) {
1202 /* clean up the UPL */
1203
1204 /*
1205 * The pages are currently dirty because we've just been
1206 * writing on them, but as far as we're concerned, they're
1207 * clean since they contain their "original" contents as
1208 * provided by us, the pager.
1209 * Tell the UPL to mark them "clean".
1210 */
1211 upl_clear_dirty(upl, TRUE);
1212
1213 /* abort or commit the UPL */
1214 if (retval != KERN_SUCCESS) {
1215 upl_abort(upl, 0);
1216 if (retval == KERN_ABORTED) {
1217 wait_result_t wait_result;
1218
1219 /*
1220 * We aborted the fault and did not provide
1221 * any contents for the requested pages but
1222 * the pages themselves are not invalid, so
1223 * let's return success and let the caller
1224 * retry the fault, in case it might succeed
1225 * later (when the decryption code is up and
1226 * running in the kernel, for example).
1227 */
1228 retval = KERN_SUCCESS;
1229 /*
1230 * Wait a little bit first to avoid using
1231 * too much CPU time retrying and failing
1232 * the same fault over and over again.
1233 */
1234 wait_result = assert_wait_timeout(
1235 (event_t) fourk_pager_data_request,
1236 THREAD_UNINT,
1237 10000, /* 10ms */
1238 NSEC_PER_USEC);
1239 assert(wait_result == THREAD_WAITING);
1240 wait_result = thread_block(THREAD_CONTINUE_NULL);
1241 assert(wait_result == THREAD_TIMED_OUT);
1242 }
1243 } else {
1244 boolean_t empty;
1245 assertf(page_aligned(upl->u_offset) && page_aligned(upl->u_size),
1246 "upl %p offset 0x%llx size 0x%x",
1247 upl, upl->u_offset, upl->u_size);
1248 upl_commit_range(upl, 0, upl->u_size,
1249 UPL_COMMIT_CS_VALIDATED | UPL_COMMIT_WRITTEN_BY_KERNEL,
1250 upl_pl, pl_count, &empty);
1251 }
1252
1253 /* and deallocate the UPL */
1254 upl_deallocate(upl);
1255 upl = NULL;
1256 }
1257 if (kernel_mapping != 0) {
1258 /* clean up the mapping of the source and destination pages */
1259 kr = vm_map_remove(kernel_map,
1260 kernel_mapping,
1261 kernel_mapping + (2 * PAGE_SIZE_64),
1262 VM_MAP_REMOVE_NO_FLAGS);
1263 assert(kr == KERN_SUCCESS);
1264 kernel_mapping = 0;
1265 src_vaddr = 0;
1266 dst_vaddr = 0;
1267 }
1268
1269 return retval;
1270 }
1271
1272
1273
1274 kern_return_t
1275 fourk_pager_populate(
1276 memory_object_t mem_obj,
1277 boolean_t overwrite,
1278 int index,
1279 vm_object_t new_backing_object,
1280 vm_object_offset_t new_backing_offset,
1281 vm_object_t *old_backing_object,
1282 vm_object_offset_t *old_backing_offset)
1283 {
1284 fourk_pager_t pager;
1285
1286 pager = fourk_pager_lookup(mem_obj);
1287 if (pager == NULL) {
1288 return KERN_INVALID_ARGUMENT;
1289 }
1290
1291 assert(pager->ref_count > 0);
1292 assert(pager->fourk_pgr_hdr.mo_control != MEMORY_OBJECT_CONTROL_NULL);
1293
1294 if (index < 0 || index > FOURK_PAGER_SLOTS) {
1295 return KERN_INVALID_ARGUMENT;
1296 }
1297
1298 if (!overwrite &&
1299 (pager->slots[index].backing_object != (vm_object_t) -1 ||
1300 pager->slots[index].backing_offset != (vm_object_offset_t) -1)) {
1301 return KERN_INVALID_ADDRESS;
1302 }
1303
1304 *old_backing_object = pager->slots[index].backing_object;
1305 *old_backing_offset = pager->slots[index].backing_offset;
1306
1307 pager->slots[index].backing_object = new_backing_object;
1308 pager->slots[index].backing_offset = new_backing_offset;
1309
1310 return KERN_SUCCESS;
1311 }