1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#include <stdint.h>
61
62#include <debug.h>
63#include <mach_pagemap.h>
64#include <mach_cluster_stats.h>
65#include <mach_kdb.h>
66#include <advisory_pageout.h>
67
68#include <mach/mach_types.h>
69#include <mach/memory_object.h>
70#include <mach/memory_object_default.h>
71#include <mach/memory_object_control_server.h>
72#include <mach/mach_host_server.h>
73#include <mach/upl.h>
74#include <mach/vm_map.h>
75#include <mach/vm_param.h>
76#include <mach/vm_statistics.h>
77
78#include <kern/kern_types.h>
79#include <kern/counters.h>
80#include <kern/host_statistics.h>
81#include <kern/machine.h>
82#include <kern/misc_protos.h>
83#include <kern/thread.h>
84#include <kern/xpr.h>
85#include <kern/kalloc.h>
86
87#include <machine/vm_tuning.h>
88
89#include <vm/pmap.h>
90#include <vm/vm_fault.h>
91#include <vm/vm_map.h>
92#include <vm/vm_object.h>
93#include <vm/vm_page.h>
94#include <vm/vm_pageout.h>
95#include <vm/vm_protos.h>
96
97
98
99
100#ifdef __ppc__
101#include <ppc/mappings.h>
102#endif
103#include <../bsd/crypto/aes/aes.h>
104
105extern ipc_port_t memory_manager_default;
106
107
108#ifndef VM_PAGEOUT_BURST_ACTIVE_THROTTLE
109#define VM_PAGEOUT_BURST_ACTIVE_THROTTLE 10000
110#endif
111
112#ifndef VM_PAGEOUT_BURST_INACTIVE_THROTTLE
113#define VM_PAGEOUT_BURST_INACTIVE_THROTTLE 4096
114#endif
115
116#ifndef VM_PAGEOUT_DEADLOCK_RELIEF
117#define VM_PAGEOUT_DEADLOCK_RELIEF 100
118#endif
119
120#ifndef VM_PAGEOUT_INACTIVE_RELIEF
121#define VM_PAGEOUT_INACTIVE_RELIEF 50
122#endif
123
124#ifndef VM_PAGE_LAUNDRY_MAX
125#define VM_PAGE_LAUNDRY_MAX 16UL
126#endif
127
128#ifndef VM_PAGEOUT_BURST_WAIT
129#define VM_PAGEOUT_BURST_WAIT 30
130#endif
131
132#ifndef VM_PAGEOUT_EMPTY_WAIT
133#define VM_PAGEOUT_EMPTY_WAIT 200
134#endif
135
136#ifndef VM_PAGEOUT_DEADLOCK_WAIT
137#define VM_PAGEOUT_DEADLOCK_WAIT 300
138#endif
139
140#ifndef VM_PAGEOUT_IDLE_WAIT
141#define VM_PAGEOUT_IDLE_WAIT 10
142#endif
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157#ifndef VM_PAGE_INACTIVE_TARGET
158#define VM_PAGE_INACTIVE_TARGET(avail) ((avail) * 1 / 3)
159#endif
160
161
162
163
164
165
166#ifndef VM_PAGE_FREE_TARGET
167#define VM_PAGE_FREE_TARGET(free) (15 + (free) / 80)
168#endif
169
170
171
172
173
174
175#ifndef VM_PAGE_FREE_MIN
176#define VM_PAGE_FREE_MIN(free) (10 + (free) / 100)
177#endif
178
179
180
181
182
183
184
185
186
187#ifndef VM_PAGE_FREE_RESERVED
188#define VM_PAGE_FREE_RESERVED(n) \
189 ((6 * VM_PAGE_LAUNDRY_MAX) + (n))
190#endif
191
192
193
194
195
196
197struct vm_pageout_queue {
198 queue_head_t pgo_pending;
199 unsigned int pgo_laundry;
200 unsigned int pgo_maxlaundry;
201
202 unsigned int pgo_idle:1,
203 pgo_busy:1,
204 pgo_throttled:1,
205 :0;
206};
207
208#define VM_PAGE_Q_THROTTLED(q) \
209 ((q)->pgo_laundry >= (q)->pgo_maxlaundry)
210
211
212
213
214
215
216
217
218
219unsigned int vm_pageout_scan_event_counter = 0;
220
221
222
223
224
225static void vm_pageout_garbage_collect(int);
226static void vm_pageout_iothread_continue(struct vm_pageout_queue *);
227static void vm_pageout_iothread_external(void);
228static void vm_pageout_iothread_internal(void);
229static void vm_pageout_queue_steal(vm_page_t);
230
231extern void vm_pageout_continue(void);
232extern void vm_pageout_scan(void);
233
234unsigned int vm_pageout_reserved_internal = 0;
235unsigned int vm_pageout_reserved_really = 0;
236
237unsigned int vm_pageout_idle_wait = 0;
238unsigned int vm_pageout_empty_wait = 0;
239unsigned int vm_pageout_burst_wait = 0;
240unsigned int vm_pageout_deadlock_wait = 0;
241unsigned int vm_pageout_deadlock_relief = 0;
242unsigned int vm_pageout_inactive_relief = 0;
243unsigned int vm_pageout_burst_active_throttle = 0;
244unsigned int vm_pageout_burst_inactive_throttle = 0;
245
246
247
248
249
250unsigned int vm_accellerate_zf_pageout_trigger = 400;
251unsigned int vm_zf_iterator;
252unsigned int vm_zf_iterator_count = 40;
253unsigned int last_page_zf;
254unsigned int vm_zf_count = 0;
255
256
257
258
259
260
261
262unsigned int vm_pageout_active = 0;
263unsigned int vm_pageout_inactive = 0;
264unsigned int vm_pageout_inactive_throttled = 0;
265unsigned int vm_pageout_inactive_forced = 0;
266unsigned int vm_pageout_inactive_nolock = 0;
267unsigned int vm_pageout_inactive_avoid = 0;
268unsigned int vm_pageout_inactive_busy = 0;
269unsigned int vm_pageout_inactive_absent = 0;
270unsigned int vm_pageout_inactive_used = 0;
271unsigned int vm_pageout_inactive_clean = 0;
272unsigned int vm_pageout_inactive_dirty = 0;
273unsigned int vm_pageout_dirty_no_pager = 0;
274unsigned int vm_pageout_purged_objects = 0;
275unsigned int vm_stat_discard = 0;
276unsigned int vm_stat_discard_sent = 0;
277unsigned int vm_stat_discard_failure = 0;
278unsigned int vm_stat_discard_throttle = 0;
279
280unsigned int vm_pageout_scan_active_throttled = 0;
281unsigned int vm_pageout_scan_inactive_throttled = 0;
282unsigned int vm_pageout_scan_throttle = 0;
283unsigned int vm_pageout_scan_burst_throttle = 0;
284unsigned int vm_pageout_scan_empty_throttle = 0;
285unsigned int vm_pageout_scan_deadlock_detected = 0;
286unsigned int vm_pageout_scan_active_throttle_success = 0;
287unsigned int vm_pageout_scan_inactive_throttle_success = 0;
288
289
290
291unsigned int vm_backing_store_low = 0;
292
293unsigned int vm_pageout_out_of_line = 0;
294unsigned int vm_pageout_in_place = 0;
295
296
297
298
299
300unsigned long vm_page_decrypt_counter = 0;
301unsigned long vm_page_decrypt_for_upl_counter = 0;
302unsigned long vm_page_encrypt_counter = 0;
303unsigned long vm_page_encrypt_abort_counter = 0;
304unsigned long vm_page_encrypt_already_encrypted_counter = 0;
305boolean_t vm_pages_encrypted = FALSE;
306
307
308struct vm_pageout_queue vm_pageout_queue_internal;
309struct vm_pageout_queue vm_pageout_queue_external;
310
311
312
313
314
315
316
317
318
319void
320vm_backing_store_disable(
321 boolean_t disable)
322{
323 if(disable) {
324 vm_backing_store_low = 1;
325 } else {
326 if(vm_backing_store_low) {
327 vm_backing_store_low = 0;
328 thread_wakeup((event_t) &vm_backing_store_low);
329 }
330 }
331}
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346vm_object_t
347vm_pageout_object_allocate(
348 vm_page_t m,
349 vm_size_t size,
350 vm_object_offset_t offset)
351{
352 vm_object_t object = m->object;
353 vm_object_t new_object;
354
355 assert(object->pager_ready);
356
357 new_object = vm_object_allocate(size);
358
359 if (object->pager_trusted) {
360 assert (offset < object->size);
361
362 vm_object_lock(new_object);
363 new_object->pageout = TRUE;
364 new_object->shadow = object;
365 new_object->can_persist = FALSE;
366 new_object->copy_strategy = MEMORY_OBJECT_COPY_NONE;
367 new_object->shadow_offset = offset;
368 vm_object_unlock(new_object);
369
370
371
372
373
374 vm_object_lock(object);
375 vm_object_paging_begin(object);
376 vm_page_lock_queues();
377 vm_page_unlock_queues();
378 vm_object_unlock(object);
379
380 vm_pageout_in_place++;
381 } else
382 vm_pageout_out_of_line++;
383 return(new_object);
384}
385
386#if MACH_CLUSTER_STATS
387unsigned long vm_pageout_cluster_dirtied = 0;
388unsigned long vm_pageout_cluster_cleaned = 0;
389unsigned long vm_pageout_cluster_collisions = 0;
390unsigned long vm_pageout_cluster_clusters = 0;
391unsigned long vm_pageout_cluster_conversions = 0;
392unsigned long vm_pageout_target_collisions = 0;
393unsigned long vm_pageout_target_page_dirtied = 0;
394unsigned long vm_pageout_target_page_freed = 0;
395#define CLUSTER_STAT(clause) clause
396#else
397#define CLUSTER_STAT(clause)
398#endif
399
400
401
402
403
404
405
406
407
408
409
410void
411vm_pageout_object_terminate(
412 vm_object_t object)
413{
414 vm_object_t shadow_object;
415 boolean_t shadow_internal;
416
417
418
419
420
421
422
423 assert(object->pageout);
424 shadow_object = object->shadow;
425 vm_object_lock(shadow_object);
426 shadow_internal = shadow_object->internal;
427
428 while (!queue_empty(&object->memq)) {
429 vm_page_t p, m;
430 vm_object_offset_t offset;
431
432 p = (vm_page_t) queue_first(&object->memq);
433
434 assert(p->private);
435 assert(p->pageout);
436 p->pageout = FALSE;
437 assert(!p->cleaning);
438
439 offset = p->offset;
440 VM_PAGE_FREE(p);
441 p = VM_PAGE_NULL;
442
443 m = vm_page_lookup(shadow_object,
444 offset + object->shadow_offset);
445
446 if(m == VM_PAGE_NULL)
447 continue;
448 assert(m->cleaning);
449
450
451
452
453
454 m->dump_cleaning = FALSE;
455
456
457
458
459
460 vm_object_paging_end(shadow_object);
461 assert((m->dirty) || (m->precious) ||
462 (m->busy && m->cleaning));
463
464
465
466
467
468 vm_page_lock_queues();
469 if (m->laundry) {
470 vm_pageout_throttle_up(m);
471 }
472
473
474
475
476
477
478
479
480
481 if (m->pageout) {
482 assert(m->busy);
483 assert(m->wire_count == 1);
484 m->cleaning = FALSE;
485 m->pageout = FALSE;
486#if MACH_CLUSTER_STATS
487 if (m->wanted) vm_pageout_target_collisions++;
488#endif
489
490
491
492
493
494
495
496
497
498
499 if (pmap_disconnect(m->phys_page) & VM_MEM_MODIFIED)
500 m->dirty = TRUE;
501 else
502 m->dirty = FALSE;
503
504 if (m->dirty) {
505 CLUSTER_STAT(vm_pageout_target_page_dirtied++;)
506 vm_page_unwire(m);
507 VM_STAT(reactivations++);
508 PAGE_WAKEUP_DONE(m);
509 } else {
510 CLUSTER_STAT(vm_pageout_target_page_freed++;)
511 vm_page_free(m);
512 }
513 vm_page_unlock_queues();
514 continue;
515 }
516
517
518
519
520
521
522 if (!m->active && !m->inactive && !m->private) {
523 if (m->reference)
524 vm_page_activate(m);
525 else
526 vm_page_deactivate(m);
527 }
528 if((m->busy) && (m->cleaning)) {
529
530
531 m->busy = FALSE;
532
533
534
535
536
537
538
539
540 pmap_clear_modify(m->phys_page);
541 if(m->absent) {
542 m->absent = FALSE;
543 if(shadow_object->absent_count == 1)
544 vm_object_absent_release(shadow_object);
545 else
546 shadow_object->absent_count--;
547 }
548 m->overwriting = FALSE;
549 } else if (m->overwriting) {
550
551
552
553 assert(m->wire_count != 0);
554 vm_page_unwire(m);
555 m->overwriting = FALSE;
556 } else {
557
558
559
560
561
562
563
564
565
566#if MACH_CLUSTER_STATS
567 m->dirty = pmap_is_modified(m->phys_page);
568
569 if (m->dirty) vm_pageout_cluster_dirtied++;
570 else vm_pageout_cluster_cleaned++;
571 if (m->wanted) vm_pageout_cluster_collisions++;
572#else
573 m->dirty = 0;
574#endif
575 }
576 m->cleaning = FALSE;
577
578
579
580
581 PAGE_WAKEUP(m);
582 vm_page_unlock_queues();
583 }
584
585
586
587 vm_object_paging_end(shadow_object);
588 vm_object_unlock(shadow_object);
589
590 assert(object->ref_count == 0);
591 assert(object->paging_in_progress == 0);
592 assert(object->resident_page_count == 0);
593 return;
594}
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623vm_page_t
624vm_pageout_setup(
625 register vm_page_t m,
626 register vm_object_t new_object,
627 vm_object_offset_t new_offset)
628{
629 register vm_object_t old_object = m->object;
630 vm_object_offset_t paging_offset;
631 vm_object_offset_t offset;
632 register vm_page_t holding_page;
633 register vm_page_t new_m;
634 boolean_t need_to_wire = FALSE;
635
636
637 XPR(XPR_VM_PAGEOUT,
638 "vm_pageout_setup, obj 0x%X off 0x%X page 0x%X new obj 0x%X offset 0x%X\n",
639 (integer_t)m->object, (integer_t)m->offset,
640 (integer_t)m, (integer_t)new_object,
641 (integer_t)new_offset);
642 assert(m && m->busy && !m->absent && !m->fictitious && !m->error &&
643 !m->restart);
644
645 assert(m->dirty || m->precious);
646
647
648
649
650
651 VM_PAGE_GRAB_FICTITIOUS(holding_page);
652
653 vm_object_lock(old_object);
654
655 offset = m->offset;
656 paging_offset = offset + old_object->paging_offset;
657
658 if (old_object->pager_trusted) {
659
660
661
662
663
664 new_m = holding_page;
665 holding_page = VM_PAGE_NULL;
666
667
668
669
670 new_m->phys_page = m->phys_page;
671 new_m->fictitious = FALSE;
672 new_m->pageout = TRUE;
673
674
675
676
677
678
679
680 pmap_clear_modify(m->phys_page);
681 vm_page_lock_queues();
682 new_m->private = TRUE;
683 vm_page_wire(new_m);
684 m->cleaning = TRUE;
685 m->pageout = TRUE;
686
687 vm_page_wire(m);
688 assert(m->wire_count == 1);
689 vm_page_unlock_queues();
690
691 m->dirty = TRUE;
692 m->precious = FALSE;
693 m->page_lock = VM_PROT_NONE;
694 m->unusual = FALSE;
695 m->unlock_request = VM_PROT_NONE;
696 } else {
697
698
699
700
701
702 vm_page_lock_queues();
703 VM_PAGE_QUEUES_REMOVE(m);
704 vm_page_remove(m);
705
706 vm_page_insert(holding_page, old_object, offset);
707 vm_page_unlock_queues();
708
709 m->dirty = TRUE;
710 m->precious = FALSE;
711 new_m = m;
712 new_m->page_lock = VM_PROT_NONE;
713 new_m->unlock_request = VM_PROT_NONE;
714
715 if (old_object->internal)
716 need_to_wire = TRUE;
717 }
718
719
720
721#if MACH_PAGEMAP
722 vm_external_state_set(old_object->existence_map, offset);
723#endif
724
725 vm_object_unlock(old_object);
726
727 vm_object_lock(new_object);
728
729
730
731
732
733
734 vm_page_lock_queues();
735 vm_page_insert(new_m, new_object, new_offset);
736 if (need_to_wire)
737 vm_page_wire(new_m);
738 else
739 vm_page_activate(new_m);
740 PAGE_WAKEUP_DONE(new_m);
741 vm_page_unlock_queues();
742
743 vm_object_unlock(new_object);
744
745
746
747
748 return (holding_page);
749}
750
751
752
753
754
755
756
757
758
759
760
761
762void
763vm_pageclean_setup(
764 vm_page_t m,
765 vm_page_t new_m,
766 vm_object_t new_object,
767 vm_object_offset_t new_offset)
768{
769 vm_object_t old_object = m->object;
770 assert(!m->busy);
771 assert(!m->cleaning);
772
773 XPR(XPR_VM_PAGEOUT,
774 "vm_pageclean_setup, obj 0x%X off 0x%X page 0x%X new 0x%X new_off 0x%X\n",
775 (integer_t)old_object, m->offset, (integer_t)m,
776 (integer_t)new_m, new_offset);
777
778 pmap_clear_modify(m->phys_page);
779 vm_object_paging_begin(old_object);
780
781
782
783
784#if MACH_PAGEMAP
785 vm_external_state_set(old_object->existence_map, m->offset);
786#endif
787
788
789
790
791 m->cleaning = TRUE;
792 m->dirty = TRUE;
793 m->precious = FALSE;
794
795
796
797
798
799 assert(new_m->fictitious);
800 new_m->fictitious = FALSE;
801 new_m->private = TRUE;
802 new_m->pageout = TRUE;
803 new_m->phys_page = m->phys_page;
804 vm_page_wire(new_m);
805
806 vm_page_insert(new_m, new_object, new_offset);
807 assert(!new_m->wanted);
808 new_m->busy = FALSE;
809}
810
811void
812vm_pageclean_copy(
813 vm_page_t m,
814 vm_page_t new_m,
815 vm_object_t new_object,
816 vm_object_offset_t new_offset)
817{
818 XPR(XPR_VM_PAGEOUT,
819 "vm_pageclean_copy, page 0x%X new_m 0x%X new_obj 0x%X offset 0x%X\n",
820 m, new_m, new_object, new_offset, 0);
821
822 assert((!m->busy) && (!m->cleaning));
823
824 assert(!new_m->private && !new_m->fictitious);
825
826 pmap_clear_modify(m->phys_page);
827
828 m->busy = TRUE;
829 vm_object_paging_begin(m->object);
830 vm_page_unlock_queues();
831 vm_object_unlock(m->object);
832
833
834
835
836 vm_page_copy(m, new_m);
837
838
839
840
841
842 vm_object_lock(m->object);
843 m->dirty = FALSE;
844
845 vm_object_paging_end(m->object);
846
847 vm_page_lock_queues();
848 if (!m->active && !m->inactive)
849 vm_page_activate(m);
850 PAGE_WAKEUP_DONE(m);
851
852 vm_page_insert(new_m, new_object, new_offset);
853 vm_page_activate(new_m);
854 new_m->busy = FALSE;
855}
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876void
877vm_pageout_initialize_page(
878 vm_page_t m)
879{
880 vm_object_t object;
881 vm_object_offset_t paging_offset;
882 vm_page_t holding_page;
883
884
885 XPR(XPR_VM_PAGEOUT,
886 "vm_pageout_initialize_page, page 0x%X\n",
887 (integer_t)m, 0, 0, 0, 0);
888 assert(m->busy);
889
890
891
892
893 assert(!m->absent);
894 assert(!m->error);
895 assert(m->dirty);
896
897
898
899
900 object = m->object;
901 paging_offset = m->offset + object->paging_offset;
902 vm_object_paging_begin(object);
903 if (m->absent || m->error || m->restart ||
904 (!m->dirty && !m->precious)) {
905 VM_PAGE_FREE(m);
906 panic("reservation without pageout?");
907 vm_object_unlock(object);
908 return;
909 }
910
911
912 holding_page = NULL;
913 vm_page_lock_queues();
914 pmap_clear_modify(m->phys_page);
915 m->dirty = TRUE;
916 m->busy = TRUE;
917 m->list_req_pending = TRUE;
918 m->cleaning = TRUE;
919 m->pageout = TRUE;
920 vm_page_wire(m);
921 vm_page_unlock_queues();
922 vm_object_unlock(object);
923
924
925
926
927
928
929
930
931
932 memory_object_data_initialize(object->pager,
933 paging_offset,
934 PAGE_SIZE);
935
936 vm_object_lock(object);
937}
938
939#if MACH_CLUSTER_STATS
940#define MAXCLUSTERPAGES 16
941struct {
942 unsigned long pages_in_cluster;
943 unsigned long pages_at_higher_offsets;
944 unsigned long pages_at_lower_offsets;
945} cluster_stats[MAXCLUSTERPAGES];
946#endif
947
948boolean_t allow_clustered_pageouts = FALSE;
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965void
966vm_pageout_cluster(vm_page_t m)
967{
968 vm_object_t object = m->object;
969 struct vm_pageout_queue *q;
970
971
972 XPR(XPR_VM_PAGEOUT,
973 "vm_pageout_cluster, object 0x%X offset 0x%X page 0x%X\n",
974 (integer_t)object, m->offset, (integer_t)m, 0, 0);
975
976
977
978
979 assert(m->busy && (m->dirty || m->precious) && (m->wire_count == 0));
980 assert(!m->cleaning && !m->pageout && !m->inactive && !m->active);
981
982
983
984
985
986 vm_object_paging_begin(object);
987
988
989
990
991
992 vm_page_wire(m);
993 m->list_req_pending = TRUE;
994 m->cleaning = TRUE;
995 m->pageout = TRUE;
996 m->laundry = TRUE;
997
998 if (object->internal == TRUE)
999 q = &vm_pageout_queue_internal;
1000 else
1001 q = &vm_pageout_queue_external;
1002 q->pgo_laundry++;
1003
1004 m->pageout_queue = TRUE;
1005 queue_enter(&q->pgo_pending, m, vm_page_t, pageq);
1006
1007 if (q->pgo_idle == TRUE) {
1008 q->pgo_idle = FALSE;
1009 thread_wakeup((event_t) &q->pgo_pending);
1010 }
1011}
1012
1013
1014unsigned long vm_pageout_throttle_up_count = 0;
1015
1016
1017
1018
1019
1020
1021
1022void
1023vm_pageout_throttle_up(
1024 vm_page_t m)
1025{
1026 struct vm_pageout_queue *q;
1027
1028 vm_pageout_throttle_up_count++;
1029
1030 assert(m->laundry);
1031 assert(m->object != VM_OBJECT_NULL);
1032 assert(m->object != kernel_object);
1033
1034 if (m->object->internal == TRUE)
1035 q = &vm_pageout_queue_internal;
1036 else
1037 q = &vm_pageout_queue_external;
1038
1039 m->laundry = FALSE;
1040 q->pgo_laundry--;
1041
1042 if (q->pgo_throttled == TRUE) {
1043 q->pgo_throttled = FALSE;
1044 thread_wakeup((event_t) &q->pgo_laundry);
1045 }
1046}
1047
1048
1049
1050
1051
1052
1053
1054
1055#define DELAYED_UNLOCK_LIMIT (3 * MAX_UPL_TRANSFER)
1056
1057#define FCS_IDLE 0
1058#define FCS_DELAYED 1
1059#define FCS_DEADLOCK_DETECTED 2
1060
1061struct flow_control {
1062 int state;
1063 mach_timespec_t ts;
1064};
1065
1066extern kern_return_t sysclk_gettime(mach_timespec_t *);
1067
1068
1069void
1070vm_pageout_scan(void)
1071{
1072 unsigned int loop_count = 0;
1073 unsigned int inactive_burst_count = 0;
1074 unsigned int active_burst_count = 0;
1075 vm_page_t local_freeq = 0;
1076 int local_freed = 0;
1077 int delayed_unlock = 0;
1078 int need_internal_inactive = 0;
1079 int refmod_state = 0;
1080 int vm_pageout_deadlock_target = 0;
1081 struct vm_pageout_queue *iq;
1082 struct vm_pageout_queue *eq;
1083 struct flow_control flow_control;
1084 boolean_t active_throttled = FALSE;
1085 boolean_t inactive_throttled = FALSE;
1086 mach_timespec_t ts;
1087 unsigned int msecs = 0;
1088 vm_object_t object;
1089
1090
1091 flow_control.state = FCS_IDLE;
1092 iq = &vm_pageout_queue_internal;
1093 eq = &vm_pageout_queue_external;
1094
1095 XPR(XPR_VM_PAGEOUT, "vm_pageout_scan\n", 0, 0, 0, 0, 0);
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 vm_page_lock_queues();
1123 delayed_unlock = 1;
1124
1125
1126Restart:
1127
1128
1129
1130 vm_page_inactive_target = VM_PAGE_INACTIVE_TARGET(vm_page_active_count +
1131 vm_page_inactive_count);
1132 object = NULL;
1133
1134 for (;;) {
1135 vm_page_t m;
1136
1137 if (delayed_unlock == 0)
1138 vm_page_lock_queues();
1139
1140 active_burst_count = vm_page_active_count;
1141
1142 if (active_burst_count > vm_pageout_burst_active_throttle)
1143 active_burst_count = vm_pageout_burst_active_throttle;
1144
1145
1146
1147
1148 while ((need_internal_inactive ||
1149 vm_page_inactive_count < vm_page_inactive_target) &&
1150 !queue_empty(&vm_page_queue_active) &&
1151 ((active_burst_count--) > 0)) {
1152
1153 vm_pageout_active++;
1154
1155 m = (vm_page_t) queue_first(&vm_page_queue_active);
1156
1157 assert(m->active && !m->inactive);
1158 assert(!m->laundry);
1159 assert(m->object != kernel_object);
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171 if (m->object != object) {
1172 if (object != NULL) {
1173 vm_object_unlock(object);
1174 object = NULL;
1175 }
1176 if (!vm_object_lock_try(m->object)) {
1177
1178
1179
1180 queue_remove(&vm_page_queue_active, m,
1181 vm_page_t, pageq);
1182 queue_enter(&vm_page_queue_active, m,
1183 vm_page_t, pageq);
1184
1185 goto done_with_activepage;
1186 }
1187 object = m->object;
1188 }
1189
1190
1191
1192
1193
1194
1195 if (m->busy) {
1196 queue_remove(&vm_page_queue_active, m,
1197 vm_page_t, pageq);
1198 m->pageq.next = NULL;
1199 m->pageq.prev = NULL;
1200
1201 if (!m->fictitious)
1202 vm_page_active_count--;
1203 m->active = FALSE;
1204
1205 goto done_with_activepage;
1206 }
1207 if (need_internal_inactive) {
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217 active_throttled = FALSE;
1218
1219 if (object->internal) {
1220 if ((VM_PAGE_Q_THROTTLED(iq) || !IP_VALID(memory_manager_default)))
1221 active_throttled = TRUE;
1222 } else if (VM_PAGE_Q_THROTTLED(eq)) {
1223 active_throttled = TRUE;
1224 }
1225 if (active_throttled == TRUE) {
1226 if (!m->dirty) {
1227 refmod_state = pmap_get_refmod(m->phys_page);
1228
1229 if (refmod_state & VM_MEM_REFERENCED)
1230 m->reference = TRUE;
1231 if (refmod_state & VM_MEM_MODIFIED)
1232 m->dirty = TRUE;
1233 }
1234 if (m->dirty || m->precious) {
1235
1236
1237
1238
1239
1240
1241 queue_remove(&vm_page_queue_active, m,
1242 vm_page_t, pageq);
1243 queue_enter(&vm_page_queue_active, m,
1244 vm_page_t, pageq);
1245
1246 vm_pageout_scan_active_throttled++;
1247
1248 goto done_with_activepage;
1249 }
1250 }
1251 vm_pageout_scan_active_throttle_success++;
1252 need_internal_inactive--;
1253 }
1254
1255
1256
1257
1258
1259
1260
1261
1262 vm_page_deactivate(m);
1263done_with_activepage:
1264 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1265
1266 if (object != NULL) {
1267 vm_object_unlock(object);
1268 object = NULL;
1269 }
1270 if (local_freeq) {
1271 vm_page_free_list(local_freeq);
1272
1273 local_freeq = 0;
1274 local_freed = 0;
1275 }
1276 delayed_unlock = 0;
1277 vm_page_unlock_queues();
1278
1279 mutex_pause();
1280 vm_page_lock_queues();
1281
1282
1283
1284
1285
1286 continue;
1287 }
1288 }
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304 if (vm_page_free_count + local_freed >= vm_page_free_target) {
1305 if (object != NULL) {
1306 vm_object_unlock(object);
1307 object = NULL;
1308 }
1309 if (local_freeq) {
1310 vm_page_free_list(local_freeq);
1311
1312 local_freeq = 0;
1313 local_freed = 0;
1314 }
1315 mutex_lock(&vm_page_queue_free_lock);
1316
1317 if ((vm_page_free_count >= vm_page_free_target) &&
1318 (vm_page_free_wanted == 0)) {
1319
1320 vm_page_unlock_queues();
1321
1322 thread_wakeup((event_t) &vm_pageout_garbage_collect);
1323 return;
1324 }
1325 mutex_unlock(&vm_page_queue_free_lock);
1326 }
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336 if ((queue_empty(&vm_page_queue_inactive) && queue_empty(&vm_page_queue_zf))) {
1337 vm_pageout_scan_empty_throttle++;
1338 msecs = vm_pageout_empty_wait;
1339 goto vm_pageout_scan_delay;
1340
1341 } else if (inactive_burst_count >= vm_pageout_burst_inactive_throttle) {
1342 vm_pageout_scan_burst_throttle++;
1343 msecs = vm_pageout_burst_wait;
1344 goto vm_pageout_scan_delay;
1345
1346 } else if (VM_PAGE_Q_THROTTLED(iq)) {
1347
1348 switch (flow_control.state) {
1349
1350 case FCS_IDLE:
1351reset_deadlock_timer:
1352 ts.tv_sec = vm_pageout_deadlock_wait / 1000;
1353 ts.tv_nsec = (vm_pageout_deadlock_wait % 1000) * 1000 * NSEC_PER_USEC;
1354 sysclk_gettime(&flow_control.ts);
1355 ADD_MACH_TIMESPEC(&flow_control.ts, &ts);
1356
1357 flow_control.state = FCS_DELAYED;
1358 msecs = vm_pageout_deadlock_wait;
1359
1360 break;
1361
1362 case FCS_DELAYED:
1363 sysclk_gettime(&ts);
1364
1365 if (CMP_MACH_TIMESPEC(&ts, &flow_control.ts) >= 0) {
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382 vm_pageout_deadlock_target = vm_pageout_deadlock_relief + vm_page_free_wanted;
1383 vm_pageout_scan_deadlock_detected++;
1384 flow_control.state = FCS_DEADLOCK_DETECTED;
1385
1386 thread_wakeup((event_t) &vm_pageout_garbage_collect);
1387 goto consider_inactive;
1388 }
1389
1390
1391
1392
1393
1394
1395 msecs = vm_pageout_idle_wait;
1396 break;
1397
1398 case FCS_DEADLOCK_DETECTED:
1399 if (vm_pageout_deadlock_target)
1400 goto consider_inactive;
1401 goto reset_deadlock_timer;
1402
1403 }
1404 vm_pageout_scan_throttle++;
1405 iq->pgo_throttled = TRUE;
1406vm_pageout_scan_delay:
1407 if (object != NULL) {
1408 vm_object_unlock(object);
1409 object = NULL;
1410 }
1411 if (local_freeq) {
1412 vm_page_free_list(local_freeq);
1413
1414 local_freeq = 0;
1415 local_freed = 0;
1416 }
1417 assert_wait_timeout((event_t) &iq->pgo_laundry, THREAD_INTERRUPTIBLE, msecs, 1000*NSEC_PER_USEC);
1418
1419 counter(c_vm_pageout_scan_block++);
1420
1421 vm_page_unlock_queues();
1422
1423 thread_block(THREAD_CONTINUE_NULL);
1424
1425 vm_page_lock_queues();
1426 delayed_unlock = 1;
1427
1428 iq->pgo_throttled = FALSE;
1429
1430 if (loop_count >= vm_page_inactive_count) {
1431 if (VM_PAGE_Q_THROTTLED(eq) || VM_PAGE_Q_THROTTLED(iq)) {
1432
1433
1434
1435
1436
1437 need_internal_inactive = vm_pageout_inactive_relief;
1438 }
1439 loop_count = 0;
1440 }
1441 inactive_burst_count = 0;
1442
1443 goto Restart;
1444
1445 }
1446
1447
1448 flow_control.state = FCS_IDLE;
1449consider_inactive:
1450 loop_count++;
1451 inactive_burst_count++;
1452 vm_pageout_inactive++;
1453
1454 if (!queue_empty(&vm_page_queue_inactive)) {
1455 m = (vm_page_t) queue_first(&vm_page_queue_inactive);
1456
1457 if (m->clustered && (m->no_isync == TRUE)) {
1458 goto use_this_page;
1459 }
1460 }
1461 if (vm_zf_count < vm_accellerate_zf_pageout_trigger) {
1462 vm_zf_iterator = 0;
1463 } else {
1464 last_page_zf = 0;
1465 if((vm_zf_iterator+=1) >= vm_zf_iterator_count) {
1466 vm_zf_iterator = 0;
1467 }
1468 }
1469 if (queue_empty(&vm_page_queue_zf) ||
1470 (((last_page_zf) || (vm_zf_iterator == 0)) &&
1471 !queue_empty(&vm_page_queue_inactive))) {
1472 m = (vm_page_t) queue_first(&vm_page_queue_inactive);
1473 last_page_zf = 0;
1474 } else {
1475 m = (vm_page_t) queue_first(&vm_page_queue_zf);
1476 last_page_zf = 1;
1477 }
1478use_this_page:
1479 assert(!m->active && m->inactive);
1480 assert(!m->laundry);
1481 assert(m->object != kernel_object);
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493 if (m->object != object) {
1494 if (object != NULL) {
1495 vm_object_unlock(object);
1496 object = NULL;
1497 }
1498 if (!vm_object_lock_try(m->object)) {
1499
1500
1501
1502
1503 if (m->zero_fill) {
1504 queue_remove(&vm_page_queue_zf, m,
1505 vm_page_t, pageq);
1506 queue_enter(&vm_page_queue_zf, m,
1507 vm_page_t, pageq);
1508 } else {
1509 queue_remove(&vm_page_queue_inactive, m,
1510 vm_page_t, pageq);
1511 queue_enter(&vm_page_queue_inactive, m,
1512 vm_page_t, pageq);
1513 }
1514 vm_pageout_inactive_nolock++;
1515
1516
1517
1518
1519
1520 delayed_unlock = DELAYED_UNLOCK_LIMIT + 1;
1521
1522 goto done_with_inactivepage;
1523 }
1524 object = m->object;
1525 }
1526
1527
1528
1529
1530
1531
1532 if ((object->purgable == VM_OBJECT_PURGABLE_VOLATILE ||
1533 object->purgable == VM_OBJECT_PURGABLE_EMPTY) &&
1534 object->copy == VM_OBJECT_NULL) {
1535
1536 (void) vm_object_purge(object);
1537 vm_pageout_purged_objects++;
1538
1539
1540
1541
1542
1543 vm_object_unlock(object);
1544 object = NULL;
1545
1546 inactive_burst_count = 0;
1547
1548 goto done_with_inactivepage;
1549 }
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561 if (!object->pager_initialized && object->pager_created) {
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572 if (m->zero_fill) {
1573 queue_remove(&vm_page_queue_zf, m,
1574 vm_page_t, pageq);
1575 queue_enter(&vm_page_queue_zf, m,
1576 vm_page_t, pageq);
1577 last_page_zf = 1;
1578 vm_zf_iterator = vm_zf_iterator_count - 1;
1579 } else {
1580 queue_remove(&vm_page_queue_inactive, m,
1581 vm_page_t, pageq);
1582 queue_enter(&vm_page_queue_inactive, m,
1583 vm_page_t, pageq);
1584 last_page_zf = 0;
1585 vm_zf_iterator = 1;
1586 }
1587 vm_pageout_inactive_avoid++;
1588
1589 goto done_with_inactivepage;
1590 }
1591
1592
1593
1594 if (m->zero_fill) {
1595 queue_remove(&vm_page_queue_zf, m, vm_page_t, pageq);
1596 } else {
1597 queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
1598 }
1599 m->pageq.next = NULL;
1600 m->pageq.prev = NULL;
1601 m->inactive = FALSE;
1602 if (!m->fictitious)
1603 vm_page_inactive_count--;
1604
1605 if (m->busy || !object->alive) {
1606
1607
1608
1609
1610 vm_pageout_inactive_busy++;
1611
1612 goto done_with_inactivepage;
1613 }
1614
1615
1616
1617
1618
1619 if (m->absent || m->error) {
1620 vm_pageout_inactive_absent++;
1621reclaim_page:
1622 if (vm_pageout_deadlock_target) {
1623 vm_pageout_scan_inactive_throttle_success++;
1624 vm_pageout_deadlock_target--;
1625 }
1626 if (m->tabled)
1627 vm_page_remove(m);
1628 if (m->absent)
1629 vm_object_absent_release(object);
1630
1631 assert(m->pageq.next == NULL &&
1632 m->pageq.prev == NULL);
1633 m->pageq.next = (queue_entry_t)local_freeq;
1634 local_freeq = m;
1635 local_freed++;
1636
1637 inactive_burst_count = 0;
1638
1639 goto done_with_inactivepage;
1640 }
1641
1642 assert(!m->private);
1643 assert(!m->fictitious);
1644
1645
1646
1647
1648
1649
1650
1651
1652 if (m->cleaning) {
1653 m->busy = TRUE;
1654 m->pageout = TRUE;
1655 m->dump_cleaning = TRUE;
1656 vm_page_wire(m);
1657
1658 CLUSTER_STAT(vm_pageout_cluster_conversions++);
1659
1660 inactive_burst_count = 0;
1661
1662 goto done_with_inactivepage;
1663 }
1664
1665
1666
1667
1668
1669 if ( (!m->reference) ) {
1670 refmod_state = pmap_get_refmod(m->phys_page);
1671
1672 if (refmod_state & VM_MEM_REFERENCED)
1673 m->reference = TRUE;
1674 if (refmod_state & VM_MEM_MODIFIED)
1675 m->dirty = TRUE;
1676 }
1677 if (m->reference) {
1678was_referenced:
1679 vm_page_activate(m);
1680 VM_STAT(reactivations++);
1681
1682 vm_pageout_inactive_used++;
1683 last_page_zf = 0;
1684 inactive_burst_count = 0;
1685
1686 goto done_with_inactivepage;
1687 }
1688
1689 XPR(XPR_VM_PAGEOUT,
1690 "vm_pageout_scan, replace object 0x%X offset 0x%X page 0x%X\n",
1691 (integer_t)object, (integer_t)m->offset, (integer_t)m, 0,0);
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707 inactive_throttled = FALSE;
1708
1709 if (m->dirty || m->precious) {
1710 if (object->internal) {
1711 if ((VM_PAGE_Q_THROTTLED(iq) || !IP_VALID(memory_manager_default)))
1712 inactive_throttled = TRUE;
1713 } else if (VM_PAGE_Q_THROTTLED(eq)) {
1714 inactive_throttled = TRUE;
1715 }
1716 }
1717 if (inactive_throttled == TRUE) {
1718 if (m->zero_fill) {
1719 queue_enter(&vm_page_queue_zf, m,
1720 vm_page_t, pageq);
1721 } else {
1722 queue_enter(&vm_page_queue_inactive, m,
1723 vm_page_t, pageq);
1724 }
1725 if (!m->fictitious)
1726 vm_page_inactive_count++;
1727 m->inactive = TRUE;
1728
1729 vm_pageout_scan_inactive_throttled++;
1730
1731 goto done_with_inactivepage;
1732 }
1733
1734
1735
1736
1737
1738
1739
1740 m->busy = TRUE;
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761 if (m->no_isync == FALSE) {
1762 refmod_state = pmap_disconnect(m->phys_page);
1763
1764 if (refmod_state & VM_MEM_MODIFIED)
1765 m->dirty = TRUE;
1766 if (refmod_state & VM_MEM_REFERENCED) {
1767 m->reference = TRUE;
1768
1769 PAGE_WAKEUP_DONE(m);
1770 goto was_referenced;
1771 }
1772 }
1773
1774
1775
1776 if (!m->dirty && !m->precious) {
1777 vm_pageout_inactive_clean++;
1778 goto reclaim_page;
1779 }
1780 vm_pageout_cluster(m);
1781
1782 vm_pageout_inactive_dirty++;
1783
1784 inactive_burst_count = 0;
1785
1786done_with_inactivepage:
1787 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1788
1789 if (object != NULL) {
1790 vm_object_unlock(object);
1791 object = NULL;
1792 }
1793 if (local_freeq) {
1794 vm_page_free_list(local_freeq);
1795
1796 local_freeq = 0;
1797 local_freed = 0;
1798 }
1799 delayed_unlock = 0;
1800 vm_page_unlock_queues();
1801 mutex_pause();
1802 }
1803
1804
1805
1806 }
1807}
1808
1809
1810int vm_page_free_count_init;
1811
1812void
1813vm_page_free_reserve(
1814 int pages)
1815{
1816 int free_after_reserve;
1817
1818 vm_page_free_reserved += pages;
1819
1820 free_after_reserve = vm_page_free_count_init - vm_page_free_reserved;
1821
1822 vm_page_free_min = vm_page_free_reserved +
1823 VM_PAGE_FREE_MIN(free_after_reserve);
1824
1825 vm_page_free_target = vm_page_free_reserved +
1826 VM_PAGE_FREE_TARGET(free_after_reserve);
1827
1828 if (vm_page_free_target < vm_page_free_min + 5)
1829 vm_page_free_target = vm_page_free_min + 5;
1830}
1831
1832
1833
1834
1835
1836void
1837vm_pageout_continue(void)
1838{
1839 vm_pageout_scan_event_counter++;
1840 vm_pageout_scan();
1841
1842 assert(vm_page_free_wanted == 0);
1843 assert_wait((event_t) &vm_page_free_wanted, THREAD_UNINT);
1844 mutex_unlock(&vm_page_queue_free_lock);
1845
1846 counter(c_vm_pageout_block++);
1847 thread_block((thread_continue_t)vm_pageout_continue);
1848
1849}
1850
1851
1852
1853
1854
1855
1856static void
1857vm_pageout_queue_steal(vm_page_t m)
1858{
1859 struct vm_pageout_queue *q;
1860
1861 if (m->object->internal == TRUE)
1862 q = &vm_pageout_queue_internal;
1863 else
1864 q = &vm_pageout_queue_external;
1865
1866 m->laundry = FALSE;
1867 m->pageout_queue = FALSE;
1868 queue_remove(&q->pgo_pending, m, vm_page_t, pageq);
1869
1870 m->pageq.next = NULL;
1871 m->pageq.prev = NULL;
1872
1873 vm_object_paging_end(m->object);
1874
1875 q->pgo_laundry--;
1876}
1877
1878
1879#ifdef FAKE_DEADLOCK
1880
1881#define FAKE_COUNT 5000
1882
1883int internal_count = 0;
1884int fake_deadlock = 0;
1885
1886#endif
1887
1888static void
1889vm_pageout_iothread_continue(struct vm_pageout_queue *q)
1890{
1891 vm_page_t m = NULL;
1892 vm_object_t object;
1893 boolean_t need_wakeup;
1894
1895 vm_page_lock_queues();
1896
1897 while ( !queue_empty(&q->pgo_pending) ) {
1898
1899 q->pgo_busy = TRUE;
1900 queue_remove_first(&q->pgo_pending, m, vm_page_t, pageq);
1901 m->pageout_queue = FALSE;
1902 vm_page_unlock_queues();
1903
1904 m->pageq.next = NULL;
1905 m->pageq.prev = NULL;
1906#ifdef FAKE_DEADLOCK
1907 if (q == &vm_pageout_queue_internal) {
1908 vm_offset_t addr;
1909 int pg_count;
1910
1911 internal_count++;
1912
1913 if ((internal_count == FAKE_COUNT)) {
1914
1915 pg_count = vm_page_free_count + vm_page_free_reserved;
1916
1917 if (kmem_alloc(kernel_map, &addr, PAGE_SIZE * pg_count) == KERN_SUCCESS) {
1918 kmem_free(kernel_map, addr, PAGE_SIZE * pg_count);
1919 }
1920 internal_count = 0;
1921 fake_deadlock++;
1922 }
1923 }
1924#endif
1925 object = m->object;
1926
1927 if (!object->pager_initialized) {
1928 vm_object_lock(object);
1929
1930
1931
1932
1933
1934
1935 if (!object->pager_initialized)
1936 vm_object_collapse(object, (vm_object_offset_t)0);
1937 if (!object->pager_initialized)
1938 vm_object_pager_create(object);
1939 if (!object->pager_initialized) {
1940
1941
1942
1943
1944
1945
1946
1947 m->list_req_pending = FALSE;
1948 m->cleaning = FALSE;
1949 m->pageout = FALSE;
1950 vm_page_unwire(m);
1951
1952 vm_pageout_throttle_up(m);
1953
1954 vm_page_lock_queues();
1955 vm_pageout_dirty_no_pager++;
1956 vm_page_activate(m);
1957 vm_page_unlock_queues();
1958
1959
1960
1961
1962 PAGE_WAKEUP_DONE(m);
1963
1964 vm_object_paging_end(object);
1965 vm_object_unlock(object);
1966
1967 vm_page_lock_queues();
1968 continue;
1969 } else if (object->pager == MEMORY_OBJECT_NULL) {
1970
1971
1972
1973
1974
1975
1976
1977
1978 VM_PAGE_FREE(m);
1979
1980 vm_object_paging_end(object);
1981 vm_object_unlock(object);
1982
1983 vm_page_lock_queues();
1984 continue;
1985 }
1986 vm_object_unlock(object);
1987 }
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000 memory_object_data_return(object->pager,
2001 m->offset + object->paging_offset,
2002 PAGE_SIZE,
2003 NULL,
2004 NULL,
2005 FALSE,
2006 FALSE,
2007 0);
2008
2009 vm_object_lock(object);
2010 vm_object_paging_end(object);
2011 vm_object_unlock(object);
2012
2013 vm_page_lock_queues();
2014 }
2015 assert_wait((event_t) q, THREAD_UNINT);
2016
2017
2018 if (q->pgo_throttled == TRUE && !VM_PAGE_Q_THROTTLED(q)) {
2019 q->pgo_throttled = FALSE;
2020 need_wakeup = TRUE;
2021 } else
2022 need_wakeup = FALSE;
2023
2024 q->pgo_busy = FALSE;
2025 q->pgo_idle = TRUE;
2026 vm_page_unlock_queues();
2027
2028 if (need_wakeup == TRUE)
2029 thread_wakeup((event_t) &q->pgo_laundry);
2030
2031 thread_block_parameter((thread_continue_t)vm_pageout_iothread_continue, (void *) &q->pgo_pending);
2032
2033}
2034
2035
2036static void
2037vm_pageout_iothread_external(void)
2038{
2039
2040 vm_pageout_iothread_continue(&vm_pageout_queue_external);
2041
2042}
2043
2044
2045static void
2046vm_pageout_iothread_internal(void)
2047{
2048 thread_t self = current_thread();
2049
2050 self->options |= TH_OPT_VMPRIV;
2051
2052 vm_pageout_iothread_continue(&vm_pageout_queue_internal);
2053
2054}
2055
2056static void
2057vm_pageout_garbage_collect(int collect)
2058{
2059 if (collect) {
2060 stack_collect();
2061
2062
2063
2064
2065
2066 consider_machine_collect();
2067 consider_zone_gc();
2068
2069 consider_machine_adjust();
2070 }
2071
2072 assert_wait((event_t) &vm_pageout_garbage_collect, THREAD_UNINT);
2073
2074 thread_block_parameter((thread_continue_t) vm_pageout_garbage_collect, (void *)1);
2075
2076}
2077
2078
2079
2080void
2081vm_pageout(void)
2082{
2083 thread_t self = current_thread();
2084 thread_t thread;
2085 kern_return_t result;
2086 spl_t s;
2087
2088
2089
2090
2091 s = splsched();
2092 thread_lock(self);
2093 self->priority = BASEPRI_PREEMPT - 1;
2094 set_sched_pri(self, self->priority);
2095 thread_unlock(self);
2096 splx(s);
2097
2098
2099
2100
2101
2102 if (vm_pageout_idle_wait == 0)
2103 vm_pageout_idle_wait = VM_PAGEOUT_IDLE_WAIT;
2104
2105 if (vm_pageout_burst_wait == 0)
2106 vm_pageout_burst_wait = VM_PAGEOUT_BURST_WAIT;
2107
2108 if (vm_pageout_empty_wait == 0)
2109 vm_pageout_empty_wait = VM_PAGEOUT_EMPTY_WAIT;
2110
2111 if (vm_pageout_deadlock_wait == 0)
2112 vm_pageout_deadlock_wait = VM_PAGEOUT_DEADLOCK_WAIT;
2113
2114 if (vm_pageout_deadlock_relief == 0)
2115 vm_pageout_deadlock_relief = VM_PAGEOUT_DEADLOCK_RELIEF;
2116
2117 if (vm_pageout_inactive_relief == 0)
2118 vm_pageout_inactive_relief = VM_PAGEOUT_INACTIVE_RELIEF;
2119
2120 if (vm_pageout_burst_active_throttle == 0)
2121 vm_pageout_burst_active_throttle = VM_PAGEOUT_BURST_ACTIVE_THROTTLE;
2122
2123 if (vm_pageout_burst_inactive_throttle == 0)
2124 vm_pageout_burst_inactive_throttle = VM_PAGEOUT_BURST_INACTIVE_THROTTLE;
2125
2126
2127
2128
2129
2130 task_lock(kernel_task);
2131 kernel_task->priv_flags |= VM_BACKING_STORE_PRIV;
2132 task_unlock(kernel_task);
2133
2134 vm_page_free_count_init = vm_page_free_count;
2135 vm_zf_iterator = 0;
2136
2137
2138
2139
2140
2141
2142
2143 if (vm_page_free_reserved < VM_PAGE_FREE_RESERVED(processor_count)) {
2144 vm_page_free_reserve((VM_PAGE_FREE_RESERVED(processor_count)) - vm_page_free_reserved);
2145 } else
2146 vm_page_free_reserve(0);
2147
2148
2149 queue_init(&vm_pageout_queue_external.pgo_pending);
2150 vm_pageout_queue_external.pgo_maxlaundry = VM_PAGE_LAUNDRY_MAX;
2151 vm_pageout_queue_external.pgo_laundry = 0;
2152 vm_pageout_queue_external.pgo_idle = FALSE;
2153 vm_pageout_queue_external.pgo_busy = FALSE;
2154 vm_pageout_queue_external.pgo_throttled = FALSE;
2155
2156 queue_init(&vm_pageout_queue_internal.pgo_pending);
2157 vm_pageout_queue_internal.pgo_maxlaundry = VM_PAGE_LAUNDRY_MAX;
2158 vm_pageout_queue_internal.pgo_laundry = 0;
2159 vm_pageout_queue_internal.pgo_idle = FALSE;
2160 vm_pageout_queue_internal.pgo_busy = FALSE;
2161 vm_pageout_queue_internal.pgo_throttled = FALSE;
2162
2163
2164 result = kernel_thread_start_priority((thread_continue_t)vm_pageout_iothread_internal, NULL, BASEPRI_PREEMPT - 1, &thread);
2165 if (result != KERN_SUCCESS)
2166 panic("vm_pageout_iothread_internal: create failed");
2167
2168 thread_deallocate(thread);
2169
2170
2171 result = kernel_thread_start_priority((thread_continue_t)vm_pageout_iothread_external, NULL, BASEPRI_PREEMPT - 1, &thread);
2172 if (result != KERN_SUCCESS)
2173 panic("vm_pageout_iothread_external: create failed");
2174
2175 thread_deallocate(thread);
2176
2177
2178 result = kernel_thread_start_priority((thread_continue_t)vm_pageout_garbage_collect, NULL, BASEPRI_PREEMPT - 2, &thread);
2179 if (result != KERN_SUCCESS)
2180 panic("vm_pageout_garbage_collect: create failed");
2181
2182 thread_deallocate(thread);
2183
2184
2185 vm_pageout_continue();
2186
2187}
2188
2189
2190static upl_t
2191upl_create(
2192 int flags,
2193 upl_size_t size)
2194{
2195 upl_t upl;
2196 int page_field_size;
2197
2198 page_field_size = 0;
2199 if (flags & UPL_CREATE_LITE) {
2200 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
2201 page_field_size = (page_field_size + 3) & 0xFFFFFFFC;
2202 }
2203 if(flags & UPL_CREATE_INTERNAL) {
2204 upl = (upl_t)kalloc(sizeof(struct upl)
2205 + (sizeof(struct upl_page_info)*(size/PAGE_SIZE))
2206 + page_field_size);
2207 } else {
2208 upl = (upl_t)kalloc(sizeof(struct upl) + page_field_size);
2209 }
2210 upl->flags = 0;
2211 upl->src_object = NULL;
2212 upl->kaddr = (vm_offset_t)0;
2213 upl->size = 0;
2214 upl->map_object = NULL;
2215 upl->ref_count = 1;
2216 upl_lock_init(upl);
2217#ifdef UPL_DEBUG
2218 upl->ubc_alias1 = 0;
2219 upl->ubc_alias2 = 0;
2220#endif
2221 return(upl);
2222}
2223
2224static void
2225upl_destroy(
2226 upl_t upl)
2227{
2228 int page_field_size;
2229
2230#ifdef UPL_DEBUG
2231 {
2232 upl_t upl_ele;
2233 vm_object_t object;
2234 if (upl->map_object->pageout) {
2235 object = upl->map_object->shadow;
2236 } else {
2237 object = upl->map_object;
2238 }
2239 vm_object_lock(object);
2240 queue_iterate(&object->uplq, upl_ele, upl_t, uplq) {
2241 if(upl_ele == upl) {
2242 queue_remove(&object->uplq,
2243 upl_ele, upl_t, uplq);
2244 break;
2245 }
2246 }
2247 vm_object_unlock(object);
2248 }
2249#endif
2250
2251
2252 if(upl->map_object->pageout)
2253 vm_object_deallocate(upl->map_object);
2254
2255 page_field_size = 0;
2256 if (upl->flags & UPL_LITE) {
2257 page_field_size = ((upl->size/PAGE_SIZE) + 7) >> 3;
2258 page_field_size = (page_field_size + 3) & 0xFFFFFFFC;
2259 }
2260 if(upl->flags & UPL_INTERNAL) {
2261 kfree(upl,
2262 sizeof(struct upl) +
2263 (sizeof(struct upl_page_info) * (upl->size/PAGE_SIZE))
2264 + page_field_size);
2265 } else {
2266 kfree(upl, sizeof(struct upl) + page_field_size);
2267 }
2268}
2269
2270void uc_upl_dealloc(upl_t upl);
2271__private_extern__ void
2272uc_upl_dealloc(
2273 upl_t upl)
2274{
2275 upl->ref_count -= 1;
2276 if(upl->ref_count == 0) {
2277 upl_destroy(upl);
2278 }
2279}
2280
2281void
2282upl_deallocate(
2283 upl_t upl)
2284{
2285
2286 upl->ref_count -= 1;
2287 if(upl->ref_count == 0) {
2288 upl_destroy(upl);
2289 }
2290}
2291
2292
2293
2294
2295unsigned long upl_cow = 0;
2296unsigned long upl_cow_again = 0;
2297unsigned long upl_cow_contiguous = 0;
2298unsigned long upl_cow_pages = 0;
2299unsigned long upl_cow_again_pages = 0;
2300unsigned long upl_cow_contiguous_pages = 0;
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346__private_extern__ kern_return_t
2347vm_object_upl_request(
2348 vm_object_t object,
2349 vm_object_offset_t offset,
2350 upl_size_t size,
2351 upl_t *upl_ptr,
2352 upl_page_info_array_t user_page_list,
2353 unsigned int *page_list_count,
2354 int cntrl_flags)
2355{
2356 vm_page_t dst_page = VM_PAGE_NULL;
2357 vm_object_offset_t dst_offset = offset;
2358 upl_size_t xfer_size = size;
2359 boolean_t do_m_lock = FALSE;
2360 boolean_t dirty;
2361 boolean_t hw_dirty;
2362 upl_t upl = NULL;
2363 unsigned int entry;
2364#if MACH_CLUSTER_STATS
2365 boolean_t encountered_lrp = FALSE;
2366#endif
2367 vm_page_t alias_page = NULL;
2368 int page_ticket;
2369 int refmod_state;
2370 wpl_array_t lite_list = NULL;
2371 vm_object_t last_copy_object;
2372
2373
2374 if (cntrl_flags & ~UPL_VALID_FLAGS) {
2375
2376
2377
2378
2379 return KERN_INVALID_VALUE;
2380 }
2381
2382 page_ticket = (cntrl_flags & UPL_PAGE_TICKET_MASK)
2383 >> UPL_PAGE_TICKET_SHIFT;
2384
2385 if(((size/PAGE_SIZE) > MAX_UPL_TRANSFER) && !object->phys_contiguous) {
2386 size = MAX_UPL_TRANSFER * PAGE_SIZE;
2387 }
2388
2389 if(cntrl_flags & UPL_SET_INTERNAL)
2390 if(page_list_count != NULL)
2391 *page_list_count = MAX_UPL_TRANSFER;
2392
2393 if((!object->internal) && (object->paging_offset != 0))
2394 panic("vm_object_upl_request: vnode object with non-zero paging offset\n");
2395
2396 if((cntrl_flags & UPL_COPYOUT_FROM) && (upl_ptr == NULL)) {
2397 return KERN_SUCCESS;
2398 }
2399
2400 vm_object_lock(object);
2401 vm_object_paging_begin(object);
2402 vm_object_unlock(object);
2403
2404 if(upl_ptr) {
2405 if(cntrl_flags & UPL_SET_INTERNAL) {
2406 if(cntrl_flags & UPL_SET_LITE) {
2407 uintptr_t page_field_size;
2408 upl = upl_create(
2409 UPL_CREATE_INTERNAL | UPL_CREATE_LITE,
2410 size);
2411 user_page_list = (upl_page_info_t *)
2412 (((uintptr_t)upl) + sizeof(struct upl));
2413 lite_list = (wpl_array_t)
2414 (((uintptr_t)user_page_list) +
2415 ((size/PAGE_SIZE) *
2416 sizeof(upl_page_info_t)));
2417 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
2418 page_field_size =
2419 (page_field_size + 3) & 0xFFFFFFFC;
2420 bzero((char *)lite_list, page_field_size);
2421 upl->flags =
2422 UPL_LITE | UPL_INTERNAL;
2423 } else {
2424 upl = upl_create(UPL_CREATE_INTERNAL, size);
2425 user_page_list = (upl_page_info_t *)
2426 (((uintptr_t)upl) + sizeof(struct upl));
2427 upl->flags = UPL_INTERNAL;
2428 }
2429 } else {
2430 if(cntrl_flags & UPL_SET_LITE) {
2431 uintptr_t page_field_size;
2432 upl = upl_create(UPL_CREATE_LITE, size);
2433 lite_list = (wpl_array_t)
2434 (((uintptr_t)upl) + sizeof(struct upl));
2435 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
2436 page_field_size =
2437 (page_field_size + 3) & 0xFFFFFFFC;
2438 bzero((char *)lite_list, page_field_size);
2439 upl->flags = UPL_LITE;
2440 } else {
2441 upl = upl_create(UPL_CREATE_EXTERNAL, size);
2442 upl->flags = 0;
2443 }
2444 }
2445
2446 if (object->phys_contiguous) {
2447 if ((cntrl_flags & UPL_WILL_MODIFY) &&
2448 object->copy != VM_OBJECT_NULL) {
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477 vm_object_lock_request(object,
2478 offset,
2479 size,
2480 FALSE,
2481 MEMORY_OBJECT_COPY_SYNC,
2482 VM_PROT_NO_CHANGE);
2483 upl_cow_contiguous++;
2484 upl_cow_contiguous_pages += size >> PAGE_SHIFT;
2485 }
2486
2487 upl->map_object = object;
2488
2489
2490 upl->flags |= UPL_DEVICE_MEMORY;
2491
2492
2493
2494 upl->offset = offset + object->paging_offset;
2495 upl->size = size;
2496 *upl_ptr = upl;
2497 if(user_page_list) {
2498 user_page_list[0].phys_addr =
2499 (offset + object->shadow_offset)>>PAGE_SHIFT;
2500 user_page_list[0].device = TRUE;
2501 }
2502
2503 if(page_list_count != NULL) {
2504 if (upl->flags & UPL_INTERNAL) {
2505 *page_list_count = 0;
2506 } else {
2507 *page_list_count = 1;
2508 }
2509 }
2510
2511 return KERN_SUCCESS;
2512 }
2513
2514 if(user_page_list)
2515 user_page_list[0].device = FALSE;
2516
2517 if(cntrl_flags & UPL_SET_LITE) {
2518 upl->map_object = object;
2519 } else {
2520 upl->map_object = vm_object_allocate(size);
2521
2522
2523
2524
2525 upl->map_object->shadow = object;
2526 upl->map_object->pageout = TRUE;
2527 upl->map_object->can_persist = FALSE;
2528 upl->map_object->copy_strategy =
2529 MEMORY_OBJECT_COPY_NONE;
2530 upl->map_object->shadow_offset = offset;
2531 upl->map_object->wimg_bits = object->wimg_bits;
2532 }
2533
2534 }
2535 if (!(cntrl_flags & UPL_SET_LITE)) {
2536 VM_PAGE_GRAB_FICTITIOUS(alias_page);
2537 }
2538
2539
2540
2541
2542
2543
2544
2545
2546 if (cntrl_flags & UPL_ENCRYPT) {
2547 upl->flags |= UPL_ENCRYPTED;
2548 }
2549 if (cntrl_flags & UPL_FOR_PAGEOUT) {
2550 upl->flags |= UPL_PAGEOUT;
2551 }
2552 vm_object_lock(object);
2553
2554
2555 if(upl_ptr) {
2556 upl->size = size;
2557 upl->offset = offset + object->paging_offset;
2558 *upl_ptr = upl;
2559#ifdef UPL_DEBUG
2560 queue_enter(&object->uplq, upl, upl_t, uplq);
2561#endif
2562 }
2563
2564 if ((cntrl_flags & UPL_WILL_MODIFY) &&
2565 object->copy != VM_OBJECT_NULL) {
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575 vm_object_update(object,
2576 offset,
2577 size,
2578 NULL,
2579 NULL,
2580 FALSE,
2581 MEMORY_OBJECT_COPY_SYNC,
2582 VM_PROT_NO_CHANGE);
2583 upl_cow++;
2584 upl_cow_pages += size >> PAGE_SHIFT;
2585
2586 }
2587
2588 last_copy_object = object->copy;
2589
2590 entry = 0;
2591 if(cntrl_flags & UPL_COPYOUT_FROM) {
2592 upl->flags |= UPL_PAGE_SYNC_DONE;
2593
2594 while (xfer_size) {
2595 if((alias_page == NULL) &&
2596 !(cntrl_flags & UPL_SET_LITE)) {
2597 vm_object_unlock(object);
2598 VM_PAGE_GRAB_FICTITIOUS(alias_page);
2599 vm_object_lock(object);
2600 }
2601 if ( ((dst_page = vm_page_lookup(object, dst_offset)) == VM_PAGE_NULL) ||
2602 dst_page->fictitious ||
2603 dst_page->absent ||
2604 dst_page->error ||
2605 (dst_page->wire_count && !dst_page->pageout) ||
2606
2607 ((!dst_page->inactive) && (cntrl_flags & UPL_FOR_PAGEOUT) &&
2608 (dst_page->page_ticket != page_ticket) &&
2609 ((dst_page->page_ticket+1) != page_ticket)) ) {
2610
2611 if (user_page_list)
2612 user_page_list[entry].phys_addr = 0;
2613 } else {
2614
2615
2616
2617
2618
2619
2620
2621 refmod_state = pmap_get_refmod(dst_page->phys_page);
2622
2623 if (cntrl_flags & UPL_RET_ONLY_DIRTY) {
2624
2625
2626
2627
2628 if (dst_page->list_req_pending || !(cntrl_flags & UPL_FOR_PAGEOUT)) {
2629
2630
2631
2632
2633
2634
2635
2636 if (dst_page->dirty || dst_page->precious ||
2637 (refmod_state & VM_MEM_MODIFIED)) {
2638 goto check_busy;
2639 }
2640 }
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650 if ( !(refmod_state & VM_MEM_REFERENCED) &&
2651 ((refmod_state & VM_MEM_MODIFIED) ||
2652 dst_page->dirty || dst_page->precious) ) {
2653 goto check_busy;
2654 }
2655
2656
2657
2658
2659 if (user_page_list)
2660 user_page_list[entry].phys_addr = 0;
2661 entry++;
2662 dst_offset += PAGE_SIZE_64;
2663 xfer_size -= PAGE_SIZE;
2664 continue;
2665 }
2666check_busy:
2667 if(dst_page->busy &&
2668 (!(dst_page->list_req_pending &&
2669 dst_page->pageout))) {
2670 if(cntrl_flags & UPL_NOBLOCK) {
2671 if(user_page_list) {
2672 user_page_list[entry].phys_addr = 0;
2673 }
2674 entry++;
2675 dst_offset += PAGE_SIZE_64;
2676 xfer_size -= PAGE_SIZE;
2677 continue;
2678 }
2679
2680
2681
2682
2683 PAGE_SLEEP(object, dst_page, THREAD_UNINT);
2684 continue;
2685 }
2686
2687 if((dst_page->cleaning || dst_page->absent ||
2688 dst_page->wire_count != 0) &&
2689 !dst_page->list_req_pending) {
2690 if(user_page_list) {
2691 user_page_list[entry].phys_addr = 0;
2692 }
2693 entry++;
2694 dst_offset += PAGE_SIZE_64;
2695 xfer_size -= PAGE_SIZE;
2696 continue;
2697 }
2698
2699
2700
2701 vm_page_lock_queues();
2702
2703 if (dst_page->pageout_queue == TRUE)
2704
2705
2706
2707
2708
2709
2710
2711 vm_pageout_queue_steal(dst_page);
2712#if MACH_CLUSTER_STATS
2713
2714
2715
2716
2717 if(dst_page->list_req_pending)
2718 encountered_lrp = TRUE;
2719 if((dst_page->dirty ||
2720 (dst_page->object->internal &&
2721 dst_page->precious)) &&
2722 (dst_page->list_req_pending
2723 == FALSE)) {
2724 if(encountered_lrp) {
2725 CLUSTER_STAT
2726 (pages_at_higher_offsets++;)
2727 } else {
2728 CLUSTER_STAT
2729 (pages_at_lower_offsets++;)
2730 }
2731 }
2732#endif
2733
2734
2735
2736 dst_page->list_req_pending = FALSE;
2737 dst_page->busy = FALSE;
2738 dst_page->cleaning = FALSE;
2739
2740 hw_dirty = refmod_state & VM_MEM_MODIFIED;
2741 dirty = hw_dirty ? TRUE : dst_page->dirty;
2742
2743 if(cntrl_flags & UPL_SET_LITE) {
2744 int pg_num;
2745 pg_num = (dst_offset-offset)/PAGE_SIZE;
2746 lite_list[pg_num>>5] |=
2747 1 << (pg_num & 31);
2748 if (hw_dirty)
2749 pmap_clear_modify(dst_page->phys_page);
2750
2751
2752
2753
2754#if MACH_PAGEMAP
2755 vm_external_state_set(
2756 object->existence_map,
2757 dst_page->offset);
2758#endif
2759
2760
2761
2762
2763
2764 dst_page->cleaning = TRUE;
2765 dst_page->dirty = TRUE;
2766 dst_page->precious = FALSE;
2767 } else {
2768
2769
2770
2771
2772 vm_object_lock(upl->map_object);
2773 vm_pageclean_setup(dst_page,
2774 alias_page, upl->map_object,
2775 size - xfer_size);
2776 vm_object_unlock(upl->map_object);
2777
2778 alias_page->absent = FALSE;
2779 alias_page = NULL;
2780 }
2781
2782 if(!dirty) {
2783 dst_page->dirty = FALSE;
2784 dst_page->precious = TRUE;
2785 }
2786
2787 if(dst_page->pageout)
2788 dst_page->busy = TRUE;
2789
2790 if ( (cntrl_flags & UPL_ENCRYPT) ) {
2791
2792
2793
2794
2795
2796
2797
2798
2799 dst_page->busy = TRUE;
2800 }
2801 if ( !(cntrl_flags & UPL_CLEAN_IN_PLACE) ) {
2802
2803
2804
2805
2806 if ((!dst_page->pageout) &&
2807 (dst_page->wire_count == 0)) {
2808 dst_page->busy = TRUE;
2809 dst_page->pageout = TRUE;
2810 vm_page_wire(dst_page);
2811 }
2812 }
2813
2814 if(user_page_list) {
2815 user_page_list[entry].phys_addr
2816 = dst_page->phys_page;
2817 user_page_list[entry].dirty =
2818 dst_page->dirty;
2819 user_page_list[entry].pageout =
2820 dst_page->pageout;
2821 user_page_list[entry].absent =
2822 dst_page->absent;
2823 user_page_list[entry].precious =
2824 dst_page->precious;
2825 }
2826 vm_page_unlock_queues();
2827
2828
2829
2830
2831
2832
2833
2834
2835 if (! (cntrl_flags & UPL_ENCRYPT) &&
2836 dst_page->encrypted) {
2837 assert(dst_page->busy);
2838
2839 vm_page_decrypt(dst_page, 0);
2840 vm_page_decrypt_for_upl_counter++;
2841
2842
2843
2844
2845
2846
2847 continue;
2848 }
2849 }
2850 entry++;
2851 dst_offset += PAGE_SIZE_64;
2852 xfer_size -= PAGE_SIZE;
2853 }
2854 } else {
2855 while (xfer_size) {
2856 if((alias_page == NULL) &&
2857 !(cntrl_flags & UPL_SET_LITE)) {
2858 vm_object_unlock(object);
2859 VM_PAGE_GRAB_FICTITIOUS(alias_page);
2860 vm_object_lock(object);
2861 }
2862
2863 if ((cntrl_flags & UPL_WILL_MODIFY) &&
2864 object->copy != last_copy_object) {
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886 if (object->copy != VM_OBJECT_NULL) {
2887 vm_object_update(
2888 object,
2889 dst_offset,
2890 xfer_size,
2891 NULL,
2892 NULL,
2893 FALSE,
2894 MEMORY_OBJECT_COPY_SYNC,
2895 VM_PROT_NO_CHANGE);
2896 upl_cow_again++;
2897 upl_cow_again_pages +=
2898 xfer_size >> PAGE_SHIFT;
2899 }
2900
2901 last_copy_object = object->copy;
2902 }
2903
2904 dst_page = vm_page_lookup(object, dst_offset);
2905
2906 if(dst_page != VM_PAGE_NULL) {
2907 if((cntrl_flags & UPL_RET_ONLY_ABSENT) &&
2908 !((dst_page->list_req_pending)
2909 && (dst_page->absent))) {
2910
2911
2912
2913
2914 if(user_page_list) {
2915 user_page_list[entry].phys_addr = 0;
2916 }
2917 entry++;
2918 dst_offset += PAGE_SIZE_64;
2919 xfer_size -= PAGE_SIZE;
2920 continue;
2921 }
2922 if((dst_page->cleaning) &&
2923 !(dst_page->list_req_pending)) {
2924
2925
2926 PAGE_SLEEP(object,dst_page,THREAD_UNINT);
2927 continue;
2928 }
2929 if ((dst_page->fictitious &&
2930 dst_page->list_req_pending)) {
2931
2932 dst_page->list_req_pending = FALSE;
2933 dst_page->clustered = FALSE;
2934
2935 vm_page_lock_queues();
2936 vm_page_free(dst_page);
2937 vm_page_unlock_queues();
2938
2939 dst_page = NULL;
2940 } else if ((dst_page->absent &&
2941 dst_page->list_req_pending)) {
2942
2943 dst_page->list_req_pending = FALSE;
2944 dst_page->busy = FALSE;
2945 }
2946 }
2947 if(dst_page == VM_PAGE_NULL) {
2948 if(object->private) {
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958 if(user_page_list) {
2959 user_page_list[entry].phys_addr = 0;
2960 }
2961 entry++;
2962 dst_offset += PAGE_SIZE_64;
2963 xfer_size -= PAGE_SIZE;
2964 continue;
2965 }
2966
2967 dst_page = vm_page_alloc(object, dst_offset);
2968 if (dst_page == VM_PAGE_NULL) {
2969 vm_object_unlock(object);
2970 VM_PAGE_WAIT();
2971 vm_object_lock(object);
2972 continue;
2973 }
2974 dst_page->busy = FALSE;
2975#if 0
2976 if(cntrl_flags & UPL_NO_SYNC) {
2977 dst_page->page_lock = 0;
2978 dst_page->unlock_request = 0;
2979 }
2980#endif
2981 if(cntrl_flags & UPL_RET_ONLY_ABSENT) {
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991 dst_page->clustered = TRUE;
2992 }
2993 dst_page->absent = TRUE;
2994 object->absent_count++;
2995 }
2996#if 1
2997 if(cntrl_flags & UPL_NO_SYNC) {
2998 dst_page->page_lock = 0;
2999 dst_page->unlock_request = 0;
3000 }
3001#endif
3002
3003
3004
3005
3006 if (cntrl_flags & UPL_ENCRYPT) {
3007
3008
3009
3010
3011 dst_page->encrypted = TRUE;
3012 } else {
3013
3014
3015
3016
3017 dst_page->encrypted = FALSE;
3018 }
3019
3020 dst_page->overwriting = TRUE;
3021 if(dst_page->fictitious) {
3022 panic("need corner case for fictitious page");
3023 }
3024 if(dst_page->page_lock) {
3025 do_m_lock = TRUE;
3026 }
3027 if(upl_ptr) {
3028
3029
3030
3031
3032 if(dst_page->busy) {
3033
3034
3035 PAGE_SLEEP(object, dst_page, THREAD_UNINT);
3036 continue;
3037 }
3038 vm_page_lock_queues();
3039
3040 if( !(cntrl_flags & UPL_FILE_IO))
3041 hw_dirty = pmap_disconnect(dst_page->phys_page) & VM_MEM_MODIFIED;
3042 else
3043 hw_dirty = pmap_get_refmod(dst_page->phys_page) & VM_MEM_MODIFIED;
3044 dirty = hw_dirty ? TRUE : dst_page->dirty;
3045
3046 if(cntrl_flags & UPL_SET_LITE) {
3047 int pg_num;
3048 pg_num = (dst_offset-offset)/PAGE_SIZE;
3049 lite_list[pg_num>>5] |=
3050 1 << (pg_num & 31);
3051 if (hw_dirty)
3052 pmap_clear_modify(dst_page->phys_page);
3053
3054
3055
3056
3057#if MACH_PAGEMAP
3058 vm_external_state_set(
3059 object->existence_map,
3060 dst_page->offset);
3061#endif
3062
3063
3064
3065
3066
3067 dst_page->cleaning = TRUE;
3068 dst_page->dirty = TRUE;
3069 dst_page->precious = FALSE;
3070 } else {
3071
3072
3073
3074 vm_object_lock(upl->map_object);
3075 vm_pageclean_setup(dst_page,
3076 alias_page, upl->map_object,
3077 size - xfer_size);
3078 vm_object_unlock(upl->map_object);
3079
3080 alias_page->absent = FALSE;
3081 alias_page = NULL;
3082 }
3083
3084 if(cntrl_flags & UPL_CLEAN_IN_PLACE) {
3085
3086
3087
3088
3089
3090
3091
3092 upl->flags |= UPL_CLEAR_DIRTY;
3093 }
3094
3095 if(!dirty) {
3096 dst_page->dirty = FALSE;
3097 dst_page->precious = TRUE;
3098 }
3099
3100 if (dst_page->wire_count == 0) {
3101
3102
3103 dst_page->busy = TRUE;
3104 } else {
3105 vm_page_wire(dst_page);
3106 }
3107 if(cntrl_flags & UPL_RET_ONLY_ABSENT) {
3108
3109
3110
3111
3112
3113
3114
3115
3116 dst_page->reference = FALSE;
3117 } else {
3118
3119
3120
3121 dst_page->reference = TRUE;
3122 }
3123 dst_page->precious =
3124 (cntrl_flags & UPL_PRECIOUS)
3125 ? TRUE : FALSE;
3126 if(user_page_list) {
3127 user_page_list[entry].phys_addr
3128 = dst_page->phys_page;
3129 user_page_list[entry].dirty =
3130 dst_page->dirty;
3131 user_page_list[entry].pageout =
3132 dst_page->pageout;
3133 user_page_list[entry].absent =
3134 dst_page->absent;
3135 user_page_list[entry].precious =
3136 dst_page->precious;
3137 }
3138 vm_page_unlock_queues();
3139 }
3140 entry++;
3141 dst_offset += PAGE_SIZE_64;
3142 xfer_size -= PAGE_SIZE;
3143 }
3144 }
3145
3146 if (upl->flags & UPL_INTERNAL) {
3147 if(page_list_count != NULL)
3148 *page_list_count = 0;
3149 } else if (*page_list_count > entry) {
3150 if(page_list_count != NULL)
3151 *page_list_count = entry;
3152 }
3153
3154 if(alias_page != NULL) {
3155 vm_page_lock_queues();
3156 vm_page_free(alias_page);
3157 vm_page_unlock_queues();
3158 }
3159
3160 if(do_m_lock) {
3161 vm_prot_t access_required;
3162
3163
3164
3165
3166
3167 access_required = (cntrl_flags & UPL_COPYOUT_FROM)
3168 ? VM_PROT_READ : VM_PROT_WRITE;
3169 while (TRUE) {
3170 kern_return_t rc;
3171
3172 if(!object->pager_ready) {
3173 wait_result_t wait_result;
3174
3175 wait_result = vm_object_sleep(object,
3176 VM_OBJECT_EVENT_PAGER_READY,
3177 THREAD_UNINT);
3178 if (wait_result != THREAD_AWAKENED) {
3179 vm_object_unlock(object);
3180 return KERN_FAILURE;
3181 }
3182 continue;
3183 }
3184
3185 vm_object_unlock(object);
3186 rc = memory_object_data_unlock(
3187 object->pager,
3188 dst_offset + object->paging_offset,
3189 size,
3190 access_required);
3191 if (rc != KERN_SUCCESS && rc != MACH_SEND_INTERRUPTED)
3192 return KERN_FAILURE;
3193 vm_object_lock(object);
3194
3195 if (rc == KERN_SUCCESS)
3196 break;
3197 }
3198
3199
3200
3201 if(dst_page != VM_PAGE_NULL &&
3202 (access_required & dst_page->page_lock) != access_required) {
3203 PAGE_ASSERT_WAIT(dst_page, THREAD_UNINT);
3204 vm_object_unlock(object);
3205 thread_block(THREAD_CONTINUE_NULL);
3206 return KERN_SUCCESS;
3207 }
3208 }
3209
3210 vm_object_unlock(object);
3211 return KERN_SUCCESS;
3212}
3213
3214
3215kern_return_t
3216vm_fault_list_request(
3217 memory_object_control_t control,
3218 vm_object_offset_t offset,
3219 upl_size_t size,
3220 upl_t *upl_ptr,
3221 upl_page_info_t **user_page_list_ptr,
3222 int page_list_count,
3223 int cntrl_flags);
3224kern_return_t
3225vm_fault_list_request(
3226 memory_object_control_t control,
3227 vm_object_offset_t offset,
3228 upl_size_t size,
3229 upl_t *upl_ptr,
3230 upl_page_info_t **user_page_list_ptr,
3231 int page_list_count,
3232 int cntrl_flags)
3233{
3234 int local_list_count;
3235 upl_page_info_t *user_page_list;
3236 kern_return_t kr;
3237
3238 if (user_page_list_ptr != NULL) {
3239 local_list_count = page_list_count;
3240 user_page_list = *user_page_list_ptr;
3241 } else {
3242 local_list_count = 0;
3243 user_page_list = NULL;
3244 }
3245 kr = memory_object_upl_request(control,
3246 offset,
3247 size,
3248 upl_ptr,
3249 user_page_list,
3250 &local_list_count,
3251 cntrl_flags);
3252
3253 if(kr != KERN_SUCCESS)
3254 return kr;
3255
3256 if ((user_page_list_ptr != NULL) && (cntrl_flags & UPL_INTERNAL)) {
3257 *user_page_list_ptr = UPL_GET_INTERNAL_PAGE_LIST(*upl_ptr);
3258 }
3259
3260 return KERN_SUCCESS;
3261}
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276__private_extern__ kern_return_t
3277vm_object_super_upl_request(
3278 vm_object_t object,
3279 vm_object_offset_t offset,
3280 upl_size_t size,
3281 upl_size_t super_cluster,
3282 upl_t *upl,
3283 upl_page_info_t *user_page_list,
3284 unsigned int *page_list_count,
3285 int cntrl_flags)
3286{
3287 vm_page_t target_page;
3288 int ticket;
3289
3290
3291 if(object->paging_offset > offset)
3292 return KERN_FAILURE;
3293
3294 assert(object->paging_in_progress);
3295 offset = offset - object->paging_offset;
3296
3297 if(cntrl_flags & UPL_FOR_PAGEOUT) {
3298
3299 vm_object_lock(object);
3300
3301 if((target_page = vm_page_lookup(object, offset))
3302 != VM_PAGE_NULL) {
3303 ticket = target_page->page_ticket;
3304 cntrl_flags = cntrl_flags & ~(int)UPL_PAGE_TICKET_MASK;
3305 cntrl_flags = cntrl_flags |
3306 ((ticket << UPL_PAGE_TICKET_SHIFT)
3307 & UPL_PAGE_TICKET_MASK);
3308 }
3309 vm_object_unlock(object);
3310 }
3311
3312 if (super_cluster > size) {
3313
3314 vm_object_offset_t base_offset;
3315 upl_size_t super_size;
3316
3317 base_offset = (offset &
3318 ~((vm_object_offset_t) super_cluster - 1));
3319 super_size = (offset+size) > (base_offset + super_cluster) ?
3320 super_cluster<<1 : super_cluster;
3321 super_size = ((base_offset + super_size) > object->size) ?
3322 (object->size - base_offset) : super_size;
3323 if(offset > (base_offset + super_size))
3324 panic("vm_object_super_upl_request: Missed target pageout"
3325 " %#llx,%#llx, %#x, %#x, %#x, %#llx\n",
3326 offset, base_offset, super_size, super_cluster,
3327 size, object->paging_offset);
3328
3329
3330
3331
3332
3333 if((offset + size) > (base_offset + super_size))
3334 super_size = (offset + size) - base_offset;
3335
3336 offset = base_offset;
3337 size = super_size;
3338 }
3339 return vm_object_upl_request(object, offset, size,
3340 upl, user_page_list, page_list_count,
3341 cntrl_flags);
3342}
3343
3344
3345kern_return_t
3346vm_map_create_upl(
3347 vm_map_t map,
3348 vm_map_address_t offset,
3349 upl_size_t *upl_size,
3350 upl_t *upl,
3351 upl_page_info_array_t page_list,
3352 unsigned int *count,
3353 int *flags)
3354{
3355 vm_map_entry_t entry;
3356 int caller_flags;
3357 int force_data_sync;
3358 int sync_cow_data;
3359 vm_object_t local_object;
3360 vm_map_offset_t local_offset;
3361 vm_map_offset_t local_start;
3362 kern_return_t ret;
3363
3364 caller_flags = *flags;
3365
3366 if (caller_flags & ~UPL_VALID_FLAGS) {
3367
3368
3369
3370
3371 return KERN_INVALID_VALUE;
3372 }
3373
3374 force_data_sync = (caller_flags & UPL_FORCE_DATA_SYNC);
3375 sync_cow_data = !(caller_flags & UPL_COPYOUT_FROM);
3376
3377 if(upl == NULL)
3378 return KERN_INVALID_ARGUMENT;
3379
3380
3381REDISCOVER_ENTRY:
3382 vm_map_lock(map);
3383 if (vm_map_lookup_entry(map, offset, &entry)) {
3384 if (entry->object.vm_object == VM_OBJECT_NULL ||
3385 !entry->object.vm_object->phys_contiguous) {
3386 if((*upl_size/page_size) > MAX_UPL_TRANSFER) {
3387 *upl_size = MAX_UPL_TRANSFER * page_size;
3388 }
3389 }
3390 if((entry->vme_end - offset) < *upl_size) {
3391 *upl_size = entry->vme_end - offset;
3392 }
3393 if (caller_flags & UPL_QUERY_OBJECT_TYPE) {
3394 if (entry->object.vm_object == VM_OBJECT_NULL) {
3395 *flags = 0;
3396 } else if (entry->object.vm_object->private) {
3397 *flags = UPL_DEV_MEMORY;
3398 if (entry->object.vm_object->phys_contiguous) {
3399 *flags |= UPL_PHYS_CONTIG;
3400 }
3401 } else {
3402 *flags = 0;
3403 }
3404 vm_map_unlock(map);
3405 return KERN_SUCCESS;
3406 }
3407
3408
3409
3410 if (entry->object.vm_object == VM_OBJECT_NULL) {
3411 entry->object.vm_object = vm_object_allocate(
3412 (vm_size_t)(entry->vme_end - entry->vme_start));
3413 entry->offset = 0;
3414 }
3415 if (!(caller_flags & UPL_COPYOUT_FROM)) {
3416 if (!(entry->protection & VM_PROT_WRITE)) {
3417 vm_map_unlock(map);
3418 return KERN_PROTECTION_FAILURE;
3419 }
3420 if (entry->needs_copy) {
3421 vm_map_t local_map;
3422 vm_object_t object;
3423 vm_map_offset_t offset_hi;
3424 vm_map_offset_t offset_lo;
3425 vm_object_offset_t new_offset;
3426 vm_prot_t prot;
3427 boolean_t wired;
3428 vm_behavior_t behavior;
3429 vm_map_version_t version;
3430 vm_map_t real_map;
3431
3432 local_map = map;
3433 vm_map_lock_write_to_read(map);
3434 if(vm_map_lookup_locked(&local_map,
3435 offset, VM_PROT_WRITE,
3436 &version, &object,
3437 &new_offset, &prot, &wired,
3438 &behavior, &offset_lo,
3439 &offset_hi, &real_map)) {
3440 vm_map_unlock(local_map);
3441 return KERN_FAILURE;
3442 }
3443 if (real_map != map) {
3444 vm_map_unlock(real_map);
3445 }
3446 vm_object_unlock(object);
3447 vm_map_unlock(local_map);
3448
3449 goto REDISCOVER_ENTRY;
3450 }
3451 }
3452 if (entry->is_sub_map) {
3453 vm_map_t submap;
3454
3455 submap = entry->object.sub_map;
3456 local_start = entry->vme_start;
3457 local_offset = entry->offset;
3458 vm_map_reference(submap);
3459 vm_map_unlock(map);
3460
3461 ret = (vm_map_create_upl(submap,
3462 local_offset + (offset - local_start),
3463 upl_size, upl, page_list, count,
3464 flags));
3465
3466 vm_map_deallocate(submap);
3467 return ret;
3468 }
3469
3470 if (sync_cow_data) {
3471 if (entry->object.vm_object->shadow
3472 || entry->object.vm_object->copy) {
3473
3474 local_object = entry->object.vm_object;
3475 local_start = entry->vme_start;
3476 local_offset = entry->offset;
3477 vm_object_reference(local_object);
3478 vm_map_unlock(map);
3479
3480 if (entry->object.vm_object->shadow &&
3481 entry->object.vm_object->copy) {
3482 vm_object_lock_request(
3483 local_object->shadow,
3484 (vm_object_offset_t)
3485 ((offset - local_start) +
3486 local_offset) +
3487 local_object->shadow_offset,
3488 *upl_size, FALSE,
3489 MEMORY_OBJECT_DATA_SYNC,
3490 VM_PROT_NO_CHANGE);
3491 }
3492 sync_cow_data = FALSE;
3493 vm_object_deallocate(local_object);
3494 goto REDISCOVER_ENTRY;
3495 }
3496 }
3497
3498 if (force_data_sync) {
3499
3500 local_object = entry->object.vm_object;
3501 local_start = entry->vme_start;
3502 local_offset = entry->offset;
3503 vm_object_reference(local_object);
3504 vm_map_unlock(map);
3505
3506 vm_object_lock_request(
3507 local_object,
3508 (vm_object_offset_t)
3509 ((offset - local_start) + local_offset),
3510 (vm_object_size_t)*upl_size, FALSE,
3511 MEMORY_OBJECT_DATA_SYNC,
3512 VM_PROT_NO_CHANGE);
3513 force_data_sync = FALSE;
3514 vm_object_deallocate(local_object);
3515 goto REDISCOVER_ENTRY;
3516 }
3517
3518 if(!(entry->object.vm_object->private)) {
3519 if(*upl_size > (MAX_UPL_TRANSFER*PAGE_SIZE))
3520 *upl_size = (MAX_UPL_TRANSFER*PAGE_SIZE);
3521 if(entry->object.vm_object->phys_contiguous) {
3522 *flags = UPL_PHYS_CONTIG;
3523 } else {
3524 *flags = 0;
3525 }
3526 } else {
3527 *flags = UPL_DEV_MEMORY | UPL_PHYS_CONTIG;
3528 }
3529 local_object = entry->object.vm_object;
3530 local_offset = entry->offset;
3531 local_start = entry->vme_start;
3532 vm_object_reference(local_object);
3533 vm_map_unlock(map);
3534 if(caller_flags & UPL_SET_IO_WIRE) {
3535 ret = (vm_object_iopl_request(local_object,
3536 (vm_object_offset_t)
3537 ((offset - local_start)
3538 + local_offset),
3539 *upl_size,
3540 upl,
3541 page_list,
3542 count,
3543 caller_flags));
3544 } else {
3545 ret = (vm_object_upl_request(local_object,
3546 (vm_object_offset_t)
3547 ((offset - local_start)
3548 + local_offset),
3549 *upl_size,
3550 upl,
3551 page_list,
3552 count,
3553 caller_flags));
3554 }
3555 vm_object_deallocate(local_object);
3556 return(ret);
3557 }
3558
3559 vm_map_unlock(map);
3560 return(KERN_FAILURE);
3561
3562}
3563
3564
3565
3566
3567
3568
3569
3570kern_return_t
3571vm_map_enter_upl(
3572 vm_map_t map,
3573 upl_t upl,
3574 vm_map_offset_t *dst_addr)
3575{
3576 vm_map_size_t size;
3577 vm_object_offset_t offset;
3578 vm_map_offset_t addr;
3579 vm_page_t m;
3580 kern_return_t kr;
3581
3582 if (upl == UPL_NULL)
3583 return KERN_INVALID_ARGUMENT;
3584
3585 upl_lock(upl);
3586
3587
3588 if(UPL_PAGE_LIST_MAPPED & upl->flags) {
3589 upl_unlock(upl);
3590 return KERN_FAILURE;
3591 }
3592
3593 if((!(upl->map_object->pageout)) &&
3594 !((upl->flags & (UPL_DEVICE_MEMORY | UPL_IO_WIRE)) ||
3595 (upl->map_object->phys_contiguous))) {
3596 vm_object_t object;
3597 vm_page_t alias_page;
3598 vm_object_offset_t new_offset;
3599 int pg_num;
3600 wpl_array_t lite_list;
3601
3602 if(upl->flags & UPL_INTERNAL) {
3603 lite_list = (wpl_array_t)
3604 ((((uintptr_t)upl) + sizeof(struct upl))
3605 + ((upl->size/PAGE_SIZE)
3606 * sizeof(upl_page_info_t)));
3607 } else {
3608 lite_list = (wpl_array_t)
3609 (((uintptr_t)upl) + sizeof(struct upl));
3610 }
3611 object = upl->map_object;
3612 upl->map_object = vm_object_allocate(upl->size);
3613 vm_object_lock(upl->map_object);
3614 upl->map_object->shadow = object;
3615 upl->map_object->pageout = TRUE;
3616 upl->map_object->can_persist = FALSE;
3617 upl->map_object->copy_strategy =
3618 MEMORY_OBJECT_COPY_NONE;
3619 upl->map_object->shadow_offset =
3620 upl->offset - object->paging_offset;
3621 upl->map_object->wimg_bits = object->wimg_bits;
3622 offset = upl->map_object->shadow_offset;
3623 new_offset = 0;
3624 size = upl->size;
3625
3626 vm_object_lock(object);
3627
3628 while(size) {
3629 pg_num = (new_offset)/PAGE_SIZE;
3630 if(lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
3631 vm_object_unlock(object);
3632 VM_PAGE_GRAB_FICTITIOUS(alias_page);
3633 vm_object_lock(object);
3634 m = vm_page_lookup(object, offset);
3635 if (m == VM_PAGE_NULL) {
3636 panic("vm_upl_map: page missing\n");
3637 }
3638
3639 vm_object_paging_begin(object);
3640
3641
3642
3643
3644
3645 assert(alias_page->fictitious);
3646 alias_page->fictitious = FALSE;
3647 alias_page->private = TRUE;
3648 alias_page->pageout = TRUE;
3649 alias_page->phys_page = m->phys_page;
3650
3651 vm_page_lock_queues();
3652 vm_page_wire(alias_page);
3653 vm_page_unlock_queues();
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669 ASSERT_PAGE_DECRYPTED(m);
3670
3671 vm_page_insert(alias_page,
3672 upl->map_object, new_offset);
3673 assert(!alias_page->wanted);
3674 alias_page->busy = FALSE;
3675 alias_page->absent = FALSE;
3676 }
3677
3678 size -= PAGE_SIZE;
3679 offset += PAGE_SIZE_64;
3680 new_offset += PAGE_SIZE_64;
3681 }
3682 vm_object_unlock(object);
3683 vm_object_unlock(upl->map_object);
3684 }
3685 if ((upl->flags & (UPL_DEVICE_MEMORY | UPL_IO_WIRE)) || upl->map_object->phys_contiguous)
3686 offset = upl->offset - upl->map_object->paging_offset;
3687 else
3688 offset = 0;
3689
3690 size = upl->size;
3691
3692 vm_object_lock(upl->map_object);
3693 upl->map_object->ref_count++;
3694 vm_object_res_reference(upl->map_object);
3695 vm_object_unlock(upl->map_object);
3696
3697 *dst_addr = 0;
3698
3699
3700
3701 kr = vm_map_enter(map, dst_addr, (vm_map_size_t)size, (vm_map_offset_t) 0,
3702 VM_FLAGS_ANYWHERE, upl->map_object, offset, FALSE,
3703 VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
3704
3705 if (kr != KERN_SUCCESS) {
3706 upl_unlock(upl);
3707 return(kr);
3708 }
3709
3710 vm_object_lock(upl->map_object);
3711
3712 for(addr=*dst_addr; size > 0; size-=PAGE_SIZE,addr+=PAGE_SIZE) {
3713 m = vm_page_lookup(upl->map_object, offset);
3714 if(m) {
3715 unsigned int cache_attr;
3716 cache_attr = ((unsigned int)m->object->wimg_bits) & VM_WIMG_MASK;
3717
3718 PMAP_ENTER(map->pmap, addr,
3719 m, VM_PROT_ALL,
3720 cache_attr, TRUE);
3721 }
3722 offset+=PAGE_SIZE_64;
3723 }
3724 vm_object_unlock(upl->map_object);
3725
3726 upl->ref_count++;
3727 upl->flags |= UPL_PAGE_LIST_MAPPED;
3728 upl->kaddr = *dst_addr;
3729 upl_unlock(upl);
3730 return KERN_SUCCESS;
3731}
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743kern_return_t
3744vm_map_remove_upl(
3745 vm_map_t map,
3746 upl_t upl)
3747{
3748 vm_address_t addr;
3749 upl_size_t size;
3750
3751 if (upl == UPL_NULL)
3752 return KERN_INVALID_ARGUMENT;
3753
3754 upl_lock(upl);
3755 if(upl->flags & UPL_PAGE_LIST_MAPPED) {
3756 addr = upl->kaddr;
3757 size = upl->size;
3758 assert(upl->ref_count > 1);
3759 upl->ref_count--;
3760 upl->flags &= ~UPL_PAGE_LIST_MAPPED;
3761 upl->kaddr = (vm_offset_t) 0;
3762 upl_unlock(upl);
3763
3764 vm_map_remove( map,
3765 vm_map_trunc_page(addr),
3766 vm_map_round_page(addr + size),
3767 VM_MAP_NO_FLAGS);
3768 return KERN_SUCCESS;
3769 }
3770 upl_unlock(upl);
3771 return KERN_FAILURE;
3772}
3773
3774kern_return_t
3775upl_commit_range(
3776 upl_t upl,
3777 upl_offset_t offset,
3778 upl_size_t size,
3779 int flags,
3780 upl_page_info_t *page_list,
3781 mach_msg_type_number_t count,
3782 boolean_t *empty)
3783{
3784 upl_size_t xfer_size = size;
3785 vm_object_t shadow_object;
3786 vm_object_t object = upl->map_object;
3787 vm_object_offset_t target_offset;
3788 int entry;
3789 wpl_array_t lite_list;
3790 int occupied;
3791 int delayed_unlock = 0;
3792 int clear_refmod = 0;
3793 boolean_t shadow_internal;
3794
3795 *empty = FALSE;
3796
3797 if (upl == UPL_NULL)
3798 return KERN_INVALID_ARGUMENT;
3799
3800
3801 if (count == 0)
3802 page_list = NULL;
3803
3804 if (object->pageout) {
3805 shadow_object = object->shadow;
3806 } else {
3807 shadow_object = object;
3808 }
3809
3810 upl_lock(upl);
3811
3812 if (upl->flags & UPL_ACCESS_BLOCKED) {
3813
3814
3815
3816
3817
3818 flags |= UPL_COMMIT_ALLOW_ACCESS;
3819 }
3820
3821 if (upl->flags & UPL_CLEAR_DIRTY)
3822 flags |= UPL_COMMIT_CLEAR_DIRTY;
3823
3824 if (upl->flags & UPL_DEVICE_MEMORY) {
3825 xfer_size = 0;
3826 } else if ((offset + size) > upl->size) {
3827 upl_unlock(upl);
3828 return KERN_FAILURE;
3829 }
3830
3831 if (upl->flags & UPL_INTERNAL) {
3832 lite_list = (wpl_array_t)
3833 ((((uintptr_t)upl) + sizeof(struct upl))
3834 + ((upl->size/PAGE_SIZE) * sizeof(upl_page_info_t)));
3835 } else {
3836 lite_list = (wpl_array_t)
3837 (((uintptr_t)upl) + sizeof(struct upl));
3838 }
3839 if (object != shadow_object)
3840 vm_object_lock(object);
3841 vm_object_lock(shadow_object);
3842
3843 shadow_internal = shadow_object->internal;
3844
3845 entry = offset/PAGE_SIZE;
3846 target_offset = (vm_object_offset_t)offset;
3847
3848 while (xfer_size) {
3849 vm_page_t t,m;
3850 upl_page_info_t *p;
3851
3852 m = VM_PAGE_NULL;
3853
3854 if (upl->flags & UPL_LITE) {
3855 int pg_num;
3856
3857 pg_num = target_offset/PAGE_SIZE;
3858
3859 if (lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
3860 lite_list[pg_num>>5] &= ~(1 << (pg_num & 31));
3861 m = vm_page_lookup(shadow_object,
3862 target_offset + (upl->offset -
3863 shadow_object->paging_offset));
3864 }
3865 }
3866 if (object->pageout) {
3867 if ((t = vm_page_lookup(object, target_offset)) != NULL) {
3868 t->pageout = FALSE;
3869
3870 if (delayed_unlock) {
3871 delayed_unlock = 0;
3872 vm_page_unlock_queues();
3873 }
3874 VM_PAGE_FREE(t);
3875
3876 if (m == NULL) {
3877 m = vm_page_lookup(
3878 shadow_object,
3879 target_offset +
3880 object->shadow_offset);
3881 }
3882 if (m != VM_PAGE_NULL)
3883 vm_object_paging_end(m->object);
3884 }
3885 }
3886 if (m != VM_PAGE_NULL) {
3887
3888 clear_refmod = 0;
3889
3890 if (upl->flags & UPL_IO_WIRE) {
3891
3892 if (delayed_unlock == 0)
3893 vm_page_lock_queues();
3894
3895 vm_page_unwire(m);
3896
3897 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
3898 delayed_unlock = 0;
3899 vm_page_unlock_queues();
3900 }
3901 if (page_list) {
3902 page_list[entry].phys_addr = 0;
3903 }
3904 if (flags & UPL_COMMIT_SET_DIRTY) {
3905 m->dirty = TRUE;
3906 } else if (flags & UPL_COMMIT_CLEAR_DIRTY) {
3907 m->dirty = FALSE;
3908 clear_refmod |= VM_MEM_MODIFIED;
3909 }
3910 if (flags & UPL_COMMIT_INACTIVATE) {
3911 m->reference = FALSE;
3912 clear_refmod |= VM_MEM_REFERENCED;
3913 vm_page_deactivate(m);
3914 }
3915 if (clear_refmod)
3916 pmap_clear_refmod(m->phys_page, clear_refmod);
3917
3918 if (flags & UPL_COMMIT_ALLOW_ACCESS) {
3919
3920
3921
3922
3923
3924 PAGE_WAKEUP_DONE(m);
3925 }
3926
3927 target_offset += PAGE_SIZE_64;
3928 xfer_size -= PAGE_SIZE;
3929 entry++;
3930 continue;
3931 }
3932 if (delayed_unlock == 0)
3933 vm_page_lock_queues();
3934
3935
3936
3937
3938
3939
3940
3941 if (flags & UPL_COMMIT_CLEAR_DIRTY) {
3942 m->dirty = FALSE;
3943 clear_refmod |= VM_MEM_MODIFIED;
3944 }
3945 if (flags & UPL_COMMIT_INACTIVATE)
3946 clear_refmod |= VM_MEM_REFERENCED;
3947
3948 if (clear_refmod)
3949 pmap_clear_refmod(m->phys_page, clear_refmod);
3950
3951 if (page_list) {
3952 p = &(page_list[entry]);
3953 if(p->phys_addr && p->pageout && !m->pageout) {
3954 m->busy = TRUE;
3955 m->pageout = TRUE;
3956 vm_page_wire(m);
3957 } else if (page_list[entry].phys_addr &&
3958 !p->pageout && m->pageout &&
3959 !m->dump_cleaning) {
3960 m->pageout = FALSE;
3961 m->absent = FALSE;
3962 m->overwriting = FALSE;
3963 vm_page_unwire(m);
3964 PAGE_WAKEUP_DONE(m);
3965 }
3966 page_list[entry].phys_addr = 0;
3967 }
3968 m->dump_cleaning = FALSE;
3969 if(m->laundry) {
3970 vm_pageout_throttle_up(m);
3971 }
3972 if(m->pageout) {
3973 m->cleaning = FALSE;
3974 m->pageout = FALSE;
3975#if MACH_CLUSTER_STATS
3976 if (m->wanted) vm_pageout_target_collisions++;
3977#endif
3978 if (pmap_disconnect(m->phys_page) & VM_MEM_MODIFIED)
3979 m->dirty = TRUE;
3980 else
3981 m->dirty = FALSE;
3982
3983 if(m->dirty) {
3984 vm_page_unwire(m);
3985
3986 if (upl->flags & UPL_PAGEOUT) {
3987 CLUSTER_STAT(vm_pageout_target_page_dirtied++;)
3988 VM_STAT(reactivations++);
3989 }
3990 PAGE_WAKEUP_DONE(m);
3991 } else {
3992 vm_page_free(m);
3993
3994 if (upl->flags & UPL_PAGEOUT) {
3995 CLUSTER_STAT(vm_pageout_target_page_freed++;)
3996
3997 if (page_list[entry].dirty)
3998 VM_STAT(pageouts++);
3999 }
4000 }
4001 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
4002 delayed_unlock = 0;
4003 vm_page_unlock_queues();
4004 }
4005 target_offset += PAGE_SIZE_64;
4006 xfer_size -= PAGE_SIZE;
4007 entry++;
4008 continue;
4009 }
4010#if MACH_CLUSTER_STATS
4011 m->dirty = pmap_is_modified(m->phys_page);
4012
4013 if (m->dirty) vm_pageout_cluster_dirtied++;
4014 else vm_pageout_cluster_cleaned++;
4015 if (m->wanted) vm_pageout_cluster_collisions++;
4016#else
4017 m->dirty = 0;
4018#endif
4019
4020 if((m->busy) && (m->cleaning)) {
4021
4022 if(m->absent) {
4023 m->absent = FALSE;
4024 if(shadow_object->absent_count == 1)
4025 vm_object_absent_release(shadow_object);
4026 else
4027 shadow_object->absent_count--;
4028 }
4029 m->overwriting = FALSE;
4030 m->busy = FALSE;
4031 m->dirty = FALSE;
4032 } else if (m->overwriting) {
4033
4034
4035
4036
4037 assert(m->wire_count != 0);
4038 vm_page_unwire(m);
4039 m->overwriting = FALSE;
4040 }
4041 m->cleaning = FALSE;
4042
4043
4044
4045
4046
4047
4048 if (upl->flags & UPL_PAGE_SYNC_DONE)
4049 m->precious = FALSE;
4050
4051 if (flags & UPL_COMMIT_SET_DIRTY)
4052 m->dirty = TRUE;
4053
4054 if (flags & UPL_COMMIT_INACTIVATE) {
4055 m->reference = FALSE;
4056 vm_page_deactivate(m);
4057 } else if (!m->active && !m->inactive) {
4058 if (m->reference)
4059 vm_page_activate(m);
4060 else
4061 vm_page_deactivate(m);
4062 }
4063
4064 if (flags & UPL_COMMIT_ALLOW_ACCESS) {
4065
4066
4067
4068
4069
4070 m->busy = FALSE;
4071 }
4072
4073
4074
4075
4076 PAGE_WAKEUP(m);
4077
4078 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
4079 delayed_unlock = 0;
4080 vm_page_unlock_queues();
4081 }
4082 }
4083 target_offset += PAGE_SIZE_64;
4084 xfer_size -= PAGE_SIZE;
4085 entry++;
4086 }
4087 if (delayed_unlock)
4088 vm_page_unlock_queues();
4089
4090 occupied = 1;
4091
4092 if (upl->flags & UPL_DEVICE_MEMORY) {
4093 occupied = 0;
4094 } else if (upl->flags & UPL_LITE) {
4095 int pg_num;
4096 int i;
4097 pg_num = upl->size/PAGE_SIZE;
4098 pg_num = (pg_num + 31) >> 5;
4099 occupied = 0;
4100 for(i= 0; i<pg_num; i++) {
4101 if(lite_list[i] != 0) {
4102 occupied = 1;
4103 break;
4104 }
4105 }
4106 } else {
4107 if(queue_empty(&upl->map_object->memq)) {
4108 occupied = 0;
4109 }
4110 }
4111
4112 if(occupied == 0) {
4113 if(upl->flags & UPL_COMMIT_NOTIFY_EMPTY) {
4114 *empty = TRUE;
4115 }
4116 if(object == shadow_object)
4117 vm_object_paging_end(shadow_object);
4118 }
4119 vm_object_unlock(shadow_object);
4120 if (object != shadow_object)
4121 vm_object_unlock(object);
4122 upl_unlock(upl);
4123
4124 return KERN_SUCCESS;
4125}
4126
4127kern_return_t
4128upl_abort_range(
4129 upl_t upl,
4130 upl_offset_t offset,
4131 upl_size_t size,
4132 int error,
4133 boolean_t *empty)
4134{
4135 upl_size_t xfer_size = size;
4136 vm_object_t shadow_object;
4137 vm_object_t object = upl->map_object;
4138 vm_object_offset_t target_offset;
4139 int entry;
4140 wpl_array_t lite_list;
4141 int occupied;
4142 boolean_t shadow_internal;
4143
4144 *empty = FALSE;
4145
4146 if (upl == UPL_NULL)
4147 return KERN_INVALID_ARGUMENT;
4148
4149 if (upl->flags & UPL_IO_WIRE) {
4150 return upl_commit_range(upl,
4151 offset, size, 0,
4152 NULL, 0, empty);
4153 }
4154
4155 if(object->pageout) {
4156 shadow_object = object->shadow;
4157 } else {
4158 shadow_object = object;
4159 }
4160
4161 upl_lock(upl);
4162 if(upl->flags & UPL_DEVICE_MEMORY) {
4163 xfer_size = 0;
4164 } else if ((offset + size) > upl->size) {
4165 upl_unlock(upl);
4166 return KERN_FAILURE;
4167 }
4168 if (object != shadow_object)
4169 vm_object_lock(object);
4170 vm_object_lock(shadow_object);
4171
4172 shadow_internal = shadow_object->internal;
4173
4174 if(upl->flags & UPL_INTERNAL) {
4175 lite_list = (wpl_array_t)
4176 ((((uintptr_t)upl) + sizeof(struct upl))
4177 + ((upl->size/PAGE_SIZE) * sizeof(upl_page_info_t)));
4178 } else {
4179 lite_list = (wpl_array_t)
4180 (((uintptr_t)upl) + sizeof(struct upl));
4181 }
4182
4183 entry = offset/PAGE_SIZE;
4184 target_offset = (vm_object_offset_t)offset;
4185 while(xfer_size) {
4186 vm_page_t t,m;
4187
4188 m = VM_PAGE_NULL;
4189 if(upl->flags & UPL_LITE) {
4190 int pg_num;
4191 pg_num = target_offset/PAGE_SIZE;
4192 if(lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
4193 lite_list[pg_num>>5] &= ~(1 << (pg_num & 31));
4194 m = vm_page_lookup(shadow_object,
4195 target_offset + (upl->offset -
4196 shadow_object->paging_offset));
4197 }
4198 }
4199 if(object->pageout) {
4200 if ((t = vm_page_lookup(object, target_offset))
4201 != NULL) {
4202 t->pageout = FALSE;
4203 VM_PAGE_FREE(t);
4204 if(m == NULL) {
4205 m = vm_page_lookup(
4206 shadow_object,
4207 target_offset +
4208 object->shadow_offset);
4209 }
4210 if(m != VM_PAGE_NULL)
4211 vm_object_paging_end(m->object);
4212 }
4213 }
4214 if(m != VM_PAGE_NULL) {
4215 vm_page_lock_queues();
4216 if(m->absent) {
4217 boolean_t must_free = TRUE;
4218
4219
4220
4221
4222 if(error & UPL_ABORT_RESTART) {
4223 m->restart = TRUE;
4224 m->absent = FALSE;
4225 vm_object_absent_release(m->object);
4226 m->page_error = KERN_MEMORY_ERROR;
4227 m->error = TRUE;
4228 must_free = FALSE;
4229 } else if(error & UPL_ABORT_UNAVAILABLE) {
4230 m->restart = FALSE;
4231 m->unusual = TRUE;
4232 must_free = FALSE;
4233 } else if(error & UPL_ABORT_ERROR) {
4234 m->restart = FALSE;
4235 m->absent = FALSE;
4236 vm_object_absent_release(m->object);
4237 m->page_error = KERN_MEMORY_ERROR;
4238 m->error = TRUE;
4239 must_free = FALSE;
4240 }
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251 m->cleaning = FALSE;
4252 m->overwriting = FALSE;
4253 PAGE_WAKEUP_DONE(m);
4254
4255 if (must_free == TRUE) {
4256 vm_page_free(m);
4257 } else {
4258 vm_page_activate(m);
4259 }
4260 vm_page_unlock_queues();
4261
4262 target_offset += PAGE_SIZE_64;
4263 xfer_size -= PAGE_SIZE;
4264 entry++;
4265 continue;
4266 }
4267
4268
4269
4270 if (m->laundry) {
4271 vm_pageout_throttle_up(m);
4272 }
4273 if(m->pageout) {
4274 assert(m->busy);
4275 assert(m->wire_count == 1);
4276 m->pageout = FALSE;
4277 vm_page_unwire(m);
4278 }
4279 m->dump_cleaning = FALSE;
4280 m->cleaning = FALSE;
4281 m->overwriting = FALSE;
4282#if MACH_PAGEMAP
4283 vm_external_state_clr(
4284 m->object->existence_map, m->offset);
4285#endif
4286 if(error & UPL_ABORT_DUMP_PAGES) {
4287 vm_page_free(m);
4288 pmap_disconnect(m->phys_page);
4289 } else {
4290 PAGE_WAKEUP_DONE(m);
4291 }
4292 vm_page_unlock_queues();
4293 }
4294 target_offset += PAGE_SIZE_64;
4295 xfer_size -= PAGE_SIZE;
4296 entry++;
4297 }
4298 occupied = 1;
4299 if (upl->flags & UPL_DEVICE_MEMORY) {
4300 occupied = 0;
4301 } else if (upl->flags & UPL_LITE) {
4302 int pg_num;
4303 int i;
4304 pg_num = upl->size/PAGE_SIZE;
4305 pg_num = (pg_num + 31) >> 5;
4306 occupied = 0;
4307 for(i= 0; i<pg_num; i++) {
4308 if(lite_list[i] != 0) {
4309 occupied = 1;
4310 break;
4311 }
4312 }
4313 } else {
4314 if(queue_empty(&upl->map_object->memq)) {
4315 occupied = 0;
4316 }
4317 }
4318
4319 if(occupied == 0) {
4320 if(upl->flags & UPL_COMMIT_NOTIFY_EMPTY) {
4321 *empty = TRUE;
4322 }
4323 if(object == shadow_object)
4324 vm_object_paging_end(shadow_object);
4325 }
4326 vm_object_unlock(shadow_object);
4327 if (object != shadow_object)
4328 vm_object_unlock(object);
4329
4330 upl_unlock(upl);
4331
4332 return KERN_SUCCESS;
4333}
4334
4335kern_return_t
4336upl_abort(
4337 upl_t upl,
4338 int error)
4339{
4340 vm_object_t object = NULL;
4341 vm_object_t shadow_object = NULL;
4342 vm_object_offset_t offset;
4343 vm_object_offset_t shadow_offset;
4344 vm_object_offset_t target_offset;
4345 upl_size_t i;
4346 wpl_array_t lite_list;
4347 vm_page_t t,m;
4348 int occupied;
4349 boolean_t shadow_internal;
4350
4351 if (upl == UPL_NULL)
4352 return KERN_INVALID_ARGUMENT;
4353
4354 if (upl->flags & UPL_IO_WIRE) {
4355 boolean_t empty;
4356 return upl_commit_range(upl,
4357 0, upl->size, 0,
4358 NULL, 0, &empty);
4359 }
4360
4361 upl_lock(upl);
4362 if(upl->flags & UPL_DEVICE_MEMORY) {
4363 upl_unlock(upl);
4364 return KERN_SUCCESS;
4365 }
4366
4367 object = upl->map_object;
4368
4369 if (object == NULL) {
4370 panic("upl_abort: upl object is not backed by an object");
4371 upl_unlock(upl);
4372 return KERN_INVALID_ARGUMENT;
4373 }
4374
4375 if(object->pageout) {
4376 shadow_object = object->shadow;
4377 shadow_offset = object->shadow_offset;
4378 } else {
4379 shadow_object = object;
4380 shadow_offset = upl->offset - object->paging_offset;
4381 }
4382
4383 if(upl->flags & UPL_INTERNAL) {
4384 lite_list = (wpl_array_t)
4385 ((((uintptr_t)upl) + sizeof(struct upl))
4386 + ((upl->size/PAGE_SIZE) * sizeof(upl_page_info_t)));
4387 } else {
4388 lite_list = (wpl_array_t)
4389 (((uintptr_t)upl) + sizeof(struct upl));
4390 }
4391 offset = 0;
4392
4393 if (object != shadow_object)
4394 vm_object_lock(object);
4395 vm_object_lock(shadow_object);
4396
4397 shadow_internal = shadow_object->internal;
4398
4399 for(i = 0; i<(upl->size); i+=PAGE_SIZE, offset += PAGE_SIZE_64) {
4400 m = VM_PAGE_NULL;
4401 target_offset = offset + shadow_offset;
4402 if(upl->flags & UPL_LITE) {
4403 int pg_num;
4404 pg_num = offset/PAGE_SIZE;
4405 if(lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
4406 lite_list[pg_num>>5] &= ~(1 << (pg_num & 31));
4407 m = vm_page_lookup(
4408 shadow_object, target_offset);
4409 }
4410 }
4411 if(object->pageout) {
4412 if ((t = vm_page_lookup(object, offset)) != NULL) {
4413 t->pageout = FALSE;
4414 VM_PAGE_FREE(t);
4415 if(m == NULL) {
4416 m = vm_page_lookup(
4417 shadow_object, target_offset);
4418 }
4419 if(m != VM_PAGE_NULL)
4420 vm_object_paging_end(m->object);
4421 }
4422 }
4423 if(m != VM_PAGE_NULL) {
4424 vm_page_lock_queues();
4425 if(m->absent) {
4426 boolean_t must_free = TRUE;
4427
4428
4429
4430
4431 if(error & UPL_ABORT_RESTART) {
4432 m->restart = TRUE;
4433 m->absent = FALSE;
4434 vm_object_absent_release(m->object);
4435 m->page_error = KERN_MEMORY_ERROR;
4436 m->error = TRUE;
4437 must_free = FALSE;
4438 } else if(error & UPL_ABORT_UNAVAILABLE) {
4439 m->restart = FALSE;
4440 m->unusual = TRUE;
4441 must_free = FALSE;
4442 } else if(error & UPL_ABORT_ERROR) {
4443 m->restart = FALSE;
4444 m->absent = FALSE;
4445 vm_object_absent_release(m->object);
4446 m->page_error = KERN_MEMORY_ERROR;
4447 m->error = TRUE;
4448 must_free = FALSE;
4449 }
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460 m->cleaning = FALSE;
4461 m->overwriting = FALSE;
4462 PAGE_WAKEUP_DONE(m);
4463
4464 if (must_free == TRUE) {
4465 vm_page_free(m);
4466 } else {
4467 vm_page_activate(m);
4468 }
4469 vm_page_unlock_queues();
4470 continue;
4471 }
4472
4473
4474
4475 if (m->laundry) {
4476 vm_pageout_throttle_up(m);
4477 }
4478 if(m->pageout) {
4479 assert(m->busy);
4480 assert(m->wire_count == 1);
4481 m->pageout = FALSE;
4482 vm_page_unwire(m);
4483 }
4484 m->dump_cleaning = FALSE;
4485 m->cleaning = FALSE;
4486 m->overwriting = FALSE;
4487#if MACH_PAGEMAP
4488 vm_external_state_clr(
4489 m->object->existence_map, m->offset);
4490#endif
4491 if(error & UPL_ABORT_DUMP_PAGES) {
4492 vm_page_free(m);
4493 pmap_disconnect(m->phys_page);
4494 } else {
4495 PAGE_WAKEUP_DONE(m);
4496 }
4497 vm_page_unlock_queues();
4498 }
4499 }
4500 occupied = 1;
4501 if (upl->flags & UPL_DEVICE_MEMORY) {
4502 occupied = 0;
4503 } else if (upl->flags & UPL_LITE) {
4504 int pg_num;
4505 int j;
4506 pg_num = upl->size/PAGE_SIZE;
4507 pg_num = (pg_num + 31) >> 5;
4508 occupied = 0;
4509 for(j= 0; j<pg_num; j++) {
4510 if(lite_list[j] != 0) {
4511 occupied = 1;
4512 break;
4513 }
4514 }
4515 } else {
4516 if(queue_empty(&upl->map_object->memq)) {
4517 occupied = 0;
4518 }
4519 }
4520
4521 if(occupied == 0) {
4522 if(object == shadow_object)
4523 vm_object_paging_end(shadow_object);
4524 }
4525 vm_object_unlock(shadow_object);
4526 if (object != shadow_object)
4527 vm_object_unlock(object);
4528
4529 upl_unlock(upl);
4530 return KERN_SUCCESS;
4531}
4532
4533
4534kern_return_t
4535upl_commit(
4536 upl_t upl,
4537 upl_page_info_t *page_list,
4538 mach_msg_type_number_t count)
4539{
4540 if (upl == UPL_NULL)
4541 return KERN_INVALID_ARGUMENT;
4542
4543 if(upl->flags & (UPL_LITE | UPL_IO_WIRE)) {
4544 boolean_t empty;
4545 return upl_commit_range(upl, 0, upl->size, 0,
4546 page_list, count, &empty);
4547 }
4548
4549 if (count == 0)
4550 page_list = NULL;
4551
4552 upl_lock(upl);
4553 if (upl->flags & UPL_DEVICE_MEMORY)
4554 page_list = NULL;
4555
4556 if (upl->flags & UPL_ENCRYPTED) {
4557
4558
4559
4560
4561
4562
4563
4564 }
4565
4566 if ((upl->flags & UPL_CLEAR_DIRTY) ||
4567 (upl->flags & UPL_PAGE_SYNC_DONE) || page_list) {
4568 vm_object_t shadow_object = upl->map_object->shadow;
4569 vm_object_t object = upl->map_object;
4570 vm_object_offset_t target_offset;
4571 upl_size_t xfer_end;
4572 int entry;
4573
4574 vm_page_t t, m;
4575 upl_page_info_t *p;
4576
4577 if (object != shadow_object)
4578 vm_object_lock(object);
4579 vm_object_lock(shadow_object);
4580
4581 entry = 0;
4582 target_offset = object->shadow_offset;
4583 xfer_end = upl->size + object->shadow_offset;
4584
4585 while(target_offset < xfer_end) {
4586
4587 if ((t = vm_page_lookup(object,
4588 target_offset - object->shadow_offset))
4589 == NULL) {
4590 target_offset += PAGE_SIZE_64;
4591 entry++;
4592 continue;
4593 }
4594
4595 m = vm_page_lookup(shadow_object, target_offset);
4596 if(m != VM_PAGE_NULL) {
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606 if (upl->flags & UPL_CLEAR_DIRTY) {
4607 pmap_clear_modify(m->phys_page);
4608 m->dirty = FALSE;
4609 }
4610
4611
4612
4613
4614
4615
4616 if (upl->flags & UPL_PAGE_SYNC_DONE)
4617 m->precious = FALSE;
4618
4619 if(page_list) {
4620 p = &(page_list[entry]);
4621 if(page_list[entry].phys_addr &&
4622 p->pageout && !m->pageout) {
4623 vm_page_lock_queues();
4624 m->busy = TRUE;
4625 m->pageout = TRUE;
4626 vm_page_wire(m);
4627 vm_page_unlock_queues();
4628 } else if (page_list[entry].phys_addr &&
4629 !p->pageout && m->pageout &&
4630 !m->dump_cleaning) {
4631 vm_page_lock_queues();
4632 m->pageout = FALSE;
4633 m->absent = FALSE;
4634 m->overwriting = FALSE;
4635 vm_page_unwire(m);
4636 PAGE_WAKEUP_DONE(m);
4637 vm_page_unlock_queues();
4638 }
4639 page_list[entry].phys_addr = 0;
4640 }
4641 }
4642 target_offset += PAGE_SIZE_64;
4643 entry++;
4644 }
4645 vm_object_unlock(shadow_object);
4646 if (object != shadow_object)
4647 vm_object_unlock(object);
4648
4649 }
4650 if (upl->flags & UPL_DEVICE_MEMORY) {
4651 vm_object_lock(upl->map_object->shadow);
4652 if(upl->map_object == upl->map_object->shadow)
4653 vm_object_paging_end(upl->map_object->shadow);
4654 vm_object_unlock(upl->map_object->shadow);
4655 }
4656 upl_unlock(upl);
4657 return KERN_SUCCESS;
4658}
4659
4660
4661
4662kern_return_t
4663vm_object_iopl_request(
4664 vm_object_t object,
4665 vm_object_offset_t offset,
4666 upl_size_t size,
4667 upl_t *upl_ptr,
4668 upl_page_info_array_t user_page_list,
4669 unsigned int *page_list_count,
4670 int cntrl_flags)
4671{
4672 vm_page_t dst_page;
4673 vm_object_offset_t dst_offset = offset;
4674 upl_size_t xfer_size = size;
4675 upl_t upl = NULL;
4676 unsigned int entry;
4677 wpl_array_t lite_list = NULL;
4678 int page_field_size;
4679 int delayed_unlock = 0;
4680 int no_zero_fill = FALSE;
4681 vm_page_t alias_page = NULL;
4682 kern_return_t ret;
4683 vm_prot_t prot;
4684
4685
4686 if (cntrl_flags & ~UPL_VALID_FLAGS) {
4687
4688
4689
4690
4691 return KERN_INVALID_VALUE;
4692 }
4693
4694 if (cntrl_flags & UPL_ENCRYPT) {
4695
4696
4697
4698
4699
4700
4701 assert(! (cntrl_flags & UPL_ENCRYPT));
4702 }
4703
4704 if (cntrl_flags & UPL_NOZEROFILL)
4705 no_zero_fill = TRUE;
4706
4707 if (cntrl_flags & UPL_COPYOUT_FROM)
4708 prot = VM_PROT_READ;
4709 else
4710 prot = VM_PROT_READ | VM_PROT_WRITE;
4711
4712 if(((size/page_size) > MAX_UPL_TRANSFER) && !object->phys_contiguous) {
4713 size = MAX_UPL_TRANSFER * page_size;
4714 }
4715
4716 if(cntrl_flags & UPL_SET_INTERNAL)
4717 if(page_list_count != NULL)
4718 *page_list_count = MAX_UPL_TRANSFER;
4719 if(((cntrl_flags & UPL_SET_INTERNAL) && !(object->phys_contiguous)) &&
4720 ((page_list_count != NULL) && (*page_list_count != 0)
4721 && *page_list_count < (size/page_size)))
4722 return KERN_INVALID_ARGUMENT;
4723
4724 if((!object->internal) && (object->paging_offset != 0))
4725 panic("vm_object_upl_request: vnode object with non-zero paging offset\n");
4726
4727 if(object->phys_contiguous) {
4728
4729
4730 cntrl_flags |= UPL_SET_LITE;
4731 }
4732
4733 if(upl_ptr) {
4734 if(cntrl_flags & UPL_SET_INTERNAL) {
4735 if(cntrl_flags & UPL_SET_LITE) {
4736 upl = upl_create(
4737 UPL_CREATE_INTERNAL | UPL_CREATE_LITE,
4738 size);
4739 user_page_list = (upl_page_info_t *)
4740 (((uintptr_t)upl) + sizeof(struct upl));
4741 lite_list = (wpl_array_t)
4742 (((uintptr_t)user_page_list) +
4743 ((size/PAGE_SIZE) *
4744 sizeof(upl_page_info_t)));
4745 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
4746 page_field_size =
4747 (page_field_size + 3) & 0xFFFFFFFC;
4748 bzero((char *)lite_list, page_field_size);
4749 upl->flags =
4750 UPL_LITE | UPL_INTERNAL | UPL_IO_WIRE;
4751 } else {
4752 upl = upl_create(UPL_CREATE_INTERNAL, size);
4753 user_page_list = (upl_page_info_t *)
4754 (((uintptr_t)upl)
4755 + sizeof(struct upl));
4756 upl->flags = UPL_INTERNAL | UPL_IO_WIRE;
4757 }
4758 } else {
4759 if(cntrl_flags & UPL_SET_LITE) {
4760 upl = upl_create(UPL_CREATE_LITE, size);
4761 lite_list = (wpl_array_t)
4762 (((uintptr_t)upl) + sizeof(struct upl));
4763 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
4764 page_field_size =
4765 (page_field_size + 3) & 0xFFFFFFFC;
4766 bzero((char *)lite_list, page_field_size);
4767 upl->flags = UPL_LITE | UPL_IO_WIRE;
4768 } else {
4769 upl = upl_create(UPL_CREATE_EXTERNAL, size);
4770 upl->flags = UPL_IO_WIRE;
4771 }
4772 }
4773
4774 if(object->phys_contiguous) {
4775 upl->map_object = object;
4776
4777
4778 upl->flags |= UPL_DEVICE_MEMORY;
4779
4780 vm_object_lock(object);
4781 vm_object_paging_begin(object);
4782 vm_object_unlock(object);
4783
4784
4785 upl->offset = offset + object->paging_offset;
4786 upl->size = size;
4787 *upl_ptr = upl;
4788 if(user_page_list) {
4789 user_page_list[0].phys_addr =
4790 (offset + object->shadow_offset)>>PAGE_SHIFT;
4791 user_page_list[0].device = TRUE;
4792 }
4793
4794 if(page_list_count != NULL) {
4795 if (upl->flags & UPL_INTERNAL) {
4796 *page_list_count = 0;
4797 } else {
4798 *page_list_count = 1;
4799 }
4800 }
4801 return KERN_SUCCESS;
4802 }
4803 if(user_page_list)
4804 user_page_list[0].device = FALSE;
4805
4806 if(cntrl_flags & UPL_SET_LITE) {
4807 upl->map_object = object;
4808 } else {
4809 upl->map_object = vm_object_allocate(size);
4810 vm_object_lock(upl->map_object);
4811 upl->map_object->shadow = object;
4812 upl->map_object->pageout = TRUE;
4813 upl->map_object->can_persist = FALSE;
4814 upl->map_object->copy_strategy =
4815 MEMORY_OBJECT_COPY_NONE;
4816 upl->map_object->shadow_offset = offset;
4817 upl->map_object->wimg_bits = object->wimg_bits;
4818 vm_object_unlock(upl->map_object);
4819 }
4820 }
4821 vm_object_lock(object);
4822 vm_object_paging_begin(object);
4823
4824 if (!object->phys_contiguous) {
4825
4826 object->true_share = TRUE;
4827 if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC)
4828 object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
4829 }
4830
4831
4832 if(upl_ptr) {
4833 upl->size = size;
4834 upl->offset = offset + object->paging_offset;
4835 *upl_ptr = upl;
4836#ifdef UPL_DEBUG
4837 queue_enter(&object->uplq, upl, upl_t, uplq);
4838#endif
4839 }
4840
4841 if (cntrl_flags & UPL_BLOCK_ACCESS) {
4842
4843
4844
4845
4846 upl->flags |= UPL_ACCESS_BLOCKED;
4847 }
4848
4849 entry = 0;
4850 while (xfer_size) {
4851 if((alias_page == NULL) && !(cntrl_flags & UPL_SET_LITE)) {
4852 if (delayed_unlock) {
4853 delayed_unlock = 0;
4854 vm_page_unlock_queues();
4855 }
4856 vm_object_unlock(object);
4857 VM_PAGE_GRAB_FICTITIOUS(alias_page);
4858 vm_object_lock(object);
4859 }
4860 dst_page = vm_page_lookup(object, dst_offset);
4861
4862
4863
4864
4865
4866
4867 if ((dst_page == VM_PAGE_NULL) || (dst_page->busy) ||
4868 (dst_page->encrypted) ||
4869 (dst_page->unusual && (dst_page->error ||
4870 dst_page->restart ||
4871 dst_page->absent ||
4872 dst_page->fictitious ||
4873 (prot & dst_page->page_lock)))) {
4874 vm_fault_return_t result;
4875 do {
4876 vm_page_t top_page;
4877 kern_return_t error_code;
4878 int interruptible;
4879
4880 vm_object_offset_t lo_offset = offset;
4881 vm_object_offset_t hi_offset = offset + size;
4882
4883
4884 if (delayed_unlock) {
4885 delayed_unlock = 0;
4886 vm_page_unlock_queues();
4887 }
4888
4889 if(cntrl_flags & UPL_SET_INTERRUPTIBLE) {
4890 interruptible = THREAD_ABORTSAFE;
4891 } else {
4892 interruptible = THREAD_UNINT;
4893 }
4894
4895 result = vm_fault_page(object, dst_offset,
4896 prot | VM_PROT_WRITE, FALSE,
4897 interruptible,
4898 lo_offset, hi_offset,
4899 VM_BEHAVIOR_SEQUENTIAL,
4900 &prot, &dst_page, &top_page,
4901 (int *)0,
4902 &error_code, no_zero_fill, FALSE, NULL, 0);
4903
4904 switch(result) {
4905 case VM_FAULT_SUCCESS:
4906
4907 PAGE_WAKEUP_DONE(dst_page);
4908
4909
4910
4911
4912
4913
4914 if(top_page != VM_PAGE_NULL) {
4915 vm_object_t local_object;
4916 local_object =
4917 top_page->object;
4918 if(top_page->object
4919 != dst_page->object) {
4920 vm_object_lock(
4921 local_object);
4922 VM_PAGE_FREE(top_page);
4923 vm_object_paging_end(
4924 local_object);
4925 vm_object_unlock(
4926 local_object);
4927 } else {
4928 VM_PAGE_FREE(top_page);
4929 vm_object_paging_end(
4930 local_object);
4931 }
4932 }
4933
4934 break;
4935
4936
4937 case VM_FAULT_RETRY:
4938 vm_object_lock(object);
4939 vm_object_paging_begin(object);
4940 break;
4941
4942 case VM_FAULT_FICTITIOUS_SHORTAGE:
4943 vm_page_more_fictitious();
4944 vm_object_lock(object);
4945 vm_object_paging_begin(object);
4946 break;
4947
4948 case VM_FAULT_MEMORY_SHORTAGE:
4949 if (vm_page_wait(interruptible)) {
4950 vm_object_lock(object);
4951 vm_object_paging_begin(object);
4952 break;
4953 }
4954
4955
4956 case VM_FAULT_INTERRUPTED:
4957 error_code = MACH_SEND_INTERRUPTED;
4958 case VM_FAULT_MEMORY_ERROR:
4959 ret = (error_code ? error_code:
4960 KERN_MEMORY_ERROR);
4961 vm_object_lock(object);
4962 for(; offset < dst_offset;
4963 offset += PAGE_SIZE) {
4964 dst_page = vm_page_lookup(
4965 object, offset);
4966 if(dst_page == VM_PAGE_NULL)
4967 panic("vm_object_iopl_request: Wired pages missing. \n");
4968 vm_page_lock_queues();
4969 vm_page_unwire(dst_page);
4970 vm_page_unlock_queues();
4971 VM_STAT(reactivations++);
4972 }
4973 vm_object_unlock(object);
4974 upl_destroy(upl);
4975 return ret;
4976 }
4977 } while ((result != VM_FAULT_SUCCESS)
4978 || (result == VM_FAULT_INTERRUPTED));
4979 }
4980 if (delayed_unlock == 0)
4981 vm_page_lock_queues();
4982 vm_page_wire(dst_page);
4983
4984 if (cntrl_flags & UPL_BLOCK_ACCESS) {
4985
4986
4987
4988
4989
4990 assert(!dst_page->fictitious);
4991 dst_page->busy = TRUE;
4992 }
4993
4994 if (upl_ptr) {
4995 if (cntrl_flags & UPL_SET_LITE) {
4996 int pg_num;
4997 pg_num = (dst_offset-offset)/PAGE_SIZE;
4998 lite_list[pg_num>>5] |= 1 << (pg_num & 31);
4999 } else {
5000
5001
5002
5003
5004 assert(alias_page->fictitious);
5005 alias_page->fictitious = FALSE;
5006 alias_page->private = TRUE;
5007 alias_page->pageout = TRUE;
5008 alias_page->phys_page = dst_page->phys_page;
5009 vm_page_wire(alias_page);
5010
5011 vm_page_insert(alias_page,
5012 upl->map_object, size - xfer_size);
5013 assert(!alias_page->wanted);
5014 alias_page->busy = FALSE;
5015 alias_page->absent = FALSE;
5016 }
5017
5018
5019 dst_page->reference = TRUE;
5020
5021 if (!(cntrl_flags & UPL_COPYOUT_FROM))
5022 dst_page->dirty = TRUE;
5023 alias_page = NULL;
5024
5025 if (user_page_list) {
5026 user_page_list[entry].phys_addr
5027 = dst_page->phys_page;
5028 user_page_list[entry].dirty =
5029 dst_page->dirty;
5030 user_page_list[entry].pageout =
5031 dst_page->pageout;
5032 user_page_list[entry].absent =
5033 dst_page->absent;
5034 user_page_list[entry].precious =
5035 dst_page->precious;
5036 }
5037 }
5038 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
5039 delayed_unlock = 0;
5040 vm_page_unlock_queues();
5041 }
5042 entry++;
5043 dst_offset += PAGE_SIZE_64;
5044 xfer_size -= PAGE_SIZE;
5045 }
5046 if (delayed_unlock)
5047 vm_page_unlock_queues();
5048
5049 if (upl->flags & UPL_INTERNAL) {
5050 if(page_list_count != NULL)
5051 *page_list_count = 0;
5052 } else if (*page_list_count > entry) {
5053 if(page_list_count != NULL)
5054 *page_list_count = entry;
5055 }
5056
5057 if (alias_page != NULL) {
5058 vm_page_lock_queues();
5059 vm_page_free(alias_page);
5060 vm_page_unlock_queues();
5061 }
5062
5063 vm_object_unlock(object);
5064
5065 if (cntrl_flags & UPL_BLOCK_ACCESS) {
5066
5067
5068
5069
5070
5071
5072 vm_object_pmap_protect(object, offset, (vm_object_size_t)size,
5073 PMAP_NULL, 0, VM_PROT_NONE);
5074 }
5075
5076 return KERN_SUCCESS;
5077}
5078
5079kern_return_t
5080upl_transpose(
5081 upl_t upl1,
5082 upl_t upl2)
5083{
5084 kern_return_t retval;
5085 boolean_t upls_locked;
5086 vm_object_t object1, object2;
5087
5088 if (upl1 == UPL_NULL || upl2 == UPL_NULL || upl1 == upl2) {
5089 return KERN_INVALID_ARGUMENT;
5090 }
5091
5092 upls_locked = FALSE;
5093
5094
5095
5096
5097
5098 if (upl1 < upl2) {
5099 upl_lock(upl1);
5100 upl_lock(upl2);
5101 } else {
5102 upl_lock(upl2);
5103 upl_lock(upl1);
5104 }
5105 upls_locked = TRUE;
5106
5107 object1 = upl1->map_object;
5108 object2 = upl2->map_object;
5109
5110 if (upl1->offset != 0 || upl2->offset != 0 ||
5111 upl1->size != upl2->size) {
5112
5113
5114
5115
5116
5117
5118 retval = KERN_INVALID_VALUE;
5119 goto done;
5120 }
5121
5122
5123
5124
5125 retval = vm_object_transpose(object1, object2,
5126 (vm_object_size_t) upl1->size);
5127
5128 if (retval == KERN_SUCCESS) {
5129
5130
5131
5132
5133 upl1->map_object = object2;
5134 upl2->map_object = object1;
5135 }
5136
5137done:
5138
5139
5140
5141 if (upls_locked) {
5142 upl_unlock(upl1);
5143 upl_unlock(upl2);
5144 upls_locked = FALSE;
5145 }
5146
5147 return retval;
5148}
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193decl_simple_lock_data(,vm_paging_lock)
5194#define VM_PAGING_NUM_PAGES 64
5195vm_map_offset_t vm_paging_base_address = 0;
5196boolean_t vm_paging_page_inuse[VM_PAGING_NUM_PAGES] = { FALSE, };
5197int vm_paging_max_index = 0;
5198unsigned long vm_paging_no_kernel_page = 0;
5199unsigned long vm_paging_objects_mapped = 0;
5200unsigned long vm_paging_pages_mapped = 0;
5201unsigned long vm_paging_objects_mapped_slow = 0;
5202unsigned long vm_paging_pages_mapped_slow = 0;
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214kern_return_t
5215vm_paging_map_object(
5216 vm_map_offset_t *address,
5217 vm_page_t page,
5218 vm_object_t object,
5219 vm_object_offset_t offset,
5220 vm_map_size_t *size)
5221{
5222 kern_return_t kr;
5223 vm_map_offset_t page_map_offset;
5224 vm_map_size_t map_size;
5225 vm_object_offset_t object_offset;
5226#ifdef __ppc__
5227 int i;
5228 vm_map_entry_t map_entry;
5229#endif
5230
5231
5232#ifdef __ppc__
5233 if (page != VM_PAGE_NULL && *size == PAGE_SIZE) {
5234
5235
5236
5237
5238
5239
5240 vm_object_unlock(object);
5241 simple_lock(&vm_paging_lock);
5242
5243 if (vm_paging_base_address == 0) {
5244
5245
5246
5247
5248 simple_unlock(&vm_paging_lock);
5249 page_map_offset = 0;
5250 kr = vm_map_find_space(kernel_map,
5251 &page_map_offset,
5252 VM_PAGING_NUM_PAGES * PAGE_SIZE,
5253 0,
5254 &map_entry);
5255 if (kr != KERN_SUCCESS) {
5256 panic("vm_paging_map_object: "
5257 "kernel_map full\n");
5258 }
5259 map_entry->object.vm_object = kernel_object;
5260 map_entry->offset =
5261 page_map_offset - VM_MIN_KERNEL_ADDRESS;
5262 vm_object_reference(kernel_object);
5263 vm_map_unlock(kernel_map);
5264
5265 simple_lock(&vm_paging_lock);
5266 if (vm_paging_base_address != 0) {
5267
5268 simple_unlock(&vm_paging_lock);
5269 kr = vm_map_remove(kernel_map,
5270 page_map_offset,
5271 page_map_offset +
5272 (VM_PAGING_NUM_PAGES
5273 * PAGE_SIZE),
5274 VM_MAP_NO_FLAGS);
5275 assert(kr == KERN_SUCCESS);
5276 simple_lock(&vm_paging_lock);
5277 } else {
5278 vm_paging_base_address = page_map_offset;
5279 }
5280 }
5281
5282
5283
5284
5285
5286 page_map_offset = 0;
5287 for (i = 0; i < VM_PAGING_NUM_PAGES; i++) {
5288 if (vm_paging_page_inuse[i] == FALSE) {
5289 page_map_offset = vm_paging_base_address +
5290 (i * PAGE_SIZE);
5291 break;
5292 }
5293 }
5294
5295 if (page_map_offset != 0) {
5296
5297
5298
5299
5300 if (i > vm_paging_max_index) {
5301 vm_paging_max_index = i;
5302 }
5303 vm_paging_page_inuse[i] = TRUE;
5304 simple_unlock(&vm_paging_lock);
5305 pmap_map_block(kernel_pmap,
5306 page_map_offset,
5307 page->phys_page,
5308 1,
5309 VM_PROT_DEFAULT,
5310 ((int) page->object->wimg_bits &
5311 VM_WIMG_MASK),
5312 0);
5313 vm_paging_objects_mapped++;
5314 vm_paging_pages_mapped++;
5315 *address = page_map_offset;
5316 vm_object_lock(object);
5317
5318
5319 return KERN_SUCCESS;
5320 }
5321
5322
5323
5324
5325
5326
5327 vm_paging_no_kernel_page++;
5328 simple_unlock(&vm_paging_lock);
5329 vm_object_lock(object);
5330 }
5331#endif
5332
5333 object_offset = vm_object_trunc_page(offset);
5334 map_size = vm_map_round_page(*size);
5335
5336
5337
5338
5339
5340
5341
5342 if (object_offset >= object->size) {
5343 map_size = 0;
5344 } else if (map_size > object->size - offset) {
5345 map_size = object->size - offset;
5346 }
5347
5348 vm_object_reference_locked(object);
5349 vm_object_unlock(object);
5350
5351 kr = vm_map_enter(kernel_map,
5352 address,
5353 map_size,
5354 0,
5355 VM_FLAGS_ANYWHERE,
5356 object,
5357 object_offset,
5358 FALSE,
5359 VM_PROT_DEFAULT,
5360 VM_PROT_ALL,
5361 VM_INHERIT_NONE);
5362 if (kr != KERN_SUCCESS) {
5363 *address = 0;
5364 *size = 0;
5365 vm_object_deallocate(object);
5366 return kr;
5367 }
5368
5369 *size = map_size;
5370
5371
5372
5373
5374 vm_object_lock(object);
5375 for (page_map_offset = 0;
5376 map_size != 0;
5377 map_size -= PAGE_SIZE_64, page_map_offset += PAGE_SIZE_64) {
5378 unsigned int cache_attr;
5379
5380 page = vm_page_lookup(object, offset + page_map_offset);
5381 if (page == VM_PAGE_NULL) {
5382 panic("vm_paging_map_object: no page !?");
5383 }
5384 if (page->no_isync == TRUE) {
5385 pmap_sync_page_data_phys(page->phys_page);
5386 }
5387 cache_attr = ((unsigned int) object->wimg_bits) & VM_WIMG_MASK;
5388
5389 PMAP_ENTER(kernel_pmap,
5390 *address + page_map_offset,
5391 page,
5392 VM_PROT_DEFAULT,
5393 cache_attr,
5394 FALSE);
5395 }
5396
5397 vm_paging_objects_mapped_slow++;
5398 vm_paging_pages_mapped_slow += map_size / PAGE_SIZE_64;
5399
5400 return KERN_SUCCESS;
5401}
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412void
5413vm_paging_unmap_object(
5414 vm_object_t object,
5415 vm_map_offset_t start,
5416 vm_map_offset_t end)
5417{
5418 kern_return_t kr;
5419#ifdef __ppc__
5420 int i;
5421#endif
5422
5423 if ((vm_paging_base_address != 0) &&
5424 ((start < vm_paging_base_address) ||
5425 (end > (vm_paging_base_address
5426 + (VM_PAGING_NUM_PAGES * PAGE_SIZE))))) {
5427
5428
5429
5430
5431
5432 if (object != VM_OBJECT_NULL) {
5433 vm_object_unlock(object);
5434 }
5435 kr = vm_map_remove(kernel_map, start, end, VM_MAP_NO_FLAGS);
5436 if (object != VM_OBJECT_NULL) {
5437 vm_object_lock(object);
5438 }
5439 assert(kr == KERN_SUCCESS);
5440 } else {
5441
5442
5443
5444
5445
5446#ifdef __ppc__
5447 assert(end - start == PAGE_SIZE);
5448 i = (start - vm_paging_base_address) >> PAGE_SHIFT;
5449
5450
5451 mapping_remove(kernel_pmap, start);
5452
5453 simple_lock(&vm_paging_lock);
5454 vm_paging_page_inuse[i] = FALSE;
5455 simple_unlock(&vm_paging_lock);
5456#endif
5457 }
5458}
5459
5460
5461
5462
5463
5464
5465
5466#define SWAP_CRYPT_AES_KEY_SIZE 128
5467boolean_t swap_crypt_ctx_initialized = FALSE;
5468aes_32t swap_crypt_key[8];
5469aes_ctx swap_crypt_ctx;
5470const unsigned char swap_crypt_null_iv[AES_BLOCK_SIZE] = {0xa, };
5471
5472#if DEBUG
5473boolean_t swap_crypt_ctx_tested = FALSE;
5474unsigned char swap_crypt_test_page_ref[4096] __attribute__((aligned(4096)));
5475unsigned char swap_crypt_test_page_encrypt[4096] __attribute__((aligned(4096)));
5476unsigned char swap_crypt_test_page_decrypt[4096] __attribute__((aligned(4096)));
5477#endif
5478
5479extern u_long random(void);
5480
5481
5482
5483
5484void swap_crypt_ctx_initialize(void);
5485void
5486swap_crypt_ctx_initialize(void)
5487{
5488 unsigned int i;
5489
5490
5491
5492
5493
5494
5495
5496 if (swap_crypt_ctx_initialized == FALSE) {
5497 for (i = 0;
5498 i < (sizeof (swap_crypt_key) /
5499 sizeof (swap_crypt_key[0]));
5500 i++) {
5501 swap_crypt_key[i] = random();
5502 }
5503 aes_encrypt_key((const unsigned char *) swap_crypt_key,
5504 SWAP_CRYPT_AES_KEY_SIZE,
5505 &swap_crypt_ctx.encrypt);
5506 aes_decrypt_key((const unsigned char *) swap_crypt_key,
5507 SWAP_CRYPT_AES_KEY_SIZE,
5508 &swap_crypt_ctx.decrypt);
5509 swap_crypt_ctx_initialized = TRUE;
5510 }
5511
5512#if DEBUG
5513
5514
5515
5516 if (swap_crypt_ctx_tested == FALSE) {
5517
5518 for (i = 0; i < 4096; i++) {
5519 swap_crypt_test_page_ref[i] = (char) i;
5520 }
5521
5522 aes_encrypt_cbc(swap_crypt_test_page_ref,
5523 swap_crypt_null_iv,
5524 PAGE_SIZE / AES_BLOCK_SIZE,
5525 swap_crypt_test_page_encrypt,
5526 &swap_crypt_ctx.encrypt);
5527
5528 aes_decrypt_cbc(swap_crypt_test_page_encrypt,
5529 swap_crypt_null_iv,
5530 PAGE_SIZE / AES_BLOCK_SIZE,
5531 swap_crypt_test_page_decrypt,
5532 &swap_crypt_ctx.decrypt);
5533
5534 for (i = 0; i < 4096; i ++) {
5535 if (swap_crypt_test_page_decrypt[i] !=
5536 swap_crypt_test_page_ref[i]) {
5537 panic("encryption test failed");
5538 }
5539 }
5540
5541
5542 aes_encrypt_cbc(swap_crypt_test_page_decrypt,
5543 swap_crypt_null_iv,
5544 PAGE_SIZE / AES_BLOCK_SIZE,
5545 swap_crypt_test_page_decrypt,
5546 &swap_crypt_ctx.encrypt);
5547
5548 aes_decrypt_cbc(swap_crypt_test_page_decrypt,
5549 swap_crypt_null_iv,
5550 PAGE_SIZE / AES_BLOCK_SIZE,
5551 swap_crypt_test_page_decrypt,
5552 &swap_crypt_ctx.decrypt);
5553 for (i = 0; i < 4096; i ++) {
5554 if (swap_crypt_test_page_decrypt[i] !=
5555 swap_crypt_test_page_ref[i]) {
5556 panic("in place encryption test failed");
5557 }
5558 }
5559
5560 swap_crypt_ctx_tested = TRUE;
5561 }
5562#endif
5563}
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578void
5579vm_page_encrypt(
5580 vm_page_t page,
5581 vm_map_offset_t kernel_mapping_offset)
5582{
5583 int clear_refmod = 0;
5584 kern_return_t kr;
5585 boolean_t page_was_referenced;
5586 boolean_t page_was_modified;
5587 vm_map_size_t kernel_mapping_size;
5588 vm_offset_t kernel_vaddr;
5589 union {
5590 unsigned char aes_iv[AES_BLOCK_SIZE];
5591 struct {
5592 memory_object_t pager_object;
5593 vm_object_offset_t paging_offset;
5594 } vm;
5595 } encrypt_iv;
5596
5597 if (! vm_pages_encrypted) {
5598 vm_pages_encrypted = TRUE;
5599 }
5600
5601 assert(page->busy);
5602 assert(page->dirty || page->precious);
5603
5604 if (page->encrypted) {
5605
5606
5607
5608 vm_page_encrypt_already_encrypted_counter++;
5609 return;
5610 }
5611 ASSERT_PAGE_DECRYPTED(page);
5612
5613
5614
5615
5616
5617
5618
5619 page_was_referenced =
5620 (page->reference || pmap_is_referenced(page->phys_page));
5621 page_was_modified =
5622 (page->dirty || pmap_is_modified(page->phys_page));
5623
5624 if (kernel_mapping_offset == 0) {
5625
5626
5627
5628
5629
5630 kernel_mapping_size = PAGE_SIZE;
5631 kr = vm_paging_map_object(&kernel_mapping_offset,
5632 page,
5633 page->object,
5634 page->offset,
5635 &kernel_mapping_size);
5636 if (kr != KERN_SUCCESS) {
5637 panic("vm_page_encrypt: "
5638 "could not map page in kernel: 0x%x\n",
5639 kr);
5640 }
5641 } else {
5642 kernel_mapping_size = 0;
5643 }
5644 kernel_vaddr = CAST_DOWN(vm_offset_t, kernel_mapping_offset);
5645
5646 if (swap_crypt_ctx_initialized == FALSE) {
5647 swap_crypt_ctx_initialize();
5648 }
5649 assert(swap_crypt_ctx_initialized);
5650
5651
5652
5653
5654
5655
5656
5657
5658 bzero(&encrypt_iv.aes_iv[0], sizeof (encrypt_iv.aes_iv));
5659 encrypt_iv.vm.pager_object = page->object->pager;
5660 encrypt_iv.vm.paging_offset =
5661 page->object->paging_offset + page->offset;
5662
5663 vm_object_unlock(page->object);
5664
5665
5666 aes_encrypt_cbc((const unsigned char *) &encrypt_iv.aes_iv[0],
5667 swap_crypt_null_iv,
5668 1,
5669 &encrypt_iv.aes_iv[0],
5670 &swap_crypt_ctx.encrypt);
5671
5672
5673
5674
5675 aes_encrypt_cbc((const unsigned char *) kernel_vaddr,
5676 &