xref: /xnu-8020.101.4/tests/vm_phys_footprint.c (revision e7776783b89a353188416a9a346c6cdb4928faad)
1*e7776783SApple OSS Distributions #include <darwintest.h>
2*e7776783SApple OSS Distributions #include <darwintest_utils.h>
3*e7776783SApple OSS Distributions 
4*e7776783SApple OSS Distributions #include <mach/mach_error.h>
5*e7776783SApple OSS Distributions #include <mach/mach_init.h>
6*e7776783SApple OSS Distributions #include <mach/memory_entry.h>
7*e7776783SApple OSS Distributions #include <mach/mach_port.h>
8*e7776783SApple OSS Distributions #include <mach/mach_vm.h>
9*e7776783SApple OSS Distributions #include <mach/task.h>
10*e7776783SApple OSS Distributions #include <mach/task_info.h>
11*e7776783SApple OSS Distributions #include <mach/vm_map.h>
12*e7776783SApple OSS Distributions 
13*e7776783SApple OSS Distributions #include <sys/mman.h>
14*e7776783SApple OSS Distributions #include <sys/types.h>
15*e7776783SApple OSS Distributions #include <sys/sysctl.h>
16*e7776783SApple OSS Distributions 
17*e7776783SApple OSS Distributions #include <TargetConditionals.h>
18*e7776783SApple OSS Distributions 
19*e7776783SApple OSS Distributions #include <Kernel/kern/ledger.h>
20*e7776783SApple OSS Distributions extern int ledger(int cmd, caddr_t arg1, caddr_t arg2, caddr_t arg3);
21*e7776783SApple OSS Distributions 
22*e7776783SApple OSS Distributions boolean_t legacy_footprint;
23*e7776783SApple OSS Distributions 
24*e7776783SApple OSS Distributions #if LEGACY_FOOTPRINT_ENTITLED && defined(__arm64__)
25*e7776783SApple OSS Distributions #define TEST_VM_NAMESPACE "xnu.vm_legacy"
26*e7776783SApple OSS Distributions #else /* ENTITLED && __arm64__ */
27*e7776783SApple OSS Distributions #define TEST_VM_NAMESPACE "xnu.vm"
28*e7776783SApple OSS Distributions #endif /* ENTITLED && __arm64__ */
29*e7776783SApple OSS Distributions 
30*e7776783SApple OSS Distributions T_GLOBAL_META(
31*e7776783SApple OSS Distributions 	T_META_NAMESPACE(TEST_VM_NAMESPACE),
32*e7776783SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
33*e7776783SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"),
34*e7776783SApple OSS Distributions 	T_META_RUN_CONCURRENTLY(true));
35*e7776783SApple OSS Distributions 
36*e7776783SApple OSS Distributions #define MEM_SIZE (100 * 1024 * 1024) /* 100 MB */
37*e7776783SApple OSS Distributions 
38*e7776783SApple OSS Distributions static int64_t ledger_count = -1;
39*e7776783SApple OSS Distributions static int footprint_index = -1;
40*e7776783SApple OSS Distributions static int pagetable_index = -1;
41*e7776783SApple OSS Distributions static struct ledger_entry_info *lei = NULL;
42*e7776783SApple OSS Distributions 
43*e7776783SApple OSS Distributions static void
ledger_init(void)44*e7776783SApple OSS Distributions ledger_init(void)
45*e7776783SApple OSS Distributions {
46*e7776783SApple OSS Distributions 	static int                      ledger_inited = 0;
47*e7776783SApple OSS Distributions 	struct ledger_info              li;
48*e7776783SApple OSS Distributions 	struct ledger_template_info     *templateInfo;
49*e7776783SApple OSS Distributions 	int64_t                         templateCnt;
50*e7776783SApple OSS Distributions 	int                             i;
51*e7776783SApple OSS Distributions 	int                             legacy_footprint_entitlement_mode;
52*e7776783SApple OSS Distributions 	size_t                          oldlen;
53*e7776783SApple OSS Distributions 
54*e7776783SApple OSS Distributions 	if (ledger_inited) {
55*e7776783SApple OSS Distributions 		return;
56*e7776783SApple OSS Distributions 	}
57*e7776783SApple OSS Distributions 	ledger_inited = 1;
58*e7776783SApple OSS Distributions 
59*e7776783SApple OSS Distributions 	T_SETUPBEGIN;
60*e7776783SApple OSS Distributions 
61*e7776783SApple OSS Distributions 	legacy_footprint = FALSE;
62*e7776783SApple OSS Distributions #if LEGACY_FOOTPRINT_ENTITLED
63*e7776783SApple OSS Distributions 	int ret;
64*e7776783SApple OSS Distributions 
65*e7776783SApple OSS Distributions 	T_QUIET;
66*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
67*e7776783SApple OSS Distributions 	oldlen = sizeof(legacy_footprint_entitlement_mode);
68*e7776783SApple OSS Distributions 	ret = sysctlbyname("kern.legacy_footprint_entitlement_mode",
69*e7776783SApple OSS Distributions 	    &legacy_footprint_entitlement_mode,
70*e7776783SApple OSS Distributions 	    &oldlen,
71*e7776783SApple OSS Distributions 	    NULL,
72*e7776783SApple OSS Distributions 	    0);
73*e7776783SApple OSS Distributions 	if (ret == 0 && legacy_footprint_entitlement_mode == 2) {
74*e7776783SApple OSS Distributions 		legacy_footprint = TRUE;
75*e7776783SApple OSS Distributions 	}
76*e7776783SApple OSS Distributions #endif /* LEGACY_FOOTPRINT_ENTITLED */
77*e7776783SApple OSS Distributions 
78*e7776783SApple OSS Distributions 	T_QUIET;
79*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
80*e7776783SApple OSS Distributions 	T_ASSERT_EQ(ledger(LEDGER_INFO,
81*e7776783SApple OSS Distributions 	    (caddr_t)(uintptr_t)getpid(),
82*e7776783SApple OSS Distributions 	    (caddr_t)&li,
83*e7776783SApple OSS Distributions 	    NULL),
84*e7776783SApple OSS Distributions 	    0,
85*e7776783SApple OSS Distributions 	    "ledger(LEDGER_INFO)");
86*e7776783SApple OSS Distributions 
87*e7776783SApple OSS Distributions 	templateCnt = li.li_entries;
88*e7776783SApple OSS Distributions 	templateInfo = malloc((size_t)li.li_entries * sizeof(struct ledger_template_info));
89*e7776783SApple OSS Distributions 	T_QUIET;
90*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
91*e7776783SApple OSS Distributions 	T_ASSERT_NE(templateInfo, NULL, "malloc()");
92*e7776783SApple OSS Distributions 
93*e7776783SApple OSS Distributions 	ledger_count = li.li_entries;
94*e7776783SApple OSS Distributions 	footprint_index = -1;
95*e7776783SApple OSS Distributions 	pagetable_index = -1;
96*e7776783SApple OSS Distributions 	T_QUIET;
97*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
98*e7776783SApple OSS Distributions 	T_ASSERT_GE(ledger(LEDGER_TEMPLATE_INFO,
99*e7776783SApple OSS Distributions 	    (caddr_t)templateInfo,
100*e7776783SApple OSS Distributions 	    (caddr_t)&templateCnt,
101*e7776783SApple OSS Distributions 	    NULL),
102*e7776783SApple OSS Distributions 	    0,
103*e7776783SApple OSS Distributions 	    "ledger(LEDGER_TEMPLATE_INFO)");
104*e7776783SApple OSS Distributions 	for (i = 0; i < templateCnt; i++) {
105*e7776783SApple OSS Distributions 		if (!strncmp(templateInfo[i].lti_name,
106*e7776783SApple OSS Distributions 		    "phys_footprint",
107*e7776783SApple OSS Distributions 		    strlen("phys_footprint"))) {
108*e7776783SApple OSS Distributions 			footprint_index = i;
109*e7776783SApple OSS Distributions 		} else if (!strncmp(templateInfo[i].lti_name,
110*e7776783SApple OSS Distributions 		    "page_table",
111*e7776783SApple OSS Distributions 		    strlen("page_table"))) {
112*e7776783SApple OSS Distributions 			pagetable_index = i;
113*e7776783SApple OSS Distributions 		}
114*e7776783SApple OSS Distributions 	}
115*e7776783SApple OSS Distributions 	free(templateInfo);
116*e7776783SApple OSS Distributions 
117*e7776783SApple OSS Distributions 	lei = (struct ledger_entry_info *)
118*e7776783SApple OSS Distributions 	    malloc((size_t)ledger_count * sizeof(*lei));
119*e7776783SApple OSS Distributions 	T_QUIET;
120*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
121*e7776783SApple OSS Distributions 	T_ASSERT_NE(lei, NULL, "malloc(ledger_entry_info)");
122*e7776783SApple OSS Distributions 
123*e7776783SApple OSS Distributions 	T_QUIET;
124*e7776783SApple OSS Distributions 	T_ASSERT_NE(footprint_index, -1, "no footprint_index");
125*e7776783SApple OSS Distributions 	T_QUIET;
126*e7776783SApple OSS Distributions 	T_ASSERT_NE(pagetable_index, -1, "no pagetable_index");
127*e7776783SApple OSS Distributions 
128*e7776783SApple OSS Distributions 	T_SETUPEND;
129*e7776783SApple OSS Distributions }
130*e7776783SApple OSS Distributions 
131*e7776783SApple OSS Distributions static void
get_ledger_info(uint64_t * phys_footprint,uint64_t * page_table)132*e7776783SApple OSS Distributions get_ledger_info(
133*e7776783SApple OSS Distributions 	uint64_t        *phys_footprint,
134*e7776783SApple OSS Distributions 	uint64_t        *page_table)
135*e7776783SApple OSS Distributions {
136*e7776783SApple OSS Distributions 	int64_t count;
137*e7776783SApple OSS Distributions 
138*e7776783SApple OSS Distributions 	count = ledger_count;
139*e7776783SApple OSS Distributions 	T_QUIET;
140*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
141*e7776783SApple OSS Distributions 	T_ASSERT_GE(ledger(LEDGER_ENTRY_INFO,
142*e7776783SApple OSS Distributions 	    (caddr_t)(uintptr_t)getpid(),
143*e7776783SApple OSS Distributions 	    (caddr_t)lei,
144*e7776783SApple OSS Distributions 	    (caddr_t)&count),
145*e7776783SApple OSS Distributions 	    0,
146*e7776783SApple OSS Distributions 	    "ledger(LEDGER_ENTRY_INFO)");
147*e7776783SApple OSS Distributions 	T_QUIET;
148*e7776783SApple OSS Distributions 	T_ASSERT_GT(count, (int64_t)footprint_index, "no entry for footprint");
149*e7776783SApple OSS Distributions 	T_QUIET;
150*e7776783SApple OSS Distributions 	T_ASSERT_GT(count, (int64_t)pagetable_index, "no entry for pagetable");
151*e7776783SApple OSS Distributions 	if (phys_footprint) {
152*e7776783SApple OSS Distributions 		*phys_footprint = (uint64_t)(lei[footprint_index].lei_balance);
153*e7776783SApple OSS Distributions 	}
154*e7776783SApple OSS Distributions 	if (page_table) {
155*e7776783SApple OSS Distributions 		*page_table = (uint64_t)(lei[pagetable_index].lei_balance);
156*e7776783SApple OSS Distributions 	}
157*e7776783SApple OSS Distributions }
158*e7776783SApple OSS Distributions 
159*e7776783SApple OSS Distributions static mach_vm_address_t
pre_warm(mach_vm_size_t vm_size)160*e7776783SApple OSS Distributions pre_warm(
161*e7776783SApple OSS Distributions 	mach_vm_size_t  vm_size)
162*e7776783SApple OSS Distributions {
163*e7776783SApple OSS Distributions 	kern_return_t           kr;
164*e7776783SApple OSS Distributions 	mach_vm_address_t       vm_addr;
165*e7776783SApple OSS Distributions 	unsigned char           BigBufOnStack[100 * 1024];
166*e7776783SApple OSS Distributions 	uint64_t                footprint, page_table;
167*e7776783SApple OSS Distributions 
168*e7776783SApple OSS Distributions 	/* make sure ledgers are ready to be queried */
169*e7776783SApple OSS Distributions 	ledger_init();
170*e7776783SApple OSS Distributions 
171*e7776783SApple OSS Distributions 	T_SETUPBEGIN;
172*e7776783SApple OSS Distributions 
173*e7776783SApple OSS Distributions 	/*
174*e7776783SApple OSS Distributions 	 * Touch a few pages ahead on the stack, to make
175*e7776783SApple OSS Distributions 	 * sure we don't see a footprint increase due to
176*e7776783SApple OSS Distributions 	 * an extra stack page later.
177*e7776783SApple OSS Distributions 	 */
178*e7776783SApple OSS Distributions 	memset(BigBufOnStack, 0xb, sizeof(BigBufOnStack));
179*e7776783SApple OSS Distributions 	T_QUIET;
180*e7776783SApple OSS Distributions 	T_EXPECT_EQ(BigBufOnStack[0], 0xb,
181*e7776783SApple OSS Distributions 	    "BigBufOnStack[0] == 0x%x",
182*e7776783SApple OSS Distributions 	    BigBufOnStack[0]);
183*e7776783SApple OSS Distributions 	T_QUIET;
184*e7776783SApple OSS Distributions 	T_EXPECT_EQ(BigBufOnStack[sizeof(BigBufOnStack) - 1], 0xb,
185*e7776783SApple OSS Distributions 	    "BigBufOnStack[%lu] == 0x%x",
186*e7776783SApple OSS Distributions 	    sizeof(BigBufOnStack),
187*e7776783SApple OSS Distributions 	    BigBufOnStack[sizeof(BigBufOnStack) - 1]);
188*e7776783SApple OSS Distributions 
189*e7776783SApple OSS Distributions 	/*
190*e7776783SApple OSS Distributions 	 * Pre-allocate, touch and then release the same amount
191*e7776783SApple OSS Distributions 	 * of memory we'll be allocating later during the test,
192*e7776783SApple OSS Distributions 	 * to account for any memory overhead (page tables, global
193*e7776783SApple OSS Distributions 	 * variables, ...).
194*e7776783SApple OSS Distributions 	 */
195*e7776783SApple OSS Distributions 	vm_addr = 0;
196*e7776783SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(),
197*e7776783SApple OSS Distributions 	    &vm_addr,
198*e7776783SApple OSS Distributions 	    vm_size,
199*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE);
200*e7776783SApple OSS Distributions 	T_QUIET;
201*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%lld) error 0x%x (%s)",
202*e7776783SApple OSS Distributions 	    vm_size, kr, mach_error_string(kr));
203*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'p', (size_t)vm_size);
204*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(),
205*e7776783SApple OSS Distributions 	    vm_addr,
206*e7776783SApple OSS Distributions 	    vm_size);
207*e7776783SApple OSS Distributions 	T_QUIET;
208*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
209*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
210*e7776783SApple OSS Distributions 
211*e7776783SApple OSS Distributions 	/*
212*e7776783SApple OSS Distributions 	 * Exercise the ledger code to make sure it's ready to run
213*e7776783SApple OSS Distributions 	 * without any extra memory overhead later.
214*e7776783SApple OSS Distributions 	 */
215*e7776783SApple OSS Distributions 	get_ledger_info(&footprint, &page_table);
216*e7776783SApple OSS Distributions 
217*e7776783SApple OSS Distributions 	T_SETUPEND;
218*e7776783SApple OSS Distributions 
219*e7776783SApple OSS Distributions 	/*
220*e7776783SApple OSS Distributions 	 * Return the start of the virtual range we pre-warmed, so that the
221*e7776783SApple OSS Distributions 	 * test can check that it's using the same range.
222*e7776783SApple OSS Distributions 	 */
223*e7776783SApple OSS Distributions 	return vm_addr;
224*e7776783SApple OSS Distributions }
225*e7776783SApple OSS Distributions 
226*e7776783SApple OSS Distributions T_DECL(phys_footprint_anonymous,
227*e7776783SApple OSS Distributions     "phys_footprint for anonymous memory",
228*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
229*e7776783SApple OSS Distributions {
230*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
231*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
232*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
233*e7776783SApple OSS Distributions 	kern_return_t           kr;
234*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr, vm_addr;
235*e7776783SApple OSS Distributions 	mach_vm_size_t          vm_size, dirty_size;
236*e7776783SApple OSS Distributions 
237*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
238*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(MEM_SIZE);
239*e7776783SApple OSS Distributions 
240*e7776783SApple OSS Distributions 	/* allocating virtual memory... */
241*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
242*e7776783SApple OSS Distributions 	vm_addr = 0;
243*e7776783SApple OSS Distributions 	vm_size = MEM_SIZE;
244*e7776783SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &vm_addr, vm_size,
245*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE);
246*e7776783SApple OSS Distributions 	T_QUIET;
247*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate() error 0x%x (%s)",
248*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
249*e7776783SApple OSS Distributions 	T_QUIET;
250*e7776783SApple OSS Distributions 	T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
251*e7776783SApple OSS Distributions 	/* ... should not change footprint */
252*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
253*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
254*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
255*e7776783SApple OSS Distributions 	T_LOG("virtual allocation does not change phys_footprint");
256*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
257*e7776783SApple OSS Distributions 	    "virtual allocation of %lld bytes: "
258*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
259*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
260*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
261*e7776783SApple OSS Distributions 
262*e7776783SApple OSS Distributions 	/* touching memory... */
263*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
264*e7776783SApple OSS Distributions 	dirty_size = vm_size / 2;
265*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
266*e7776783SApple OSS Distributions 	/* ... should increase footprint */
267*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
268*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
269*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
270*e7776783SApple OSS Distributions 	T_LOG("modifying anonymous memory increases phys_footprint");
271*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
272*e7776783SApple OSS Distributions 	    "touched %lld bytes: "
273*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
274*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
275*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
276*e7776783SApple OSS Distributions 
277*e7776783SApple OSS Distributions 	/* deallocating memory... */
278*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
279*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
280*e7776783SApple OSS Distributions 	T_QUIET;
281*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
282*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
283*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
284*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
285*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
286*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
287*e7776783SApple OSS Distributions 	T_LOG("deallocating dirty anonymous memory decreases phys_footprint");
288*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
289*e7776783SApple OSS Distributions 	    "deallocated %lld dirty bytes: "
290*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
291*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
292*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
293*e7776783SApple OSS Distributions }
294*e7776783SApple OSS Distributions 
295*e7776783SApple OSS Distributions #define TEMP_FILE_TEMPLATE "/tmp/phys_footprint_data.XXXXXXXX"
296*e7776783SApple OSS Distributions #define TEMP_FILE_SIZE  (1 * 1024 * 1024)
297*e7776783SApple OSS Distributions 
298*e7776783SApple OSS Distributions T_DECL(phys_footprint_file,
299*e7776783SApple OSS Distributions     "phys_footprint for mapped file",
300*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
301*e7776783SApple OSS Distributions {
302*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
303*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
304*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
305*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr;
306*e7776783SApple OSS Distributions 	int                     fd;
307*e7776783SApple OSS Distributions 	char                    *map_addr;
308*e7776783SApple OSS Distributions 	size_t                  map_size, dirty_size;
309*e7776783SApple OSS Distributions 	ssize_t                 nbytes;
310*e7776783SApple OSS Distributions 	char                    tmp_file_name[PATH_MAX] = TEMP_FILE_TEMPLATE;
311*e7776783SApple OSS Distributions 	char                    *buf;
312*e7776783SApple OSS Distributions 	size_t                  buf_size;
313*e7776783SApple OSS Distributions 
314*e7776783SApple OSS Distributions 	T_SETUPBEGIN;
315*e7776783SApple OSS Distributions 	buf_size = TEMP_FILE_SIZE;
316*e7776783SApple OSS Distributions 	T_QUIET;
317*e7776783SApple OSS Distributions 	T_ASSERT_NOTNULL(buf = (char *)malloc(buf_size),
318*e7776783SApple OSS Distributions 	    "allocate %zu-byte buffer", buf_size);
319*e7776783SApple OSS Distributions 	memset(buf, 'f', buf_size);
320*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
321*e7776783SApple OSS Distributions 	T_QUIET;
322*e7776783SApple OSS Distributions 	T_ASSERT_NOTNULL(mktemp(tmp_file_name),
323*e7776783SApple OSS Distributions 	    "create temporary file name");
324*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
325*e7776783SApple OSS Distributions 	T_QUIET;
326*e7776783SApple OSS Distributions 	T_ASSERT_GE(fd = open(tmp_file_name, O_CREAT | O_RDWR),
327*e7776783SApple OSS Distributions 	    0,
328*e7776783SApple OSS Distributions 	    "create temp file");
329*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
330*e7776783SApple OSS Distributions 	T_QUIET;
331*e7776783SApple OSS Distributions 	T_ASSERT_EQ(nbytes = write(fd, buf, buf_size),
332*e7776783SApple OSS Distributions 	    (ssize_t)buf_size,
333*e7776783SApple OSS Distributions 	    "write %zu bytes", buf_size);
334*e7776783SApple OSS Distributions 	free(buf);
335*e7776783SApple OSS Distributions 	T_SETUPEND;
336*e7776783SApple OSS Distributions 
337*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
338*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(TEMP_FILE_SIZE);
339*e7776783SApple OSS Distributions 
340*e7776783SApple OSS Distributions 	/* mapping a file does not impact footprint... */
341*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
342*e7776783SApple OSS Distributions 	map_size = TEMP_FILE_SIZE;
343*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
344*e7776783SApple OSS Distributions 	T_QUIET;
345*e7776783SApple OSS Distributions 	T_ASSERT_NOTNULL(map_addr = (char *)mmap(NULL, map_size,
346*e7776783SApple OSS Distributions 	    PROT_READ | PROT_WRITE,
347*e7776783SApple OSS Distributions 	    MAP_FILE | MAP_SHARED, fd, 0),
348*e7776783SApple OSS Distributions 	    "mmap()");
349*e7776783SApple OSS Distributions 	T_QUIET;
350*e7776783SApple OSS Distributions 	T_EXPECT_EQ((mach_vm_address_t)map_addr, pre_vm_addr,
351*e7776783SApple OSS Distributions 	    "pre-warm mishap");
352*e7776783SApple OSS Distributions 	/* ... should not change footprint */
353*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
354*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
355*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
356*e7776783SApple OSS Distributions 	T_LOG("mapping file does not change phys_footprint");
357*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
358*e7776783SApple OSS Distributions 	    "mapping file with %zu bytes: "
359*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
360*e7776783SApple OSS Distributions 	    map_size, footprint_before, footprint_after,
361*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
362*e7776783SApple OSS Distributions 
363*e7776783SApple OSS Distributions 	/* touching file-backed memory... */
364*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
365*e7776783SApple OSS Distributions 	dirty_size = map_size / 2;
366*e7776783SApple OSS Distributions 	memset(map_addr, 'F', dirty_size);
367*e7776783SApple OSS Distributions 	/* ... should not impact footprint */
368*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
369*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
370*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
371*e7776783SApple OSS Distributions 	T_LOG("modifying file-backed memory does not impact phys_footprint");
372*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
373*e7776783SApple OSS Distributions 	    "touched %zu bytes: "
374*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
375*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
376*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
377*e7776783SApple OSS Distributions 
378*e7776783SApple OSS Distributions 	/* deallocating file-backed memory... */
379*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
380*e7776783SApple OSS Distributions 	T_WITH_ERRNO;
381*e7776783SApple OSS Distributions 	T_QUIET;
382*e7776783SApple OSS Distributions 	T_ASSERT_EQ(munmap(map_addr, map_size),
383*e7776783SApple OSS Distributions 	    0,
384*e7776783SApple OSS Distributions 	    "unmap file");
385*e7776783SApple OSS Distributions 	/* ... should not impact footprint */
386*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
387*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
388*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
389*e7776783SApple OSS Distributions 	T_LOG("unmapping file-backed memory does not impact phys_footprint");
390*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
391*e7776783SApple OSS Distributions 	    "unmapped %zu dirty bytes: "
392*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
393*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
394*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
395*e7776783SApple OSS Distributions }
396*e7776783SApple OSS Distributions 
397*e7776783SApple OSS Distributions T_DECL(phys_footprint_purgeable,
398*e7776783SApple OSS Distributions     "phys_footprint for purgeable memory",
399*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
400*e7776783SApple OSS Distributions {
401*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
402*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
403*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
404*e7776783SApple OSS Distributions 	kern_return_t           kr;
405*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr, vm_addr;
406*e7776783SApple OSS Distributions 	mach_vm_size_t          vm_size, dirty_size;
407*e7776783SApple OSS Distributions 	int                     state;
408*e7776783SApple OSS Distributions 
409*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
410*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(MEM_SIZE);
411*e7776783SApple OSS Distributions 
412*e7776783SApple OSS Distributions 	/* allocating purgeable virtual memory... */
413*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
414*e7776783SApple OSS Distributions 	vm_addr = 0;
415*e7776783SApple OSS Distributions 	vm_size = MEM_SIZE;
416*e7776783SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &vm_addr, vm_size,
417*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
418*e7776783SApple OSS Distributions 	T_QUIET;
419*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate() error 0x%x (%s)",
420*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
421*e7776783SApple OSS Distributions 	T_QUIET;
422*e7776783SApple OSS Distributions 	T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
423*e7776783SApple OSS Distributions 	/* ... should not change footprint */
424*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
425*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
426*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
427*e7776783SApple OSS Distributions 	T_LOG("purgeable virtual allocation does not change phys_footprint");
428*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
429*e7776783SApple OSS Distributions 	    "purgeable virtual allocation of %lld bytes: "
430*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
431*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
432*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
433*e7776783SApple OSS Distributions 
434*e7776783SApple OSS Distributions 	/* touching memory... */
435*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
436*e7776783SApple OSS Distributions 	dirty_size = vm_size / 2;
437*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
438*e7776783SApple OSS Distributions 	/* ... should increase footprint */
439*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
440*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
441*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
442*e7776783SApple OSS Distributions 	T_LOG("modifying anonymous memory increases phys_footprint");
443*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
444*e7776783SApple OSS Distributions 	    "touched %lld bytes: "
445*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
446*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
447*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
448*e7776783SApple OSS Distributions 
449*e7776783SApple OSS Distributions 	/* making it volatile... */
450*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
451*e7776783SApple OSS Distributions 	state = VM_PURGABLE_VOLATILE;
452*e7776783SApple OSS Distributions 	T_QUIET;
453*e7776783SApple OSS Distributions 	T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
454*e7776783SApple OSS Distributions 	    vm_addr,
455*e7776783SApple OSS Distributions 	    VM_PURGABLE_SET_STATE,
456*e7776783SApple OSS Distributions 	    &state),
457*e7776783SApple OSS Distributions 	    KERN_SUCCESS,
458*e7776783SApple OSS Distributions 	    "vm_purgable_control(VOLATILE)");
459*e7776783SApple OSS Distributions 	T_QUIET;
460*e7776783SApple OSS Distributions 	T_ASSERT_EQ(state, VM_PURGABLE_NONVOLATILE,
461*e7776783SApple OSS Distributions 	    "memory was non-volatile");
462*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
463*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
464*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
465*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
466*e7776783SApple OSS Distributions 	T_LOG("making volatile decreases phys_footprint");
467*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
468*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
469*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
470*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
471*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
472*e7776783SApple OSS Distributions 
473*e7776783SApple OSS Distributions 	/* making it non-volatile... */
474*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
475*e7776783SApple OSS Distributions 	state = VM_PURGABLE_NONVOLATILE;
476*e7776783SApple OSS Distributions 	T_QUIET;
477*e7776783SApple OSS Distributions 	T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
478*e7776783SApple OSS Distributions 	    vm_addr,
479*e7776783SApple OSS Distributions 	    VM_PURGABLE_SET_STATE,
480*e7776783SApple OSS Distributions 	    &state),
481*e7776783SApple OSS Distributions 	    KERN_SUCCESS,
482*e7776783SApple OSS Distributions 	    "vm_purgable_control(NONVOLATILE)");
483*e7776783SApple OSS Distributions 	T_QUIET;
484*e7776783SApple OSS Distributions 	T_ASSERT_EQ(state, VM_PURGABLE_VOLATILE,
485*e7776783SApple OSS Distributions 	    "memory was volatile");
486*e7776783SApple OSS Distributions 	/* ... should increase footprint */
487*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
488*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
489*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
490*e7776783SApple OSS Distributions 	T_LOG("making non-volatile increases phys_footprint");
491*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
492*e7776783SApple OSS Distributions 	    "made non-volatile %lld dirty bytes: "
493*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
494*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
495*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
496*e7776783SApple OSS Distributions 
497*e7776783SApple OSS Distributions 	/* deallocating memory... */
498*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
499*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
500*e7776783SApple OSS Distributions 	T_QUIET;
501*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
502*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
503*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
504*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
505*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
506*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
507*e7776783SApple OSS Distributions 	T_LOG("deallocating memory decreases phys_footprint");
508*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
509*e7776783SApple OSS Distributions 	    "deallocated %lld dirty bytes: "
510*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
511*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
512*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
513*e7776783SApple OSS Distributions }
514*e7776783SApple OSS Distributions 
515*e7776783SApple OSS Distributions T_DECL(phys_footprint_purgeable_ownership,
516*e7776783SApple OSS Distributions     "phys_footprint for owned purgeable memory",
517*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
518*e7776783SApple OSS Distributions {
519*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
520*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
521*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
522*e7776783SApple OSS Distributions 	kern_return_t           kr;
523*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr, vm_addr;
524*e7776783SApple OSS Distributions 	mach_vm_size_t          vm_size, dirty_size, me_size;
525*e7776783SApple OSS Distributions 	int                     state;
526*e7776783SApple OSS Distributions 	mach_port_t             me_port;
527*e7776783SApple OSS Distributions 
528*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
529*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(MEM_SIZE);
530*e7776783SApple OSS Distributions 
531*e7776783SApple OSS Distributions 	/* allocating purgeable virtual memory... */
532*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
533*e7776783SApple OSS Distributions 	vm_addr = 0;
534*e7776783SApple OSS Distributions 	vm_size = MEM_SIZE;
535*e7776783SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &vm_addr, vm_size,
536*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
537*e7776783SApple OSS Distributions 	T_QUIET;
538*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate() error 0x%x (%s)",
539*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
540*e7776783SApple OSS Distributions 	T_QUIET;
541*e7776783SApple OSS Distributions 	T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
542*e7776783SApple OSS Distributions 	/* ... should not change footprint */
543*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
544*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
545*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
546*e7776783SApple OSS Distributions 	T_LOG("purgeable virtual allocation does not change phys_footprint");
547*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
548*e7776783SApple OSS Distributions 	    "purgeable virtual allocation of %lld bytes: "
549*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
550*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
551*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
552*e7776783SApple OSS Distributions 
553*e7776783SApple OSS Distributions 	/* touching memory... */
554*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
555*e7776783SApple OSS Distributions 	dirty_size = vm_size / 2;
556*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
557*e7776783SApple OSS Distributions 	/* ... should increase footprint */
558*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
559*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
560*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
561*e7776783SApple OSS Distributions 	T_LOG("modifying anonymous memory increases phys_footprint");
562*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
563*e7776783SApple OSS Distributions 	    "touched %lld bytes: "
564*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
565*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
566*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
567*e7776783SApple OSS Distributions 
568*e7776783SApple OSS Distributions 	/* making it volatile... */
569*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
570*e7776783SApple OSS Distributions 	state = VM_PURGABLE_VOLATILE;
571*e7776783SApple OSS Distributions 	T_QUIET;
572*e7776783SApple OSS Distributions 	T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
573*e7776783SApple OSS Distributions 	    vm_addr,
574*e7776783SApple OSS Distributions 	    VM_PURGABLE_SET_STATE,
575*e7776783SApple OSS Distributions 	    &state),
576*e7776783SApple OSS Distributions 	    KERN_SUCCESS,
577*e7776783SApple OSS Distributions 	    "vm_purgable_control(VOLATILE)");
578*e7776783SApple OSS Distributions 	T_QUIET;
579*e7776783SApple OSS Distributions 	T_ASSERT_EQ(state, VM_PURGABLE_NONVOLATILE,
580*e7776783SApple OSS Distributions 	    "memory was non-volatile");
581*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
582*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
583*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
584*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
585*e7776783SApple OSS Distributions 	T_LOG("making volatile decreases phys_footprint");
586*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
587*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
588*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
589*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
590*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
591*e7776783SApple OSS Distributions 
592*e7776783SApple OSS Distributions 	/* making it non-volatile... */
593*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
594*e7776783SApple OSS Distributions 	state = VM_PURGABLE_NONVOLATILE;
595*e7776783SApple OSS Distributions 	T_QUIET;
596*e7776783SApple OSS Distributions 	T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
597*e7776783SApple OSS Distributions 	    vm_addr,
598*e7776783SApple OSS Distributions 	    VM_PURGABLE_SET_STATE,
599*e7776783SApple OSS Distributions 	    &state),
600*e7776783SApple OSS Distributions 	    KERN_SUCCESS,
601*e7776783SApple OSS Distributions 	    "vm_purgable_control(NONVOLATILE)");
602*e7776783SApple OSS Distributions 	T_QUIET;
603*e7776783SApple OSS Distributions 	T_ASSERT_EQ(state, VM_PURGABLE_VOLATILE,
604*e7776783SApple OSS Distributions 	    "memory was volatile");
605*e7776783SApple OSS Distributions 	/* ... should increase footprint */
606*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
607*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
608*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
609*e7776783SApple OSS Distributions 	T_LOG("making non-volatile increases phys_footprint");
610*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
611*e7776783SApple OSS Distributions 	    "made non-volatile %lld dirty bytes: "
612*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
613*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
614*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
615*e7776783SApple OSS Distributions 
616*e7776783SApple OSS Distributions 	/* making a memory entry... */
617*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
618*e7776783SApple OSS Distributions 	me_size = vm_size;
619*e7776783SApple OSS Distributions 	me_port = MACH_PORT_NULL;
620*e7776783SApple OSS Distributions 	kr = mach_make_memory_entry_64(mach_task_self(),
621*e7776783SApple OSS Distributions 	    &me_size,
622*e7776783SApple OSS Distributions 	    vm_addr,
623*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
624*e7776783SApple OSS Distributions 	    &me_port,
625*e7776783SApple OSS Distributions 	    MACH_PORT_NULL);
626*e7776783SApple OSS Distributions 	T_QUIET;
627*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
628*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
629*e7776783SApple OSS Distributions 	T_QUIET;
630*e7776783SApple OSS Distributions 	T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
631*e7776783SApple OSS Distributions 	/* ... should not change footprint */
632*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
633*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
634*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
635*e7776783SApple OSS Distributions 	T_LOG("making a memory entry does not change phys_footprint");
636*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
637*e7776783SApple OSS Distributions 	    "making a memory entry of %lld bytes: "
638*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
639*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
640*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
641*e7776783SApple OSS Distributions 
642*e7776783SApple OSS Distributions 	/* deallocating memory while holding memory entry... */
643*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
644*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
645*e7776783SApple OSS Distributions 	T_QUIET;
646*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
647*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
648*e7776783SApple OSS Distributions 	/* ... should not change footprint */
649*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
650*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
651*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
652*e7776783SApple OSS Distributions 	T_LOG("deallocating owned memory while holding memory entry "
653*e7776783SApple OSS Distributions 	    "does not change phys_footprint");
654*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
655*e7776783SApple OSS Distributions 	    "deallocated %lld dirty bytes: "
656*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
657*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
658*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
659*e7776783SApple OSS Distributions 
660*e7776783SApple OSS Distributions 	/* releasing the memory entry... */
661*e7776783SApple OSS Distributions 	kr = mach_port_deallocate(mach_task_self(), me_port);
662*e7776783SApple OSS Distributions 	T_QUIET;
663*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
664*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
665*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
666*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
667*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
668*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
669*e7776783SApple OSS Distributions 	T_LOG("releasing memory entry decreases phys_footprint");
670*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
671*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
672*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
673*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
674*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
675*e7776783SApple OSS Distributions }
676*e7776783SApple OSS Distributions 
677*e7776783SApple OSS Distributions #ifdef MAP_MEM_LEDGER_TAGGED
678*e7776783SApple OSS Distributions T_DECL(phys_footprint_ledger_purgeable_owned,
679*e7776783SApple OSS Distributions     "phys_footprint for ledger-tagged purgeable memory ownership",
680*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
681*e7776783SApple OSS Distributions {
682*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
683*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
684*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
685*e7776783SApple OSS Distributions 	kern_return_t           kr;
686*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr, vm_addr;
687*e7776783SApple OSS Distributions 	mach_vm_size_t          vm_size, dirty_size, me_size;
688*e7776783SApple OSS Distributions 	int                     state;
689*e7776783SApple OSS Distributions 	mach_port_t             me_port;
690*e7776783SApple OSS Distributions 
691*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
692*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(MEM_SIZE);
693*e7776783SApple OSS Distributions 
694*e7776783SApple OSS Distributions 	/* making a memory entry... */
695*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
696*e7776783SApple OSS Distributions 	vm_size = MEM_SIZE;
697*e7776783SApple OSS Distributions 	me_size = vm_size;
698*e7776783SApple OSS Distributions 	me_port = MACH_PORT_NULL;
699*e7776783SApple OSS Distributions 	kr = mach_make_memory_entry_64(mach_task_self(),
700*e7776783SApple OSS Distributions 	    &me_size,
701*e7776783SApple OSS Distributions 	    0,
702*e7776783SApple OSS Distributions 	    (MAP_MEM_NAMED_CREATE |
703*e7776783SApple OSS Distributions 	    MAP_MEM_LEDGER_TAGGED |
704*e7776783SApple OSS Distributions 	    MAP_MEM_PURGABLE |
705*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE),
706*e7776783SApple OSS Distributions 	    &me_port,
707*e7776783SApple OSS Distributions 	    MACH_PORT_NULL);
708*e7776783SApple OSS Distributions 	T_QUIET;
709*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
710*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
711*e7776783SApple OSS Distributions 	T_QUIET;
712*e7776783SApple OSS Distributions 	T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
713*e7776783SApple OSS Distributions 	/* ... should not change footprint */
714*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
715*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
716*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
717*e7776783SApple OSS Distributions 	T_LOG("making a memory entry does not change phys_footprint");
718*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
719*e7776783SApple OSS Distributions 	    "making a memory entry of %lld bytes: "
720*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
721*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
722*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
723*e7776783SApple OSS Distributions 
724*e7776783SApple OSS Distributions 	/* mapping ledger-tagged virtual memory... */
725*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
726*e7776783SApple OSS Distributions 	vm_addr = 0;
727*e7776783SApple OSS Distributions 	kr = mach_vm_map(mach_task_self(), &vm_addr, vm_size,
728*e7776783SApple OSS Distributions 	    0, /* mask */
729*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE,
730*e7776783SApple OSS Distributions 	    me_port,
731*e7776783SApple OSS Distributions 	    0, /* offset */
732*e7776783SApple OSS Distributions 	    FALSE, /* copy */
733*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
734*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
735*e7776783SApple OSS Distributions 	    VM_INHERIT_DEFAULT);
736*e7776783SApple OSS Distributions 	T_QUIET;
737*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_map() error 0x%x (%s)",
738*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
739*e7776783SApple OSS Distributions 	T_QUIET;
740*e7776783SApple OSS Distributions 	T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
741*e7776783SApple OSS Distributions 	/* ... should not change footprint */
742*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
743*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
744*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
745*e7776783SApple OSS Distributions 	T_LOG("mapping ledger-tagged memory does not change phys_footprint");
746*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
747*e7776783SApple OSS Distributions 	    "ledger-tagged mapping of %lld bytes: "
748*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
749*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
750*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
751*e7776783SApple OSS Distributions 
752*e7776783SApple OSS Distributions 	/* touching memory... */
753*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
754*e7776783SApple OSS Distributions 	dirty_size = vm_size / 2;
755*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
756*e7776783SApple OSS Distributions 	/* ... should increase footprint */
757*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
758*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
759*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
760*e7776783SApple OSS Distributions 	T_LOG("modifying ledger-tagged memory increases phys_footprint");
761*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
762*e7776783SApple OSS Distributions 	    "touched %lld bytes: "
763*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
764*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
765*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
766*e7776783SApple OSS Distributions 
767*e7776783SApple OSS Distributions 	/* making it volatile... */
768*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
769*e7776783SApple OSS Distributions 	state = VM_PURGABLE_VOLATILE;
770*e7776783SApple OSS Distributions 	T_QUIET;
771*e7776783SApple OSS Distributions 	T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
772*e7776783SApple OSS Distributions 	    vm_addr,
773*e7776783SApple OSS Distributions 	    VM_PURGABLE_SET_STATE,
774*e7776783SApple OSS Distributions 	    &state),
775*e7776783SApple OSS Distributions 	    KERN_SUCCESS,
776*e7776783SApple OSS Distributions 	    "vm_purgable_control(VOLATILE)");
777*e7776783SApple OSS Distributions 	T_QUIET;
778*e7776783SApple OSS Distributions 	T_ASSERT_EQ(state, VM_PURGABLE_NONVOLATILE,
779*e7776783SApple OSS Distributions 	    "memory was non-volatile");
780*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
781*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
782*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
783*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
784*e7776783SApple OSS Distributions 	T_LOG("making volatile decreases phys_footprint");
785*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
786*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
787*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
788*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
789*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
790*e7776783SApple OSS Distributions 
791*e7776783SApple OSS Distributions 	/* making it non-volatile... */
792*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
793*e7776783SApple OSS Distributions 	state = VM_PURGABLE_NONVOLATILE;
794*e7776783SApple OSS Distributions 	T_QUIET;
795*e7776783SApple OSS Distributions 	T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
796*e7776783SApple OSS Distributions 	    vm_addr,
797*e7776783SApple OSS Distributions 	    VM_PURGABLE_SET_STATE,
798*e7776783SApple OSS Distributions 	    &state),
799*e7776783SApple OSS Distributions 	    KERN_SUCCESS,
800*e7776783SApple OSS Distributions 	    "vm_purgable_control(NONVOLATILE)");
801*e7776783SApple OSS Distributions 	T_QUIET;
802*e7776783SApple OSS Distributions 	T_ASSERT_EQ(state, VM_PURGABLE_VOLATILE,
803*e7776783SApple OSS Distributions 	    "memory was volatile");
804*e7776783SApple OSS Distributions 	/* ... should increase footprint */
805*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
806*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
807*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
808*e7776783SApple OSS Distributions 	T_LOG("making non-volatile increases phys_footprint");
809*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
810*e7776783SApple OSS Distributions 	    "made non-volatile %lld dirty bytes: "
811*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
812*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
813*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
814*e7776783SApple OSS Distributions 
815*e7776783SApple OSS Distributions 	/* deallocating memory while holding memory entry... */
816*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
817*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
818*e7776783SApple OSS Distributions 	T_QUIET;
819*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
820*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
821*e7776783SApple OSS Distributions 	/* ... should not change footprint */
822*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
823*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
824*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
825*e7776783SApple OSS Distributions 	T_LOG("deallocating owned memory while holding memory entry "
826*e7776783SApple OSS Distributions 	    "does not change phys_footprint");
827*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
828*e7776783SApple OSS Distributions 	    "deallocated %lld dirty bytes: "
829*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
830*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
831*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
832*e7776783SApple OSS Distributions 
833*e7776783SApple OSS Distributions 	/* releasing the memory entry... */
834*e7776783SApple OSS Distributions 	kr = mach_port_deallocate(mach_task_self(), me_port);
835*e7776783SApple OSS Distributions 	T_QUIET;
836*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
837*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
838*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
839*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
840*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
841*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
842*e7776783SApple OSS Distributions 	T_LOG("releasing memory entry decreases phys_footprint");
843*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
844*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
845*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
846*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
847*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
848*e7776783SApple OSS Distributions }
849*e7776783SApple OSS Distributions 
850*e7776783SApple OSS Distributions T_DECL(phys_footprint_ledger_owned,
851*e7776783SApple OSS Distributions     "phys_footprint for ledger-tagged memory ownership",
852*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
853*e7776783SApple OSS Distributions {
854*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
855*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
856*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
857*e7776783SApple OSS Distributions 	kern_return_t           kr;
858*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr, vm_addr;
859*e7776783SApple OSS Distributions 	mach_vm_size_t          vm_size, dirty_size, me_size;
860*e7776783SApple OSS Distributions 	mach_port_t             me_port;
861*e7776783SApple OSS Distributions 
862*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
863*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(MEM_SIZE);
864*e7776783SApple OSS Distributions 
865*e7776783SApple OSS Distributions 	/* making a memory entry... */
866*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
867*e7776783SApple OSS Distributions 	vm_size = MEM_SIZE;
868*e7776783SApple OSS Distributions 	me_size = vm_size;
869*e7776783SApple OSS Distributions 	me_port = MACH_PORT_NULL;
870*e7776783SApple OSS Distributions 	kr = mach_make_memory_entry_64(mach_task_self(),
871*e7776783SApple OSS Distributions 	    &me_size,
872*e7776783SApple OSS Distributions 	    0,
873*e7776783SApple OSS Distributions 	    (MAP_MEM_NAMED_CREATE |
874*e7776783SApple OSS Distributions 	    MAP_MEM_LEDGER_TAGGED |
875*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE),
876*e7776783SApple OSS Distributions 	    &me_port,
877*e7776783SApple OSS Distributions 	    MACH_PORT_NULL);
878*e7776783SApple OSS Distributions 	T_QUIET;
879*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
880*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
881*e7776783SApple OSS Distributions 	T_QUIET;
882*e7776783SApple OSS Distributions 	T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
883*e7776783SApple OSS Distributions 	/* ... should not change footprint */
884*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
885*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
886*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
887*e7776783SApple OSS Distributions 	T_LOG("making a memory entry does not change phys_footprint");
888*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
889*e7776783SApple OSS Distributions 	    "making a memory entry of %lld bytes: "
890*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
891*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
892*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
893*e7776783SApple OSS Distributions 
894*e7776783SApple OSS Distributions 	/* mapping ledger-tagged virtual memory... */
895*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
896*e7776783SApple OSS Distributions 	vm_addr = 0;
897*e7776783SApple OSS Distributions 	kr = mach_vm_map(mach_task_self(), &vm_addr, vm_size,
898*e7776783SApple OSS Distributions 	    0, /* mask */
899*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE,
900*e7776783SApple OSS Distributions 	    me_port,
901*e7776783SApple OSS Distributions 	    0, /* offset */
902*e7776783SApple OSS Distributions 	    FALSE, /* copy */
903*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
904*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
905*e7776783SApple OSS Distributions 	    VM_INHERIT_DEFAULT);
906*e7776783SApple OSS Distributions 	T_QUIET;
907*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_map() error 0x%x (%s)",
908*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
909*e7776783SApple OSS Distributions 	T_QUIET;
910*e7776783SApple OSS Distributions 	T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
911*e7776783SApple OSS Distributions 	/* ... should not change footprint */
912*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
913*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
914*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
915*e7776783SApple OSS Distributions 	T_LOG("mapping ledger-tagged memory does not change phys_footprint");
916*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
917*e7776783SApple OSS Distributions 	    "ledger-tagged mapping of %lld bytes: "
918*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
919*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
920*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
921*e7776783SApple OSS Distributions 
922*e7776783SApple OSS Distributions 	/* touching memory... */
923*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
924*e7776783SApple OSS Distributions 	dirty_size = vm_size / 2;
925*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
926*e7776783SApple OSS Distributions 	/* ... should increase footprint */
927*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
928*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + dirty_size;
929*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
930*e7776783SApple OSS Distributions 	T_LOG("modifying ledger-tagged memory increases phys_footprint");
931*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
932*e7776783SApple OSS Distributions 	    "touched %lld bytes: "
933*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
934*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
935*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
936*e7776783SApple OSS Distributions 
937*e7776783SApple OSS Distributions 	/* deallocating memory while holding memory entry... */
938*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
939*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
940*e7776783SApple OSS Distributions 	T_QUIET;
941*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
942*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
943*e7776783SApple OSS Distributions 	/* ... should not change footprint */
944*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
945*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
946*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
947*e7776783SApple OSS Distributions 	T_LOG("deallocating owned memory while holding memory entry "
948*e7776783SApple OSS Distributions 	    "does not change phys_footprint");
949*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
950*e7776783SApple OSS Distributions 	    "deallocated %lld dirty bytes: "
951*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
952*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
953*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
954*e7776783SApple OSS Distributions 
955*e7776783SApple OSS Distributions 	/* releasing the memory entry... */
956*e7776783SApple OSS Distributions 	kr = mach_port_deallocate(mach_task_self(), me_port);
957*e7776783SApple OSS Distributions 	T_QUIET;
958*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
959*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
960*e7776783SApple OSS Distributions 	/* ... should decrease footprint */
961*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
962*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - dirty_size;
963*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
964*e7776783SApple OSS Distributions 	T_LOG("releasing memory entry decreases phys_footprint");
965*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
966*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
967*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
968*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
969*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
970*e7776783SApple OSS Distributions }
971*e7776783SApple OSS Distributions 
972*e7776783SApple OSS Distributions T_DECL(phys_footprint_no_footprint_for_debug,
973*e7776783SApple OSS Distributions     "phys_footprint for no_footprint_for_debug",
974*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
975*e7776783SApple OSS Distributions {
976*e7776783SApple OSS Distributions 	uint64_t                footprint_before, pagetable_before;
977*e7776783SApple OSS Distributions 	uint64_t                footprint_after, pagetable_after;
978*e7776783SApple OSS Distributions 	uint64_t                footprint_expected;
979*e7776783SApple OSS Distributions 	kern_return_t           kr;
980*e7776783SApple OSS Distributions 	mach_vm_address_t       pre_vm_addr, vm_addr;
981*e7776783SApple OSS Distributions 	mach_vm_size_t          vm_size, dirty_size, me_size;
982*e7776783SApple OSS Distributions 	mach_port_t             me_port;
983*e7776783SApple OSS Distributions 	int                     new_value, ret;
984*e7776783SApple OSS Distributions 
985*e7776783SApple OSS Distributions 	/* pre-warm to account for page table expansion */
986*e7776783SApple OSS Distributions 	pre_vm_addr = pre_warm(MEM_SIZE);
987*e7776783SApple OSS Distributions 
988*e7776783SApple OSS Distributions 	/* making a memory entry... */
989*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
990*e7776783SApple OSS Distributions 	vm_size = MEM_SIZE;
991*e7776783SApple OSS Distributions 	me_size = vm_size;
992*e7776783SApple OSS Distributions 	me_port = MACH_PORT_NULL;
993*e7776783SApple OSS Distributions 	kr = mach_make_memory_entry_64(mach_task_self(),
994*e7776783SApple OSS Distributions 	    &me_size,
995*e7776783SApple OSS Distributions 	    0,
996*e7776783SApple OSS Distributions 	    (MAP_MEM_NAMED_CREATE |
997*e7776783SApple OSS Distributions 	    MAP_MEM_LEDGER_TAGGED |
998*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE),
999*e7776783SApple OSS Distributions 	    &me_port,
1000*e7776783SApple OSS Distributions 	    MACH_PORT_NULL);
1001*e7776783SApple OSS Distributions 	T_QUIET;
1002*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
1003*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
1004*e7776783SApple OSS Distributions 	T_QUIET;
1005*e7776783SApple OSS Distributions 	T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
1006*e7776783SApple OSS Distributions 	/* ... should not change footprint */
1007*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1008*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1009*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1010*e7776783SApple OSS Distributions 	T_LOG("making a memory entry does not change phys_footprint");
1011*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1012*e7776783SApple OSS Distributions 	    "making a memory entry of %lld bytes: "
1013*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1014*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
1015*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1016*e7776783SApple OSS Distributions 
1017*e7776783SApple OSS Distributions 	/* trying to hide debug memory from footprint while not allowed */
1018*e7776783SApple OSS Distributions 	kr = mach_memory_entry_ownership(me_port,
1019*e7776783SApple OSS Distributions 	    mach_task_self(),
1020*e7776783SApple OSS Distributions 	    VM_LEDGER_TAG_DEFAULT,
1021*e7776783SApple OSS Distributions 	    VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG);
1022*e7776783SApple OSS Distributions 	T_QUIET;
1023*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_NO_ACCESS,
1024*e7776783SApple OSS Distributions 	    "mach_memory_entry_ownership(NO_FOOTPRINT_FOR_DEBUG) fails without sysctl");
1025*e7776783SApple OSS Distributions 
1026*e7776783SApple OSS Distributions 	/* let's get permission to hide debug memory */
1027*e7776783SApple OSS Distributions 	new_value = 1;
1028*e7776783SApple OSS Distributions 	ret = sysctlbyname("vm.task_no_footprint_for_debug", NULL, NULL, &new_value, sizeof(new_value));
1029*e7776783SApple OSS Distributions 	if (ret == -1 && errno == ENOENT) {
1030*e7776783SApple OSS Distributions 		T_SKIP("sysctlbyname(vm.task_no_footprint_for_debug) ENOENT");
1031*e7776783SApple OSS Distributions 	}
1032*e7776783SApple OSS Distributions 	T_QUIET;
1033*e7776783SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname(vm.task_no_footprint_for_debug)");
1034*e7776783SApple OSS Distributions 
1035*e7776783SApple OSS Distributions 	/* trying to hide debug memory from footprint while allowed */
1036*e7776783SApple OSS Distributions 	kr = mach_memory_entry_ownership(me_port,
1037*e7776783SApple OSS Distributions 	    mach_task_self(),
1038*e7776783SApple OSS Distributions 	    VM_LEDGER_TAG_DEFAULT,
1039*e7776783SApple OSS Distributions 	    VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG);
1040*e7776783SApple OSS Distributions 	T_QUIET;
1041*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS,
1042*e7776783SApple OSS Distributions 	    "mach_memory_entry_ownership(NO_FOOTPRINT_FOR_DEBUG) succeeds after sysctl");
1043*e7776783SApple OSS Distributions 
1044*e7776783SApple OSS Distributions 	/* mapping ledger-tagged virtual memory... */
1045*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1046*e7776783SApple OSS Distributions 	vm_addr = 0;
1047*e7776783SApple OSS Distributions 	kr = mach_vm_map(mach_task_self(), &vm_addr, vm_size,
1048*e7776783SApple OSS Distributions 	    0, /* mask */
1049*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE,
1050*e7776783SApple OSS Distributions 	    me_port,
1051*e7776783SApple OSS Distributions 	    0, /* offset */
1052*e7776783SApple OSS Distributions 	    FALSE, /* copy */
1053*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
1054*e7776783SApple OSS Distributions 	    VM_PROT_READ | VM_PROT_WRITE,
1055*e7776783SApple OSS Distributions 	    VM_INHERIT_DEFAULT);
1056*e7776783SApple OSS Distributions 	T_QUIET;
1057*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_map() error 0x%x (%s)",
1058*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
1059*e7776783SApple OSS Distributions 	T_QUIET;
1060*e7776783SApple OSS Distributions 	T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
1061*e7776783SApple OSS Distributions 	/* ... should not change footprint */
1062*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1063*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1064*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1065*e7776783SApple OSS Distributions 	T_LOG("mapping ledger-tagged memory does not change phys_footprint");
1066*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1067*e7776783SApple OSS Distributions 	    "ledger-tagged mapping of %lld bytes: "
1068*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1069*e7776783SApple OSS Distributions 	    vm_size, footprint_before, footprint_after,
1070*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1071*e7776783SApple OSS Distributions 
1072*e7776783SApple OSS Distributions 	/* touching memory... */
1073*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1074*e7776783SApple OSS Distributions 	dirty_size = vm_size / 2;
1075*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
1076*e7776783SApple OSS Distributions 	/* ... should not increase footprint */
1077*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1078*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1079*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1080*e7776783SApple OSS Distributions 	T_LOG("modifying no_footprint_for_debug memory does not increase phys_footprint");
1081*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1082*e7776783SApple OSS Distributions 	    "touched %lld bytes: "
1083*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1084*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
1085*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1086*e7776783SApple OSS Distributions 
1087*e7776783SApple OSS Distributions 	/* deallocating memory while holding memory entry... */
1088*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1089*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
1090*e7776783SApple OSS Distributions 	T_QUIET;
1091*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
1092*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
1093*e7776783SApple OSS Distributions 	/* ... should not change footprint */
1094*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1095*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1096*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1097*e7776783SApple OSS Distributions 	T_LOG("deallocating owned memory while holding memory entry "
1098*e7776783SApple OSS Distributions 	    "does not change phys_footprint");
1099*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1100*e7776783SApple OSS Distributions 	    "deallocated %lld dirty bytes: "
1101*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1102*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
1103*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1104*e7776783SApple OSS Distributions 
1105*e7776783SApple OSS Distributions 	/* releasing the memory entry... */
1106*e7776783SApple OSS Distributions 	kr = mach_port_deallocate(mach_task_self(), me_port);
1107*e7776783SApple OSS Distributions 	T_QUIET;
1108*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
1109*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
1110*e7776783SApple OSS Distributions 	/* ... should not change footprint */
1111*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1112*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1113*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1114*e7776783SApple OSS Distributions 	T_LOG("releasing memory entry does not change phys_footprint");
1115*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1116*e7776783SApple OSS Distributions 	    "made volatile %lld dirty bytes: "
1117*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1118*e7776783SApple OSS Distributions 	    dirty_size, footprint_before, footprint_after,
1119*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1120*e7776783SApple OSS Distributions }
1121*e7776783SApple OSS Distributions #endif /* MAP_MEM_LEDGER_TAGGED */
1122*e7776783SApple OSS Distributions 
1123*e7776783SApple OSS Distributions /* IOSurface code from: CoreImage/CoreImageTests/CIRender/SurfaceUtils.c */
1124*e7776783SApple OSS Distributions #include <CoreFoundation/CoreFoundation.h>
1125*e7776783SApple OSS Distributions #include <IOSurface/IOSurface.h>
1126*e7776783SApple OSS Distributions #include <IOSurface/IOSurfacePrivate.h>
1127*e7776783SApple OSS Distributions static size_t
bytes_per_element(uint32_t format)1128*e7776783SApple OSS Distributions bytes_per_element(uint32_t format)
1129*e7776783SApple OSS Distributions {
1130*e7776783SApple OSS Distributions 	size_t bpe = 0;
1131*e7776783SApple OSS Distributions 	switch (format) {
1132*e7776783SApple OSS Distributions 	case 32:     // kCVPixelFormatType_32ARGB (ARGB8)
1133*e7776783SApple OSS Distributions 		bpe = 4;
1134*e7776783SApple OSS Distributions 		break;
1135*e7776783SApple OSS Distributions 	default:
1136*e7776783SApple OSS Distributions 		bpe = 0;
1137*e7776783SApple OSS Distributions 		break;
1138*e7776783SApple OSS Distributions 	}
1139*e7776783SApple OSS Distributions 	return bpe;
1140*e7776783SApple OSS Distributions }
1141*e7776783SApple OSS Distributions static size_t
bytes_per_pixel(uint32_t format)1142*e7776783SApple OSS Distributions bytes_per_pixel(uint32_t format)
1143*e7776783SApple OSS Distributions {
1144*e7776783SApple OSS Distributions 	size_t bpe = 0;
1145*e7776783SApple OSS Distributions 	switch (format) {
1146*e7776783SApple OSS Distributions 	case 32:     // kCVPixelFormatType_32ARGB (ARGB8)
1147*e7776783SApple OSS Distributions 		bpe = 4;
1148*e7776783SApple OSS Distributions 		break;
1149*e7776783SApple OSS Distributions 	default:
1150*e7776783SApple OSS Distributions 		bpe = 0;
1151*e7776783SApple OSS Distributions 		break;
1152*e7776783SApple OSS Distributions 	}
1153*e7776783SApple OSS Distributions 	return bpe;
1154*e7776783SApple OSS Distributions }
1155*e7776783SApple OSS Distributions static inline size_t
roundSizeToMultiple(size_t size,size_t mult)1156*e7776783SApple OSS Distributions roundSizeToMultiple(size_t size, size_t mult)
1157*e7776783SApple OSS Distributions {
1158*e7776783SApple OSS Distributions 	return ((size + mult - 1) / mult) * mult;
1159*e7776783SApple OSS Distributions }
1160*e7776783SApple OSS Distributions static inline void
setIntValue(CFMutableDictionaryRef dict,const CFStringRef key,int value)1161*e7776783SApple OSS Distributions setIntValue(CFMutableDictionaryRef dict, const CFStringRef key, int value)
1162*e7776783SApple OSS Distributions {
1163*e7776783SApple OSS Distributions 	CFNumberRef number = CFNumberCreate(0, kCFNumberIntType, &value);
1164*e7776783SApple OSS Distributions 	CFDictionarySetValue(dict, key, number);
1165*e7776783SApple OSS Distributions 	CFRelease(number);
1166*e7776783SApple OSS Distributions }
1167*e7776783SApple OSS Distributions static inline void
setBoolValue(CFMutableDictionaryRef dict,const CFStringRef key,bool value)1168*e7776783SApple OSS Distributions setBoolValue(CFMutableDictionaryRef dict, const CFStringRef key, bool value)
1169*e7776783SApple OSS Distributions {
1170*e7776783SApple OSS Distributions 	CFDictionarySetValue(dict, key, value ? kCFBooleanTrue : kCFBooleanFalse);
1171*e7776783SApple OSS Distributions }
1172*e7776783SApple OSS Distributions typedef void (^SurfacePlaneBlock)(void *data, size_t planeIndex, size_t width, size_t height, size_t rowbytes);
1173*e7776783SApple OSS Distributions static IOReturn
SurfaceApplyPlaneBlock(IOSurfaceRef surface,SurfacePlaneBlock block)1174*e7776783SApple OSS Distributions SurfaceApplyPlaneBlock(IOSurfaceRef surface, SurfacePlaneBlock block)
1175*e7776783SApple OSS Distributions {
1176*e7776783SApple OSS Distributions 	if (surface == nil || block == nil) {
1177*e7776783SApple OSS Distributions 		return kIOReturnBadArgument;
1178*e7776783SApple OSS Distributions 	}
1179*e7776783SApple OSS Distributions 
1180*e7776783SApple OSS Distributions 	IOReturn result = kIOReturnSuccess;
1181*e7776783SApple OSS Distributions 	size_t planeCount = IOSurfaceGetPlaneCount(surface);
1182*e7776783SApple OSS Distributions 
1183*e7776783SApple OSS Distributions 	if (planeCount == 0) {
1184*e7776783SApple OSS Distributions 		result = IOSurfaceLock(surface, 0, NULL);
1185*e7776783SApple OSS Distributions 		if (result != kIOReturnSuccess) {
1186*e7776783SApple OSS Distributions 			return result;
1187*e7776783SApple OSS Distributions 		}
1188*e7776783SApple OSS Distributions 
1189*e7776783SApple OSS Distributions 		void* base = IOSurfaceGetBaseAddress(surface);
1190*e7776783SApple OSS Distributions 		size_t rb = IOSurfaceGetBytesPerRow(surface);
1191*e7776783SApple OSS Distributions 		size_t w = IOSurfaceGetWidth(surface);
1192*e7776783SApple OSS Distributions 		size_t h = IOSurfaceGetHeight(surface);
1193*e7776783SApple OSS Distributions 
1194*e7776783SApple OSS Distributions 		if (base && rb && w && h) {
1195*e7776783SApple OSS Distributions 			block(base, 0, w, h, rb);
1196*e7776783SApple OSS Distributions 		}
1197*e7776783SApple OSS Distributions 
1198*e7776783SApple OSS Distributions 		IOSurfaceUnlock(surface, 0, NULL);
1199*e7776783SApple OSS Distributions 	} else if (planeCount == 2) {
1200*e7776783SApple OSS Distributions 		for (size_t i = 0; i < planeCount; i++) {
1201*e7776783SApple OSS Distributions 			result = IOSurfaceLock(surface, 0, NULL);
1202*e7776783SApple OSS Distributions 			if (result != kIOReturnSuccess) {
1203*e7776783SApple OSS Distributions 				return result;
1204*e7776783SApple OSS Distributions 			}
1205*e7776783SApple OSS Distributions 
1206*e7776783SApple OSS Distributions 			void* base = IOSurfaceGetBaseAddressOfPlane(surface, i);
1207*e7776783SApple OSS Distributions 			size_t rb = IOSurfaceGetBytesPerRowOfPlane(surface, i);
1208*e7776783SApple OSS Distributions 			size_t w = IOSurfaceGetWidthOfPlane(surface, i);
1209*e7776783SApple OSS Distributions 			size_t h = IOSurfaceGetHeightOfPlane(surface, i);
1210*e7776783SApple OSS Distributions 
1211*e7776783SApple OSS Distributions 			if (base && rb && w && h) {
1212*e7776783SApple OSS Distributions 				block(base, i, w, h, rb);
1213*e7776783SApple OSS Distributions 			}
1214*e7776783SApple OSS Distributions 
1215*e7776783SApple OSS Distributions 			IOSurfaceUnlock(surface, 0, NULL);
1216*e7776783SApple OSS Distributions 		}
1217*e7776783SApple OSS Distributions 	}
1218*e7776783SApple OSS Distributions 	return result;
1219*e7776783SApple OSS Distributions }
1220*e7776783SApple OSS Distributions static void
ClearSurface(IOSurfaceRef surface)1221*e7776783SApple OSS Distributions ClearSurface(IOSurfaceRef surface)
1222*e7776783SApple OSS Distributions {
1223*e7776783SApple OSS Distributions 	const int zero = 0;
1224*e7776783SApple OSS Distributions 	(void) SurfaceApplyPlaneBlock(surface, ^(void *p, size_t i, __unused size_t w, size_t h, size_t rb)
1225*e7776783SApple OSS Distributions 	{
1226*e7776783SApple OSS Distributions 		if (i == 0) {
1227*e7776783SApple OSS Distributions 		        memset(p, zero, rb * h);
1228*e7776783SApple OSS Distributions 		} else {
1229*e7776783SApple OSS Distributions 		        memset(p, 128, rb * h);
1230*e7776783SApple OSS Distributions 		}
1231*e7776783SApple OSS Distributions 	});
1232*e7776783SApple OSS Distributions }
1233*e7776783SApple OSS Distributions static size_t
SurfaceGetMemorySize(IOSurfaceRef surface)1234*e7776783SApple OSS Distributions SurfaceGetMemorySize(IOSurfaceRef surface)
1235*e7776783SApple OSS Distributions {
1236*e7776783SApple OSS Distributions 	size_t planeCount = IOSurfaceGetPlaneCount(surface);
1237*e7776783SApple OSS Distributions 
1238*e7776783SApple OSS Distributions 	if (planeCount == 0) {
1239*e7776783SApple OSS Distributions 		size_t rb = IOSurfaceGetBytesPerRow(surface);
1240*e7776783SApple OSS Distributions 		size_t h = IOSurfaceGetHeight(surface);
1241*e7776783SApple OSS Distributions 		return rb * h;
1242*e7776783SApple OSS Distributions 	} else if (planeCount == 2) {
1243*e7776783SApple OSS Distributions 		size_t rb0 = IOSurfaceGetBytesPerRowOfPlane(surface, 0);
1244*e7776783SApple OSS Distributions 		size_t h0 = IOSurfaceGetHeightOfPlane(surface, 0);
1245*e7776783SApple OSS Distributions 		size_t rb1 = IOSurfaceGetBytesPerRowOfPlane(surface, 1);
1246*e7776783SApple OSS Distributions 		size_t h1 = IOSurfaceGetHeightOfPlane(surface, 1);
1247*e7776783SApple OSS Distributions 		return rb0 * h0 + rb1 * h1;
1248*e7776783SApple OSS Distributions 	}
1249*e7776783SApple OSS Distributions 	return 0;
1250*e7776783SApple OSS Distributions }
1251*e7776783SApple OSS Distributions static IOSurfaceRef
CreateSurface(uint32_t pixelsWide,uint32_t pixelsHigh,uint32_t rowBytesAlignment,uint32_t fmt,bool purgeable,bool clear)1252*e7776783SApple OSS Distributions CreateSurface(uint32_t pixelsWide, uint32_t pixelsHigh, uint32_t rowBytesAlignment, uint32_t fmt, bool purgeable, bool clear)
1253*e7776783SApple OSS Distributions {
1254*e7776783SApple OSS Distributions 	IOSurfaceRef surface = nil;
1255*e7776783SApple OSS Distributions 
1256*e7776783SApple OSS Distributions 	if (pixelsWide < 1 || pixelsHigh < 1 || fmt == 0) {
1257*e7776783SApple OSS Distributions 		return nil;
1258*e7776783SApple OSS Distributions 	}
1259*e7776783SApple OSS Distributions 
1260*e7776783SApple OSS Distributions 	size_t bpp = bytes_per_pixel(fmt);
1261*e7776783SApple OSS Distributions 	size_t bpe = bytes_per_element(fmt);
1262*e7776783SApple OSS Distributions 	if (bpp == 0 || bpe == 0) {
1263*e7776783SApple OSS Distributions 		return nil;
1264*e7776783SApple OSS Distributions 	}
1265*e7776783SApple OSS Distributions 
1266*e7776783SApple OSS Distributions 	size_t rowbytes = pixelsWide * bpp;
1267*e7776783SApple OSS Distributions 	if (rowBytesAlignment == 0) {
1268*e7776783SApple OSS Distributions 		rowBytesAlignment = 16;
1269*e7776783SApple OSS Distributions 	}
1270*e7776783SApple OSS Distributions 	rowbytes = roundSizeToMultiple(rowbytes, rowBytesAlignment);
1271*e7776783SApple OSS Distributions 
1272*e7776783SApple OSS Distributions 	CFMutableDictionaryRef props = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1273*e7776783SApple OSS Distributions 	setIntValue(props, kIOSurfaceBytesPerRow, (int)rowbytes);
1274*e7776783SApple OSS Distributions 	setIntValue(props, kIOSurfaceWidth, (int)pixelsWide);
1275*e7776783SApple OSS Distributions 	setIntValue(props, kIOSurfaceHeight, (int)pixelsHigh);
1276*e7776783SApple OSS Distributions 	setIntValue(props, kIOSurfacePixelFormat, (int)fmt);
1277*e7776783SApple OSS Distributions #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1278*e7776783SApple OSS Distributions 	setBoolValue(props, kIOSurfaceNonPurgeable, !purgeable);
1279*e7776783SApple OSS Distributions #else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1280*e7776783SApple OSS Distributions 	(void)purgeable;
1281*e7776783SApple OSS Distributions #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1282*e7776783SApple OSS Distributions 	{
1283*e7776783SApple OSS Distributions 		if (bpe != bpp) { // i.e. a 422 format such as 'yuvf' etc.
1284*e7776783SApple OSS Distributions 			setIntValue(props, kIOSurfaceElementWidth, 2);
1285*e7776783SApple OSS Distributions 			setIntValue(props, kIOSurfaceElementHeight, 1);
1286*e7776783SApple OSS Distributions 		}
1287*e7776783SApple OSS Distributions 		setIntValue(props, kIOSurfaceBytesPerElement, (int)bpe);
1288*e7776783SApple OSS Distributions 	}
1289*e7776783SApple OSS Distributions 
1290*e7776783SApple OSS Distributions 	surface = IOSurfaceCreate(props);
1291*e7776783SApple OSS Distributions 
1292*e7776783SApple OSS Distributions 	if (clear) {
1293*e7776783SApple OSS Distributions 		ClearSurface(surface);
1294*e7776783SApple OSS Distributions 	}
1295*e7776783SApple OSS Distributions 
1296*e7776783SApple OSS Distributions 	CFRelease(props);
1297*e7776783SApple OSS Distributions 	return surface;
1298*e7776783SApple OSS Distributions }
1299*e7776783SApple OSS Distributions T_DECL(phys_footprint_purgeable_iokit,
1300*e7776783SApple OSS Distributions     "phys_footprint for purgeable IOKit memory",
1301*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
1302*e7776783SApple OSS Distributions {
1303*e7776783SApple OSS Distributions 	uint64_t        footprint_before, pagetable_before;
1304*e7776783SApple OSS Distributions 	uint64_t        footprint_after, pagetable_after;
1305*e7776783SApple OSS Distributions 	uint64_t        footprint_expected, footprint_delta_slop;
1306*e7776783SApple OSS Distributions 	int64_t         footprint_delta;
1307*e7776783SApple OSS Distributions 	IOSurfaceRef    surface;
1308*e7776783SApple OSS Distributions 	uint32_t        old_state;
1309*e7776783SApple OSS Distributions 	uint64_t        surface_size;
1310*e7776783SApple OSS Distributions 
1311*e7776783SApple OSS Distributions 	T_SETUPBEGIN;
1312*e7776783SApple OSS Distributions 	footprint_delta_slop = 8 * vm_kernel_page_size;
1313*e7776783SApple OSS Distributions 	ledger_init();
1314*e7776783SApple OSS Distributions 	surface = CreateSurface(1024, 1024, 0, 32, true, true);
1315*e7776783SApple OSS Distributions 	IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableVolatile, &old_state);
1316*e7776783SApple OSS Distributions 	IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableNonVolatile, &old_state);
1317*e7776783SApple OSS Distributions 	CFRelease(surface);
1318*e7776783SApple OSS Distributions 	T_SETUPEND;
1319*e7776783SApple OSS Distributions 
1320*e7776783SApple OSS Distributions 	surface_size = 1024 * 1024 * 4;
1321*e7776783SApple OSS Distributions 
1322*e7776783SApple OSS Distributions 	/* create IOsurface: footprint grows */
1323*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1324*e7776783SApple OSS Distributions 	surface = CreateSurface(1024, 1024, 0, 32, true, true);
1325*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1326*e7776783SApple OSS Distributions 	if (legacy_footprint) {
1327*e7776783SApple OSS Distributions 		footprint_expected = footprint_before;
1328*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1329*e7776783SApple OSS Distributions 		footprint_delta = (int64_t)(footprint_after - footprint_expected);
1330*e7776783SApple OSS Distributions 		T_LOG("LEGACY FOOTPRINT: creating purgeable IOSurface: no footprint impact");
1331*e7776783SApple OSS Distributions 		T_EXPECT_LE((uint64_t)llabs(footprint_delta), footprint_delta_slop,
1332*e7776783SApple OSS Distributions 		    "create purgeable IOSurface %lld bytes: "
1333*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1334*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1335*e7776783SApple OSS Distributions 		    footprint_expected, footprint_delta);
1336*e7776783SApple OSS Distributions 	} else {
1337*e7776783SApple OSS Distributions 		footprint_expected = footprint_before + surface_size;
1338*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1339*e7776783SApple OSS Distributions 		footprint_delta = (int64_t)(footprint_after - footprint_expected);
1340*e7776783SApple OSS Distributions 		T_LOG("creating purgeable IOSurface increases phys_footprint");
1341*e7776783SApple OSS Distributions 		T_EXPECT_LE((uint64_t)llabs(footprint_delta), footprint_delta_slop,
1342*e7776783SApple OSS Distributions 		    "create purgeable IOSurface %lld bytes: "
1343*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1344*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1345*e7776783SApple OSS Distributions 		    footprint_expected, footprint_delta);
1346*e7776783SApple OSS Distributions 	}
1347*e7776783SApple OSS Distributions 
1348*e7776783SApple OSS Distributions 	/* make IOSurface volatile: footprint shrinks */
1349*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1350*e7776783SApple OSS Distributions 	IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableVolatile, &old_state);
1351*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1352*e7776783SApple OSS Distributions 	if (legacy_footprint) {
1353*e7776783SApple OSS Distributions 		footprint_expected = footprint_before;
1354*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1355*e7776783SApple OSS Distributions 		T_LOG("LEGACY FOOTPRINT: volatile IOSurface: no footprint impact");
1356*e7776783SApple OSS Distributions 		T_EXPECT_EQ(footprint_after, footprint_expected,
1357*e7776783SApple OSS Distributions 		    "volatile IOSurface %lld bytes: "
1358*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1359*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1360*e7776783SApple OSS Distributions 		    footprint_expected, footprint_after - footprint_expected);
1361*e7776783SApple OSS Distributions 	} else {
1362*e7776783SApple OSS Distributions 		footprint_expected = footprint_before - surface_size;
1363*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1364*e7776783SApple OSS Distributions 		T_LOG("making IOSurface volatile decreases phys_footprint");
1365*e7776783SApple OSS Distributions 		T_EXPECT_EQ(footprint_after, footprint_expected,
1366*e7776783SApple OSS Distributions 		    "made volatile %lld bytes: "
1367*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1368*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1369*e7776783SApple OSS Distributions 		    footprint_expected, footprint_after - footprint_expected);
1370*e7776783SApple OSS Distributions 	}
1371*e7776783SApple OSS Distributions 
1372*e7776783SApple OSS Distributions 	/* make IOSurface non-volatile: footprint grows */
1373*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1374*e7776783SApple OSS Distributions 	IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableNonVolatile, &old_state);
1375*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1376*e7776783SApple OSS Distributions 	if (legacy_footprint) {
1377*e7776783SApple OSS Distributions 		footprint_expected = footprint_before;
1378*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1379*e7776783SApple OSS Distributions 		T_LOG("LEGACY FOOTPRINT: non-volatile IOSurface: no footprint impact");
1380*e7776783SApple OSS Distributions 		T_EXPECT_EQ(footprint_after, footprint_expected,
1381*e7776783SApple OSS Distributions 		    "non-volatile IOSurface %lld bytes: "
1382*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1383*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1384*e7776783SApple OSS Distributions 		    footprint_expected, footprint_after - footprint_expected);
1385*e7776783SApple OSS Distributions 	} else {
1386*e7776783SApple OSS Distributions 		footprint_expected = footprint_before + surface_size;
1387*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1388*e7776783SApple OSS Distributions 		T_LOG("making IOSurface non-volatile increases phys_footprint");
1389*e7776783SApple OSS Distributions 		T_EXPECT_EQ(footprint_after, footprint_expected,
1390*e7776783SApple OSS Distributions 		    "made non-volatile %lld bytes: "
1391*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1392*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1393*e7776783SApple OSS Distributions 		    footprint_expected, footprint_after - footprint_expected);
1394*e7776783SApple OSS Distributions 	}
1395*e7776783SApple OSS Distributions 
1396*e7776783SApple OSS Distributions 	/* accessing IOSurface re-mapping: no footprint impact */
1397*e7776783SApple OSS Distributions 
1398*e7776783SApple OSS Distributions 	/* deallocating IOSurface re-mapping: no footprint impact */
1399*e7776783SApple OSS Distributions 
1400*e7776783SApple OSS Distributions 	/* release IOSurface: footprint shrinks */
1401*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1402*e7776783SApple OSS Distributions 	CFRelease(surface);
1403*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1404*e7776783SApple OSS Distributions 	if (legacy_footprint) {
1405*e7776783SApple OSS Distributions 		footprint_expected = footprint_before;
1406*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1407*e7776783SApple OSS Distributions 		T_LOG("LEGACY FOOTPRINT: release IOSurface: no footprint impact");
1408*e7776783SApple OSS Distributions 		T_EXPECT_EQ(footprint_after, footprint_expected,
1409*e7776783SApple OSS Distributions 		    "releasing IOSurface %lld bytes: "
1410*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1411*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1412*e7776783SApple OSS Distributions 		    footprint_expected, footprint_after - footprint_expected);
1413*e7776783SApple OSS Distributions 	} else {
1414*e7776783SApple OSS Distributions 		footprint_expected = footprint_before - surface_size;
1415*e7776783SApple OSS Distributions 		footprint_expected += (pagetable_after - pagetable_before);
1416*e7776783SApple OSS Distributions 		T_LOG("releasing IOSurface decreases phys_footprint");
1417*e7776783SApple OSS Distributions 		T_EXPECT_EQ(footprint_after, footprint_expected,
1418*e7776783SApple OSS Distributions 		    "released IOSurface %lld bytes: "
1419*e7776783SApple OSS Distributions 		    "footprint %lld -> %lld expected %lld delta %lld",
1420*e7776783SApple OSS Distributions 		    surface_size, footprint_before, footprint_after,
1421*e7776783SApple OSS Distributions 		    footprint_expected, footprint_after - footprint_expected);
1422*e7776783SApple OSS Distributions 	}
1423*e7776783SApple OSS Distributions }
1424*e7776783SApple OSS Distributions 
1425*e7776783SApple OSS Distributions #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1426*e7776783SApple OSS Distributions T_DECL(phys_footprint_nonpurgeable_iokit,
1427*e7776783SApple OSS Distributions     "phys_footprint for non-purgeable IOKit memory",
1428*e7776783SApple OSS Distributions     T_META_LTEPHASE(LTE_POSTINIT))
1429*e7776783SApple OSS Distributions {
1430*e7776783SApple OSS Distributions 	uint64_t        footprint_before, pagetable_before;
1431*e7776783SApple OSS Distributions 	uint64_t        footprint_after, pagetable_after;
1432*e7776783SApple OSS Distributions 	uint64_t        footprint_expected, footprint_delta_slop;
1433*e7776783SApple OSS Distributions 	int64_t         footprint_delta;
1434*e7776783SApple OSS Distributions 	IOSurfaceRef    surface;
1435*e7776783SApple OSS Distributions 	uint64_t        surface_size;
1436*e7776783SApple OSS Distributions 	void            *map_base;
1437*e7776783SApple OSS Distributions 	size_t          map_size;
1438*e7776783SApple OSS Distributions 	mach_vm_address_t remap_addr;
1439*e7776783SApple OSS Distributions 	kern_return_t kr;
1440*e7776783SApple OSS Distributions 	vm_prot_t       cur_prot, max_prot;
1441*e7776783SApple OSS Distributions 	uint32_t        old_state;
1442*e7776783SApple OSS Distributions 
1443*e7776783SApple OSS Distributions 
1444*e7776783SApple OSS Distributions 	T_SETUPBEGIN;
1445*e7776783SApple OSS Distributions 	ledger_init();
1446*e7776783SApple OSS Distributions 	surface = CreateSurface(1024, 1024, 0, 32, false, true);
1447*e7776783SApple OSS Distributions 	CFRelease(surface);
1448*e7776783SApple OSS Distributions 	footprint_delta_slop = 8 * vm_kernel_page_size;
1449*e7776783SApple OSS Distributions 	T_SETUPEND;
1450*e7776783SApple OSS Distributions 
1451*e7776783SApple OSS Distributions 	surface_size = 1024 * 1024 * 4;
1452*e7776783SApple OSS Distributions 
1453*e7776783SApple OSS Distributions 	/* create IOsurface: footprint grows */
1454*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1455*e7776783SApple OSS Distributions 	surface = CreateSurface(1024, 1024, 0, 32, false, true);
1456*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1457*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + surface_size;
1458*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1459*e7776783SApple OSS Distributions 	footprint_delta = (int64_t)(footprint_after - footprint_expected);
1460*e7776783SApple OSS Distributions 	T_LOG("creating non-purgeable IOSurface increases phys_footprint");
1461*e7776783SApple OSS Distributions 	T_EXPECT_LE((uint64_t)llabs(footprint_delta), footprint_delta_slop,
1462*e7776783SApple OSS Distributions 	    "create non-purgeable IOSurface %lld bytes: "
1463*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1464*e7776783SApple OSS Distributions 	    surface_size, footprint_before, footprint_after,
1465*e7776783SApple OSS Distributions 	    footprint_expected, footprint_delta);
1466*e7776783SApple OSS Distributions 
1467*e7776783SApple OSS Distributions 	/* make IOSurface volatile: fail and no footprint impact */
1468*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1469*e7776783SApple OSS Distributions 	IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableVolatile, &old_state);
1470*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1471*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1472*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1473*e7776783SApple OSS Distributions 	T_LOG("making non-purgeable IOSurface volatile: no footprint impact");
1474*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1475*e7776783SApple OSS Distributions 	    "made volatile %lld non-purgeable bytes: "
1476*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1477*e7776783SApple OSS Distributions 	    surface_size, footprint_before, footprint_after,
1478*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1479*e7776783SApple OSS Distributions 
1480*e7776783SApple OSS Distributions 	/* re-mapping IOSurface: no footprint impact */
1481*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1482*e7776783SApple OSS Distributions 	map_base = IOSurfaceGetBaseAddress(surface);
1483*e7776783SApple OSS Distributions 	map_size = SurfaceGetMemorySize(surface);
1484*e7776783SApple OSS Distributions //	T_EXPECT_EQ(map_size, surface_size, "map_size %lld surface_size %lld",
1485*e7776783SApple OSS Distributions //		    map_size, surface_size);
1486*e7776783SApple OSS Distributions 	remap_addr = 0;
1487*e7776783SApple OSS Distributions 	kr = mach_vm_remap(mach_task_self(),
1488*e7776783SApple OSS Distributions 	    &remap_addr,
1489*e7776783SApple OSS Distributions 	    (mach_vm_size_t)surface_size,
1490*e7776783SApple OSS Distributions 	    0,
1491*e7776783SApple OSS Distributions 	    VM_FLAGS_ANYWHERE,
1492*e7776783SApple OSS Distributions 	    mach_task_self(),
1493*e7776783SApple OSS Distributions 	    (mach_vm_address_t)map_base,
1494*e7776783SApple OSS Distributions 	    FALSE,                /* copy */
1495*e7776783SApple OSS Distributions 	    &cur_prot,
1496*e7776783SApple OSS Distributions 	    &max_prot,
1497*e7776783SApple OSS Distributions 	    VM_INHERIT_DEFAULT);
1498*e7776783SApple OSS Distributions 	T_QUIET;
1499*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_remap() error 0x%x (%s)",
1500*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
1501*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1502*e7776783SApple OSS Distributions 	footprint_expected = footprint_before;
1503*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1504*e7776783SApple OSS Distributions 	T_LOG("re-mapping IOSurface does not impact phys_footprint");
1505*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1506*e7776783SApple OSS Distributions 	    "remapping IOSurface %lld bytes: "
1507*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1508*e7776783SApple OSS Distributions 	    surface_size, footprint_before, footprint_after,
1509*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1510*e7776783SApple OSS Distributions 
1511*e7776783SApple OSS Distributions 	/* accessing IOSurface re-mapping: footprint grows */
1512*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1513*e7776783SApple OSS Distributions 	memset((char *)(uintptr_t)remap_addr, 'p', (size_t)surface_size);
1514*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1515*e7776783SApple OSS Distributions 	footprint_expected = footprint_before + surface_size;
1516*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1517*e7776783SApple OSS Distributions 	T_LOG("accessing re-mapped IOSurface grows phys_footprint");
1518*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1519*e7776783SApple OSS Distributions 	    "accessing remapped IOSurface %lld bytes: "
1520*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1521*e7776783SApple OSS Distributions 	    surface_size, footprint_before, footprint_after,
1522*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1523*e7776783SApple OSS Distributions 
1524*e7776783SApple OSS Distributions 	/* deallocating IOSurface re-mapping: footprint shrinks */
1525*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1526*e7776783SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(),
1527*e7776783SApple OSS Distributions 	    remap_addr,
1528*e7776783SApple OSS Distributions 	    (mach_vm_size_t)surface_size);
1529*e7776783SApple OSS Distributions 	T_QUIET;
1530*e7776783SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
1531*e7776783SApple OSS Distributions 	    kr, mach_error_string(kr));
1532*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1533*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - surface_size;
1534*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1535*e7776783SApple OSS Distributions 	T_LOG("deallocating re-mapping of IOSurface shrinks phys_footprint");
1536*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1537*e7776783SApple OSS Distributions 	    "deallocating remapped IOSurface %lld bytes: "
1538*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1539*e7776783SApple OSS Distributions 	    surface_size, footprint_before, footprint_after,
1540*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1541*e7776783SApple OSS Distributions 
1542*e7776783SApple OSS Distributions 	/* release IOSurface: footprint shrinks */
1543*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_before, &pagetable_before);
1544*e7776783SApple OSS Distributions 	CFRelease(surface);
1545*e7776783SApple OSS Distributions 	get_ledger_info(&footprint_after, &pagetable_after);
1546*e7776783SApple OSS Distributions 	footprint_expected = footprint_before - surface_size;
1547*e7776783SApple OSS Distributions 	footprint_expected += (pagetable_after - pagetable_before);
1548*e7776783SApple OSS Distributions 	T_LOG("releasing IOSurface decreases phys_footprint");
1549*e7776783SApple OSS Distributions 	T_EXPECT_EQ(footprint_after, footprint_expected,
1550*e7776783SApple OSS Distributions 	    "released IOSurface %lld bytes: "
1551*e7776783SApple OSS Distributions 	    "footprint %lld -> %lld expected %lld delta %lld",
1552*e7776783SApple OSS Distributions 	    surface_size, footprint_before, footprint_after,
1553*e7776783SApple OSS Distributions 	    footprint_expected, footprint_after - footprint_expected);
1554*e7776783SApple OSS Distributions }
1555*e7776783SApple OSS Distributions #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1556