xref: /xnu-8796.141.3/tools/tests/superpages/testsp.c (revision 1b191cb58250d0705d8a51287127505aa4bc0789)
1*1b191cb5SApple OSS Distributions /*
2*1b191cb5SApple OSS Distributions  * This tests the Mac OS X Superpage API introduced in 10.7
3*1b191cb5SApple OSS Distributions  *
4*1b191cb5SApple OSS Distributions  * Note that most of these calls go through the mach_vm_allocate() interface,
5*1b191cb5SApple OSS Distributions  * but the actually supported and documented interface is the mmap() one
6*1b191cb5SApple OSS Distributions  * (see mmap(2)).
7*1b191cb5SApple OSS Distributions  */
8*1b191cb5SApple OSS Distributions #include <stdio.h>
9*1b191cb5SApple OSS Distributions #include <stdlib.h>
10*1b191cb5SApple OSS Distributions #include <signal.h>
11*1b191cb5SApple OSS Distributions #include <setjmp.h>
12*1b191cb5SApple OSS Distributions #include <mach/mach.h>
13*1b191cb5SApple OSS Distributions #include <mach/mach_vm.h>
14*1b191cb5SApple OSS Distributions #include <time.h>
15*1b191cb5SApple OSS Distributions #include <unistd.h>
16*1b191cb5SApple OSS Distributions #include <fcntl.h>
17*1b191cb5SApple OSS Distributions #include <sys/mman.h>
18*1b191cb5SApple OSS Distributions 
19*1b191cb5SApple OSS Distributions #define SUPERPAGE_SIZE (2*1024*1024)
20*1b191cb5SApple OSS Distributions #define SUPERPAGE_MASK (-SUPERPAGE_SIZE)
21*1b191cb5SApple OSS Distributions 
22*1b191cb5SApple OSS Distributions #ifdef __LP64__
23*1b191cb5SApple OSS Distributions #define FIXED_ADDRESS1 (0x100000000ULL+500*1024*1024) /* at 4 GB + 500 MB virtual */
24*1b191cb5SApple OSS Distributions #define FIXED_ADDRESS2 (0x100000000ULL+502*1024*1024 + 4*1024) /* at 4 GB + 502 MB + 4 KB virtual */
25*1b191cb5SApple OSS Distributions #else
26*1b191cb5SApple OSS Distributions #define FIXED_ADDRESS1 (500*1024*1024) /* at 500 MB virtual */
27*1b191cb5SApple OSS Distributions #define FIXED_ADDRESS2 (502*1024*1024 + 4*1024) /* at 502 MB + 4 KB virtual */
28*1b191cb5SApple OSS Distributions #endif
29*1b191cb5SApple OSS Distributions 
30*1b191cb5SApple OSS Distributions char error[100];
31*1b191cb5SApple OSS Distributions 
32*1b191cb5SApple OSS Distributions jmp_buf resume;
33*1b191cb5SApple OSS Distributions void
test_signal_handler(int signo)34*1b191cb5SApple OSS Distributions test_signal_handler(int signo)
35*1b191cb5SApple OSS Distributions {
36*1b191cb5SApple OSS Distributions 	longjmp(resume, signo);
37*1b191cb5SApple OSS Distributions }
38*1b191cb5SApple OSS Distributions 
39*1b191cb5SApple OSS Distributions char *signame[32] = {
40*1b191cb5SApple OSS Distributions 	[SIGBUS] "SIGBUS",
41*1b191cb5SApple OSS Distributions 	[SIGSEGV] "SIGSEGV"
42*1b191cb5SApple OSS Distributions };
43*1b191cb5SApple OSS Distributions 
44*1b191cb5SApple OSS Distributions typedef struct {
45*1b191cb5SApple OSS Distributions 	char *description;
46*1b191cb5SApple OSS Distributions 	boolean_t (*fn)();
47*1b191cb5SApple OSS Distributions } test_t;
48*1b191cb5SApple OSS Distributions 
49*1b191cb5SApple OSS Distributions boolean_t
check_kr(int kr,char * fn)50*1b191cb5SApple OSS Distributions check_kr(int kr, char *fn)
51*1b191cb5SApple OSS Distributions {
52*1b191cb5SApple OSS Distributions 	if (kr) {
53*1b191cb5SApple OSS Distributions 		sprintf(error, "%s() returned %d", fn, kr);
54*1b191cb5SApple OSS Distributions 		return FALSE;
55*1b191cb5SApple OSS Distributions 	}
56*1b191cb5SApple OSS Distributions 	return TRUE;
57*1b191cb5SApple OSS Distributions }
58*1b191cb5SApple OSS Distributions 
59*1b191cb5SApple OSS Distributions boolean_t
check_addr0(mach_vm_address_t addr,char * fn)60*1b191cb5SApple OSS Distributions check_addr0(mach_vm_address_t addr, char *fn)
61*1b191cb5SApple OSS Distributions {
62*1b191cb5SApple OSS Distributions 	if (!addr) {
63*1b191cb5SApple OSS Distributions 		sprintf(error, "%s() returned address 0", fn);
64*1b191cb5SApple OSS Distributions 		return FALSE;
65*1b191cb5SApple OSS Distributions 	}
66*1b191cb5SApple OSS Distributions 	return TRUE;
67*1b191cb5SApple OSS Distributions }
68*1b191cb5SApple OSS Distributions 
69*1b191cb5SApple OSS Distributions boolean_t
check_addr(mach_vm_address_t addr1,mach_vm_address_t addr2,char * fn)70*1b191cb5SApple OSS Distributions check_addr(mach_vm_address_t addr1, mach_vm_address_t addr2, char *fn)
71*1b191cb5SApple OSS Distributions {
72*1b191cb5SApple OSS Distributions 	if (addr1 != addr2) {
73*1b191cb5SApple OSS Distributions 		sprintf(error, "%s() returned address %llx instead of %llx", fn, addr1, addr2);
74*1b191cb5SApple OSS Distributions 		return FALSE;
75*1b191cb5SApple OSS Distributions 	}
76*1b191cb5SApple OSS Distributions 	return TRUE;
77*1b191cb5SApple OSS Distributions }
78*1b191cb5SApple OSS Distributions 
79*1b191cb5SApple OSS Distributions boolean_t
check_align(mach_vm_address_t addr)80*1b191cb5SApple OSS Distributions check_align(mach_vm_address_t addr)
81*1b191cb5SApple OSS Distributions {
82*1b191cb5SApple OSS Distributions 	if (addr & !SUPERPAGE_MASK) {
83*1b191cb5SApple OSS Distributions 		sprintf(error, "address not aligned properly: 0x%llx", addr);
84*1b191cb5SApple OSS Distributions 		return FALSE;
85*1b191cb5SApple OSS Distributions 	}
86*1b191cb5SApple OSS Distributions 	return TRUE;
87*1b191cb5SApple OSS Distributions }
88*1b191cb5SApple OSS Distributions 
89*1b191cb5SApple OSS Distributions boolean_t
check_r(mach_vm_address_t addr,mach_vm_size_t size,int * res)90*1b191cb5SApple OSS Distributions check_r(mach_vm_address_t addr, mach_vm_size_t size, int *res)
91*1b191cb5SApple OSS Distributions {
92*1b191cb5SApple OSS Distributions 	volatile char *data = (char*)(uintptr_t)addr;
93*1b191cb5SApple OSS Distributions 	int i, sig, test;
94*1b191cb5SApple OSS Distributions 
95*1b191cb5SApple OSS Distributions 	if ((sig = setjmp(resume)) != 0) {
96*1b191cb5SApple OSS Distributions 		sprintf(error, "%s when reading", signame[sig]);
97*1b191cb5SApple OSS Distributions 		return FALSE;
98*1b191cb5SApple OSS Distributions 	}
99*1b191cb5SApple OSS Distributions 	test = 0;
100*1b191cb5SApple OSS Distributions 	for (i = 0; i < size; i++) {
101*1b191cb5SApple OSS Distributions 		test += (data)[i];
102*1b191cb5SApple OSS Distributions 	}
103*1b191cb5SApple OSS Distributions 
104*1b191cb5SApple OSS Distributions 	if (res) {
105*1b191cb5SApple OSS Distributions 		*res = test;
106*1b191cb5SApple OSS Distributions 	}
107*1b191cb5SApple OSS Distributions 
108*1b191cb5SApple OSS Distributions 	return TRUE;
109*1b191cb5SApple OSS Distributions }
110*1b191cb5SApple OSS Distributions 
111*1b191cb5SApple OSS Distributions /* check that no subpage of the superpage is readable */
112*1b191cb5SApple OSS Distributions boolean_t
check_nr(mach_vm_address_t addr,mach_vm_size_t size,int * res)113*1b191cb5SApple OSS Distributions check_nr(mach_vm_address_t addr, mach_vm_size_t size, int *res)
114*1b191cb5SApple OSS Distributions {
115*1b191cb5SApple OSS Distributions 	int i;
116*1b191cb5SApple OSS Distributions 	boolean_t ret;
117*1b191cb5SApple OSS Distributions 	for (i = 0; i < size / PAGE_SIZE; i++) {
118*1b191cb5SApple OSS Distributions 		if ((ret = check_r(addr + i * PAGE_SIZE, PAGE_SIZE, res))) {
119*1b191cb5SApple OSS Distributions 			sprintf(error, "page still readable");
120*1b191cb5SApple OSS Distributions 			return FALSE;
121*1b191cb5SApple OSS Distributions 		}
122*1b191cb5SApple OSS Distributions 	}
123*1b191cb5SApple OSS Distributions 	return TRUE;
124*1b191cb5SApple OSS Distributions }
125*1b191cb5SApple OSS Distributions 
126*1b191cb5SApple OSS Distributions boolean_t
check_w(mach_vm_address_t addr,mach_vm_size_t size)127*1b191cb5SApple OSS Distributions check_w(mach_vm_address_t addr, mach_vm_size_t size)
128*1b191cb5SApple OSS Distributions {
129*1b191cb5SApple OSS Distributions 	char *data = (char*)(uintptr_t)addr;
130*1b191cb5SApple OSS Distributions 	int i, sig;
131*1b191cb5SApple OSS Distributions 
132*1b191cb5SApple OSS Distributions 	if ((sig = setjmp(resume)) != 0) {
133*1b191cb5SApple OSS Distributions 		sprintf(error, "%s when writing", signame[sig]);
134*1b191cb5SApple OSS Distributions 		return FALSE;
135*1b191cb5SApple OSS Distributions 	}
136*1b191cb5SApple OSS Distributions 
137*1b191cb5SApple OSS Distributions 	for (i = 0; i < size; i++) {
138*1b191cb5SApple OSS Distributions 		(data)[i] = i & 0xFF;
139*1b191cb5SApple OSS Distributions 	}
140*1b191cb5SApple OSS Distributions 
141*1b191cb5SApple OSS Distributions 	return TRUE;
142*1b191cb5SApple OSS Distributions }
143*1b191cb5SApple OSS Distributions 
144*1b191cb5SApple OSS Distributions boolean_t
check_nw(mach_vm_address_t addr,mach_vm_size_t size)145*1b191cb5SApple OSS Distributions check_nw(mach_vm_address_t addr, mach_vm_size_t size)
146*1b191cb5SApple OSS Distributions {
147*1b191cb5SApple OSS Distributions 	int i;
148*1b191cb5SApple OSS Distributions 	boolean_t ret;
149*1b191cb5SApple OSS Distributions 
150*1b191cb5SApple OSS Distributions 	for (i = 0; i < size / PAGE_SIZE; i++) {
151*1b191cb5SApple OSS Distributions 		if ((ret = check_w(addr + i * PAGE_SIZE, PAGE_SIZE))) {
152*1b191cb5SApple OSS Distributions 			sprintf(error, "page still writable");
153*1b191cb5SApple OSS Distributions 			return FALSE;
154*1b191cb5SApple OSS Distributions 		}
155*1b191cb5SApple OSS Distributions 	}
156*1b191cb5SApple OSS Distributions 	return TRUE;
157*1b191cb5SApple OSS Distributions }
158*1b191cb5SApple OSS Distributions 
159*1b191cb5SApple OSS Distributions boolean_t
check_rw(mach_vm_address_t addr,mach_vm_size_t size)160*1b191cb5SApple OSS Distributions check_rw(mach_vm_address_t addr, mach_vm_size_t size)
161*1b191cb5SApple OSS Distributions {
162*1b191cb5SApple OSS Distributions 	int ret;
163*1b191cb5SApple OSS Distributions 	int res;
164*1b191cb5SApple OSS Distributions 	if (!(ret = check_w(addr, size))) {
165*1b191cb5SApple OSS Distributions 		return ret;
166*1b191cb5SApple OSS Distributions 	}
167*1b191cb5SApple OSS Distributions 	if (!(ret = check_r(addr, size, &res))) {
168*1b191cb5SApple OSS Distributions 		return ret;
169*1b191cb5SApple OSS Distributions 	}
170*1b191cb5SApple OSS Distributions 	if ((size == SUPERPAGE_SIZE) && (res != 0xfff00000)) {
171*1b191cb5SApple OSS Distributions 		sprintf(error, "checksum error");
172*1b191cb5SApple OSS Distributions 		return FALSE;
173*1b191cb5SApple OSS Distributions 	}
174*1b191cb5SApple OSS Distributions 
175*1b191cb5SApple OSS Distributions 	return TRUE;
176*1b191cb5SApple OSS Distributions }
177*1b191cb5SApple OSS Distributions 
178*1b191cb5SApple OSS Distributions mach_vm_address_t global_addr = 0;
179*1b191cb5SApple OSS Distributions mach_vm_size_t  global_size = 0;
180*1b191cb5SApple OSS Distributions 
181*1b191cb5SApple OSS Distributions /*
182*1b191cb5SApple OSS Distributions  * If we allocate a 2 MB superpage read-write without specifying an address,
183*1b191cb5SApple OSS Distributions  * - the call should succeed
184*1b191cb5SApple OSS Distributions  * - not return 0
185*1b191cb5SApple OSS Distributions  * - return a 2 MB aligned address
186*1b191cb5SApple OSS Distributions  * - the memory should be readable and writable
187*1b191cb5SApple OSS Distributions  */
188*1b191cb5SApple OSS Distributions boolean_t
test_allocate()189*1b191cb5SApple OSS Distributions test_allocate()
190*1b191cb5SApple OSS Distributions {
191*1b191cb5SApple OSS Distributions 	int kr, ret;
192*1b191cb5SApple OSS Distributions 
193*1b191cb5SApple OSS Distributions 	global_addr = 0;
194*1b191cb5SApple OSS Distributions 	global_size = SUPERPAGE_SIZE;
195*1b191cb5SApple OSS Distributions 
196*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &global_addr, global_size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
197*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
198*1b191cb5SApple OSS Distributions 		return ret;
199*1b191cb5SApple OSS Distributions 	}
200*1b191cb5SApple OSS Distributions 	if (!(ret = check_addr0(global_addr, "mach_vm_allocate"))) {
201*1b191cb5SApple OSS Distributions 		return ret;
202*1b191cb5SApple OSS Distributions 	}
203*1b191cb5SApple OSS Distributions 	if (!(ret = check_align(global_addr))) {
204*1b191cb5SApple OSS Distributions 		return ret;
205*1b191cb5SApple OSS Distributions 	}
206*1b191cb5SApple OSS Distributions 	if (!(ret = check_rw(global_addr, global_size))) {
207*1b191cb5SApple OSS Distributions 		return ret;
208*1b191cb5SApple OSS Distributions 	}
209*1b191cb5SApple OSS Distributions 
210*1b191cb5SApple OSS Distributions 	return TRUE;
211*1b191cb5SApple OSS Distributions }
212*1b191cb5SApple OSS Distributions 
213*1b191cb5SApple OSS Distributions /*
214*1b191cb5SApple OSS Distributions  * If we deallocate a superpage,
215*1b191cb5SApple OSS Distributions  * - the call should succeed
216*1b191cb5SApple OSS Distributions  * - make the memory inaccessible
217*1b191cb5SApple OSS Distributions  */
218*1b191cb5SApple OSS Distributions boolean_t
test_deallocate()219*1b191cb5SApple OSS Distributions test_deallocate()
220*1b191cb5SApple OSS Distributions {
221*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
222*1b191cb5SApple OSS Distributions 	int kr, ret;
223*1b191cb5SApple OSS Distributions 
224*1b191cb5SApple OSS Distributions 	if (!global_addr) {
225*1b191cb5SApple OSS Distributions 		sprintf(error, "skipped deallocation");
226*1b191cb5SApple OSS Distributions 		return FALSE;
227*1b191cb5SApple OSS Distributions 	}
228*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), global_addr, global_size);
229*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
230*1b191cb5SApple OSS Distributions 		return ret;
231*1b191cb5SApple OSS Distributions 	}
232*1b191cb5SApple OSS Distributions 	if (!(ret = check_nr(global_addr, size, NULL))) {
233*1b191cb5SApple OSS Distributions 		return ret;
234*1b191cb5SApple OSS Distributions 	}
235*1b191cb5SApple OSS Distributions 	return TRUE;
236*1b191cb5SApple OSS Distributions }
237*1b191cb5SApple OSS Distributions 
238*1b191cb5SApple OSS Distributions /*
239*1b191cb5SApple OSS Distributions  * If we allocate a superpage of any size read-write without specifying an address
240*1b191cb5SApple OSS Distributions  * - the call should succeed
241*1b191cb5SApple OSS Distributions  * - not return 0
242*1b191cb5SApple OSS Distributions  * - the memory should be readable and writable
243*1b191cb5SApple OSS Distributions  * If we deallocate it,
244*1b191cb5SApple OSS Distributions  * - the call should succeed
245*1b191cb5SApple OSS Distributions  * - make the memory inaccessible
246*1b191cb5SApple OSS Distributions  */
247*1b191cb5SApple OSS Distributions boolean_t
test_allocate_size_any()248*1b191cb5SApple OSS Distributions test_allocate_size_any()
249*1b191cb5SApple OSS Distributions {
250*1b191cb5SApple OSS Distributions 	int kr;
251*1b191cb5SApple OSS Distributions 	int ret;
252*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
253*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = 2 * PAGE_SIZE; /* will be rounded up to some superpage size */
254*1b191cb5SApple OSS Distributions 
255*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_ANY);
256*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
257*1b191cb5SApple OSS Distributions 		return ret;
258*1b191cb5SApple OSS Distributions 	}
259*1b191cb5SApple OSS Distributions 	if (!(ret = check_addr0(addr, "mach_vm_allocate"))) {
260*1b191cb5SApple OSS Distributions 		return ret;
261*1b191cb5SApple OSS Distributions 	}
262*1b191cb5SApple OSS Distributions 	if (!(ret = check_rw(addr, size))) {
263*1b191cb5SApple OSS Distributions 		return ret;
264*1b191cb5SApple OSS Distributions 	}
265*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
266*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
267*1b191cb5SApple OSS Distributions 		return ret;
268*1b191cb5SApple OSS Distributions 	}
269*1b191cb5SApple OSS Distributions 	if (!(ret = check_nr(addr, size, NULL))) {
270*1b191cb5SApple OSS Distributions 		return ret;
271*1b191cb5SApple OSS Distributions 	}
272*1b191cb5SApple OSS Distributions 	return TRUE;
273*1b191cb5SApple OSS Distributions }
274*1b191cb5SApple OSS Distributions 
275*1b191cb5SApple OSS Distributions /*
276*1b191cb5SApple OSS Distributions  * If we allocate a 2 MB superpage read-write at a 2 MB aligned address,
277*1b191cb5SApple OSS Distributions  * - the call should succeed
278*1b191cb5SApple OSS Distributions  * - return the address we wished for
279*1b191cb5SApple OSS Distributions  * - the memory should be readable and writable
280*1b191cb5SApple OSS Distributions  * If we deallocate it,
281*1b191cb5SApple OSS Distributions  * - the call should succeed
282*1b191cb5SApple OSS Distributions  * - make the memory inaccessible
283*1b191cb5SApple OSS Distributions  */
284*1b191cb5SApple OSS Distributions boolean_t
test_allocatefixed()285*1b191cb5SApple OSS Distributions test_allocatefixed()
286*1b191cb5SApple OSS Distributions {
287*1b191cb5SApple OSS Distributions 	int kr;
288*1b191cb5SApple OSS Distributions 	int ret;
289*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = FIXED_ADDRESS1;
290*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
291*1b191cb5SApple OSS Distributions 
292*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB);
293*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
294*1b191cb5SApple OSS Distributions 		return ret;
295*1b191cb5SApple OSS Distributions 	}
296*1b191cb5SApple OSS Distributions 	if (!(ret = check_addr(addr, FIXED_ADDRESS1, "mach_vm_allocate"))) {
297*1b191cb5SApple OSS Distributions 		return ret;
298*1b191cb5SApple OSS Distributions 	}
299*1b191cb5SApple OSS Distributions 	if (!(ret = check_rw(addr, size))) {
300*1b191cb5SApple OSS Distributions 		return ret;
301*1b191cb5SApple OSS Distributions 	}
302*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
303*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
304*1b191cb5SApple OSS Distributions 		return ret;
305*1b191cb5SApple OSS Distributions 	}
306*1b191cb5SApple OSS Distributions 	if (!(ret = check_nr(addr, size, NULL))) {
307*1b191cb5SApple OSS Distributions 		return ret;
308*1b191cb5SApple OSS Distributions 	}
309*1b191cb5SApple OSS Distributions 	return TRUE;
310*1b191cb5SApple OSS Distributions }
311*1b191cb5SApple OSS Distributions 
312*1b191cb5SApple OSS Distributions /*
313*1b191cb5SApple OSS Distributions  * If we allocate a 2 MB superpage read-write at an unaligned address,
314*1b191cb5SApple OSS Distributions  * - the call should fail
315*1b191cb5SApple OSS Distributions  */
316*1b191cb5SApple OSS Distributions boolean_t
test_allocateunalignedfixed()317*1b191cb5SApple OSS Distributions test_allocateunalignedfixed()
318*1b191cb5SApple OSS Distributions {
319*1b191cb5SApple OSS Distributions 	int kr;
320*1b191cb5SApple OSS Distributions 	int ret;
321*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = FIXED_ADDRESS2;
322*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
323*1b191cb5SApple OSS Distributions 
324*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB);
325*1b191cb5SApple OSS Distributions 	/* is supposed to fail */
326*1b191cb5SApple OSS Distributions 	if ((ret = check_kr(kr, "mach_vm_allocate"))) {
327*1b191cb5SApple OSS Distributions 		sprintf(error, "mach_vm_allocate() should have failed");
328*1b191cb5SApple OSS Distributions 		return FALSE;
329*1b191cb5SApple OSS Distributions 	}
330*1b191cb5SApple OSS Distributions 	return TRUE;
331*1b191cb5SApple OSS Distributions }
332*1b191cb5SApple OSS Distributions 
333*1b191cb5SApple OSS Distributions /*
334*1b191cb5SApple OSS Distributions  * If we allocate an amount of memory not divisible by 2 MB as a 2 MB superpage
335*1b191cb5SApple OSS Distributions  * - the call should fail
336*1b191cb5SApple OSS Distributions  */
337*1b191cb5SApple OSS Distributions boolean_t
test_allocateoddsize()338*1b191cb5SApple OSS Distributions test_allocateoddsize()
339*1b191cb5SApple OSS Distributions {
340*1b191cb5SApple OSS Distributions 	int kr;
341*1b191cb5SApple OSS Distributions 	int ret;
342*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = FIXED_ADDRESS1;
343*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = PAGE_SIZE; /* != 2 MB */
344*1b191cb5SApple OSS Distributions 
345*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB);
346*1b191cb5SApple OSS Distributions 	/* is supposed to fail */
347*1b191cb5SApple OSS Distributions 	if ((ret = check_kr(kr, "mach_vm_allocate"))) {
348*1b191cb5SApple OSS Distributions 		sprintf(error, "mach_vm_allocate() should have failed");
349*1b191cb5SApple OSS Distributions 		return FALSE;
350*1b191cb5SApple OSS Distributions 	}
351*1b191cb5SApple OSS Distributions 	return TRUE;
352*1b191cb5SApple OSS Distributions }
353*1b191cb5SApple OSS Distributions 
354*1b191cb5SApple OSS Distributions /*
355*1b191cb5SApple OSS Distributions  * If we deallocate a sub-page of a superpage,
356*1b191cb5SApple OSS Distributions  * - the call should succeed
357*1b191cb5SApple OSS Distributions  * - make the complete memory inaccessible
358*1b191cb5SApple OSS Distributions  */
359*1b191cb5SApple OSS Distributions boolean_t
test_deallocatesubpage()360*1b191cb5SApple OSS Distributions test_deallocatesubpage()
361*1b191cb5SApple OSS Distributions {
362*1b191cb5SApple OSS Distributions 	int kr;
363*1b191cb5SApple OSS Distributions 	int ret;
364*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
365*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
366*1b191cb5SApple OSS Distributions 
367*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
368*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
369*1b191cb5SApple OSS Distributions 		return ret;
370*1b191cb5SApple OSS Distributions 	}
371*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr + PAGE_SIZE, size);
372*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
373*1b191cb5SApple OSS Distributions 		return ret;
374*1b191cb5SApple OSS Distributions 	}
375*1b191cb5SApple OSS Distributions 	if (!(ret = check_nr(addr, size, NULL))) {
376*1b191cb5SApple OSS Distributions 		return ret;
377*1b191cb5SApple OSS Distributions 	}
378*1b191cb5SApple OSS Distributions 	return TRUE;
379*1b191cb5SApple OSS Distributions }
380*1b191cb5SApple OSS Distributions 
381*1b191cb5SApple OSS Distributions /*
382*1b191cb5SApple OSS Distributions  * If we try to allocate memory occupied by superpages as normal pages
383*1b191cb5SApple OSS Distributions  * - the call should fail
384*1b191cb5SApple OSS Distributions  */
385*1b191cb5SApple OSS Distributions boolean_t
test_reallocate()386*1b191cb5SApple OSS Distributions test_reallocate()
387*1b191cb5SApple OSS Distributions {
388*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0, addr2;
389*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
390*1b191cb5SApple OSS Distributions 	int kr, ret;
391*1b191cb5SApple OSS Distributions 	int i;
392*1b191cb5SApple OSS Distributions 
393*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
394*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
395*1b191cb5SApple OSS Distributions 		return ret;
396*1b191cb5SApple OSS Distributions 	}
397*1b191cb5SApple OSS Distributions 
398*1b191cb5SApple OSS Distributions 	/* attempt to allocate every sub-page of superpage */
399*1b191cb5SApple OSS Distributions 	for (i = 0; i < SUPERPAGE_SIZE / PAGE_SIZE; i++) {
400*1b191cb5SApple OSS Distributions 		addr2 = addr + i * PAGE_SIZE;
401*1b191cb5SApple OSS Distributions 		size = PAGE_SIZE;
402*1b191cb5SApple OSS Distributions 		kr = mach_vm_allocate(mach_task_self(), &addr2, size, 0);
403*1b191cb5SApple OSS Distributions 		if ((ret = check_kr(kr, "mach_vm_allocate"))) {
404*1b191cb5SApple OSS Distributions 			sprintf(error, "could allocate already allocated space, page %d", i);
405*1b191cb5SApple OSS Distributions 			mach_vm_deallocate(mach_task_self(), addr, size);
406*1b191cb5SApple OSS Distributions 			return FALSE;
407*1b191cb5SApple OSS Distributions 		}
408*1b191cb5SApple OSS Distributions 	}
409*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
410*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
411*1b191cb5SApple OSS Distributions 		return ret;
412*1b191cb5SApple OSS Distributions 	}
413*1b191cb5SApple OSS Distributions 	return TRUE;
414*1b191cb5SApple OSS Distributions }
415*1b191cb5SApple OSS Distributions 
416*1b191cb5SApple OSS Distributions /*
417*1b191cb5SApple OSS Distributions  * If we try to wire superpages
418*1b191cb5SApple OSS Distributions  * - the call should succeed
419*1b191cb5SApple OSS Distributions  * - the memory should remain readable and writable
420*1b191cb5SApple OSS Distributions  */
421*1b191cb5SApple OSS Distributions boolean_t
test_wire()422*1b191cb5SApple OSS Distributions test_wire()
423*1b191cb5SApple OSS Distributions {
424*1b191cb5SApple OSS Distributions 	int kr;
425*1b191cb5SApple OSS Distributions 	int ret;
426*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
427*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
428*1b191cb5SApple OSS Distributions 
429*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
430*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
431*1b191cb5SApple OSS Distributions 		return ret;
432*1b191cb5SApple OSS Distributions 	}
433*1b191cb5SApple OSS Distributions 
434*1b191cb5SApple OSS Distributions 	kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_WRITE | VM_PROT_READ);
435*1b191cb5SApple OSS Distributions 
436*1b191cb5SApple OSS Distributions 	if (!geteuid()) { /* may fail as user */
437*1b191cb5SApple OSS Distributions 		if (!(ret = check_kr(kr, "mach_vm_wire"))) {
438*1b191cb5SApple OSS Distributions 			return ret;
439*1b191cb5SApple OSS Distributions 		}
440*1b191cb5SApple OSS Distributions 	}
441*1b191cb5SApple OSS Distributions 
442*1b191cb5SApple OSS Distributions 	if (!(ret = check_rw(addr, size))) {
443*1b191cb5SApple OSS Distributions 		return ret;
444*1b191cb5SApple OSS Distributions 	}
445*1b191cb5SApple OSS Distributions 
446*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
447*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
448*1b191cb5SApple OSS Distributions 		return ret;
449*1b191cb5SApple OSS Distributions 	}
450*1b191cb5SApple OSS Distributions 
451*1b191cb5SApple OSS Distributions 	return TRUE;
452*1b191cb5SApple OSS Distributions }
453*1b191cb5SApple OSS Distributions 
454*1b191cb5SApple OSS Distributions /*
455*1b191cb5SApple OSS Distributions  * If we try to wire superpages
456*1b191cb5SApple OSS Distributions  * - the call should fail
457*1b191cb5SApple OSS Distributions  * - the memory should remain readable and writable
458*1b191cb5SApple OSS Distributions  * Currently, superpages are always wired.
459*1b191cb5SApple OSS Distributions  */
460*1b191cb5SApple OSS Distributions boolean_t
test_unwire()461*1b191cb5SApple OSS Distributions test_unwire()
462*1b191cb5SApple OSS Distributions {
463*1b191cb5SApple OSS Distributions 	int kr;
464*1b191cb5SApple OSS Distributions 	int ret;
465*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
466*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
467*1b191cb5SApple OSS Distributions 
468*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
469*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
470*1b191cb5SApple OSS Distributions 		return ret;
471*1b191cb5SApple OSS Distributions 	}
472*1b191cb5SApple OSS Distributions 
473*1b191cb5SApple OSS Distributions 	kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_NONE);
474*1b191cb5SApple OSS Distributions 	if ((ret = check_kr(kr, "mach_vm_wire"))) {
475*1b191cb5SApple OSS Distributions 		sprintf(error, "could unwire");
476*1b191cb5SApple OSS Distributions 		return FALSE;
477*1b191cb5SApple OSS Distributions 	}
478*1b191cb5SApple OSS Distributions 
479*1b191cb5SApple OSS Distributions 	if (!(ret = check_rw(addr, size))) {
480*1b191cb5SApple OSS Distributions 		return ret;
481*1b191cb5SApple OSS Distributions 	}
482*1b191cb5SApple OSS Distributions 
483*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
484*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
485*1b191cb5SApple OSS Distributions 		return ret;
486*1b191cb5SApple OSS Distributions 	}
487*1b191cb5SApple OSS Distributions 
488*1b191cb5SApple OSS Distributions 	return TRUE;
489*1b191cb5SApple OSS Distributions }
490*1b191cb5SApple OSS Distributions 
491*1b191cb5SApple OSS Distributions /*
492*1b191cb5SApple OSS Distributions  * If we try to write-protect superpages
493*1b191cb5SApple OSS Distributions  * - the call should succeed
494*1b191cb5SApple OSS Distributions  * - the memory should remain readable
495*1b191cb5SApple OSS Distributions  * - the memory should not be writable
496*1b191cb5SApple OSS Distributions  */
497*1b191cb5SApple OSS Distributions boolean_t
test_readonly()498*1b191cb5SApple OSS Distributions test_readonly()
499*1b191cb5SApple OSS Distributions {
500*1b191cb5SApple OSS Distributions 	int kr;
501*1b191cb5SApple OSS Distributions 	int ret;
502*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
503*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
504*1b191cb5SApple OSS Distributions 
505*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
506*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
507*1b191cb5SApple OSS Distributions 		return ret;
508*1b191cb5SApple OSS Distributions 	}
509*1b191cb5SApple OSS Distributions 
510*1b191cb5SApple OSS Distributions 	mach_vm_protect(mach_task_self(), addr, size, 0, VM_PROT_READ);
511*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_protect"))) {
512*1b191cb5SApple OSS Distributions 		return ret;
513*1b191cb5SApple OSS Distributions 	}
514*1b191cb5SApple OSS Distributions 
515*1b191cb5SApple OSS Distributions 	if (!(ret = check_r(addr, size, NULL))) {
516*1b191cb5SApple OSS Distributions 		return ret;
517*1b191cb5SApple OSS Distributions 	}
518*1b191cb5SApple OSS Distributions 	if (!(ret = check_nw(addr, size))) {
519*1b191cb5SApple OSS Distributions 		return ret;
520*1b191cb5SApple OSS Distributions 	}
521*1b191cb5SApple OSS Distributions 
522*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
523*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
524*1b191cb5SApple OSS Distributions 		return ret;
525*1b191cb5SApple OSS Distributions 	}
526*1b191cb5SApple OSS Distributions 
527*1b191cb5SApple OSS Distributions 	return TRUE;
528*1b191cb5SApple OSS Distributions }
529*1b191cb5SApple OSS Distributions 
530*1b191cb5SApple OSS Distributions /*
531*1b191cb5SApple OSS Distributions  * If we try to write-protect a sub-page of a superpage
532*1b191cb5SApple OSS Distributions  * - the call should succeed
533*1b191cb5SApple OSS Distributions  * - the complete memory should remain readable
534*1b191cb5SApple OSS Distributions  * - the complete memory should not be writable
535*1b191cb5SApple OSS Distributions  */
536*1b191cb5SApple OSS Distributions boolean_t
test_readonlysubpage()537*1b191cb5SApple OSS Distributions test_readonlysubpage()
538*1b191cb5SApple OSS Distributions {
539*1b191cb5SApple OSS Distributions 	int kr;
540*1b191cb5SApple OSS Distributions 	int ret;
541*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
542*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
543*1b191cb5SApple OSS Distributions 
544*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
545*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
546*1b191cb5SApple OSS Distributions 		return ret;
547*1b191cb5SApple OSS Distributions 	}
548*1b191cb5SApple OSS Distributions 
549*1b191cb5SApple OSS Distributions 	mach_vm_protect(mach_task_self(), addr + PAGE_SIZE, PAGE_SIZE, 0, VM_PROT_READ);
550*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_protect"))) {
551*1b191cb5SApple OSS Distributions 		return ret;
552*1b191cb5SApple OSS Distributions 	}
553*1b191cb5SApple OSS Distributions 
554*1b191cb5SApple OSS Distributions 	if (!(ret = check_r(addr, size, NULL))) {
555*1b191cb5SApple OSS Distributions 		return ret;
556*1b191cb5SApple OSS Distributions 	}
557*1b191cb5SApple OSS Distributions 	if (!(ret = check_nw(addr, size))) {
558*1b191cb5SApple OSS Distributions 		return ret;
559*1b191cb5SApple OSS Distributions 	}
560*1b191cb5SApple OSS Distributions 
561*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
562*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
563*1b191cb5SApple OSS Distributions 		return ret;
564*1b191cb5SApple OSS Distributions 	}
565*1b191cb5SApple OSS Distributions 
566*1b191cb5SApple OSS Distributions 	return TRUE;
567*1b191cb5SApple OSS Distributions }
568*1b191cb5SApple OSS Distributions 
569*1b191cb5SApple OSS Distributions /*
570*1b191cb5SApple OSS Distributions  * If we fork with active superpages
571*1b191cb5SApple OSS Distributions  * - the parent should still be able to access the superpages
572*1b191cb5SApple OSS Distributions  * - the child should not be able to access the superpages
573*1b191cb5SApple OSS Distributions  */
574*1b191cb5SApple OSS Distributions boolean_t
test_fork()575*1b191cb5SApple OSS Distributions test_fork()
576*1b191cb5SApple OSS Distributions {
577*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
578*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
579*1b191cb5SApple OSS Distributions 	int kr, ret;
580*1b191cb5SApple OSS Distributions 	pid_t pid;
581*1b191cb5SApple OSS Distributions 
582*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
583*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
584*1b191cb5SApple OSS Distributions 		return ret;
585*1b191cb5SApple OSS Distributions 	}
586*1b191cb5SApple OSS Distributions 
587*1b191cb5SApple OSS Distributions 	fflush(stdout);
588*1b191cb5SApple OSS Distributions 	if ((pid = fork())) { /* parent */
589*1b191cb5SApple OSS Distributions 		if (!(ret = check_rw(addr, size))) {
590*1b191cb5SApple OSS Distributions 			return ret;
591*1b191cb5SApple OSS Distributions 		}
592*1b191cb5SApple OSS Distributions 		waitpid(pid, &ret, 0);
593*1b191cb5SApple OSS Distributions 		if (!ret) {
594*1b191cb5SApple OSS Distributions 			sprintf(error, "child could access superpage");
595*1b191cb5SApple OSS Distributions 			return ret;
596*1b191cb5SApple OSS Distributions 		}
597*1b191cb5SApple OSS Distributions 	} else { /* child */
598*1b191cb5SApple OSS Distributions 		if (!(ret = check_nr(addr, size, NULL))) {
599*1b191cb5SApple OSS Distributions 			exit(ret);
600*1b191cb5SApple OSS Distributions 		}
601*1b191cb5SApple OSS Distributions 		exit(TRUE);
602*1b191cb5SApple OSS Distributions 	}
603*1b191cb5SApple OSS Distributions 
604*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
605*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
606*1b191cb5SApple OSS Distributions 		return ret;
607*1b191cb5SApple OSS Distributions 	}
608*1b191cb5SApple OSS Distributions 	return TRUE;
609*1b191cb5SApple OSS Distributions }
610*1b191cb5SApple OSS Distributions 
611*1b191cb5SApple OSS Distributions /*
612*1b191cb5SApple OSS Distributions  * Doing file I/O with superpages
613*1b191cb5SApple OSS Distributions  * - should succeed
614*1b191cb5SApple OSS Distributions  * - should behave the same as with base pages (i.e. no bad data)
615*1b191cb5SApple OSS Distributions  */
616*1b191cb5SApple OSS Distributions #define FILENAME "/System/Library/Kernels/kernel"
617*1b191cb5SApple OSS Distributions boolean_t
test_fileio()618*1b191cb5SApple OSS Distributions test_fileio()
619*1b191cb5SApple OSS Distributions {
620*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr1 = 0;
621*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr2 = 0;
622*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
623*1b191cb5SApple OSS Distributions 	int kr, ret;
624*1b191cb5SApple OSS Distributions 	int fd;
625*1b191cb5SApple OSS Distributions 	unsigned int bytes;
626*1b191cb5SApple OSS Distributions 
627*1b191cb5SApple OSS Distributions 	/* allocate one superpage */
628*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr1, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
629*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate (1)"))) {
630*1b191cb5SApple OSS Distributions 		return ret;
631*1b191cb5SApple OSS Distributions 	}
632*1b191cb5SApple OSS Distributions 
633*1b191cb5SApple OSS Distributions 	/* allocate base pages (superpage-sized) */
634*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr2, size, VM_FLAGS_ANYWHERE);
635*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate (2)"))) {
636*1b191cb5SApple OSS Distributions 		return ret;
637*1b191cb5SApple OSS Distributions 	}
638*1b191cb5SApple OSS Distributions 
639*1b191cb5SApple OSS Distributions 	if ((fd = open(FILENAME, O_RDONLY)) < 0) {
640*1b191cb5SApple OSS Distributions 		sprintf(error, "couldn't open %s", FILENAME);
641*1b191cb5SApple OSS Distributions 		return FALSE;
642*1b191cb5SApple OSS Distributions 	}
643*1b191cb5SApple OSS Distributions 	fcntl(fd, F_NOCACHE, 1);
644*1b191cb5SApple OSS Distributions 	/* read kernel into superpage */
645*1b191cb5SApple OSS Distributions 	if ((bytes = read(fd, (void*)(uintptr_t)addr1, SUPERPAGE_SIZE)) < SUPERPAGE_SIZE) {
646*1b191cb5SApple OSS Distributions 		sprintf(error, "short read (1)");
647*1b191cb5SApple OSS Distributions 		return FALSE;
648*1b191cb5SApple OSS Distributions 	}
649*1b191cb5SApple OSS Distributions 	lseek(fd, 0, SEEK_SET);
650*1b191cb5SApple OSS Distributions 	/* read kernel into base pages */
651*1b191cb5SApple OSS Distributions 	if ((bytes = read(fd, (void*)(uintptr_t)addr2, SUPERPAGE_SIZE)) < SUPERPAGE_SIZE) {
652*1b191cb5SApple OSS Distributions 		sprintf(error, "short read (2)");
653*1b191cb5SApple OSS Distributions 		return FALSE;
654*1b191cb5SApple OSS Distributions 	}
655*1b191cb5SApple OSS Distributions 	close(fd);
656*1b191cb5SApple OSS Distributions 
657*1b191cb5SApple OSS Distributions 	/* compare */
658*1b191cb5SApple OSS Distributions 	if (memcmp((void*)(uintptr_t)addr1, (void*)(uintptr_t)addr2, bytes)) {
659*1b191cb5SApple OSS Distributions 		sprintf(error, "read data corrupt");
660*1b191cb5SApple OSS Distributions 		return FALSE;
661*1b191cb5SApple OSS Distributions 	}
662*1b191cb5SApple OSS Distributions 
663*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr1, size);
664*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate (1)"))) {
665*1b191cb5SApple OSS Distributions 		return ret;
666*1b191cb5SApple OSS Distributions 	}
667*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr2, size);
668*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate (2)"))) {
669*1b191cb5SApple OSS Distributions 		return ret;
670*1b191cb5SApple OSS Distributions 	}
671*1b191cb5SApple OSS Distributions 	return TRUE;
672*1b191cb5SApple OSS Distributions }
673*1b191cb5SApple OSS Distributions 
674*1b191cb5SApple OSS Distributions /*
675*1b191cb5SApple OSS Distributions  * The mmap() interface should work just as well!
676*1b191cb5SApple OSS Distributions  */
677*1b191cb5SApple OSS Distributions boolean_t
test_mmap()678*1b191cb5SApple OSS Distributions test_mmap()
679*1b191cb5SApple OSS Distributions {
680*1b191cb5SApple OSS Distributions 	int kr, ret;
681*1b191cb5SApple OSS Distributions 	uintptr_t addr = 0;
682*1b191cb5SApple OSS Distributions 	int size = SUPERPAGE_SIZE;
683*1b191cb5SApple OSS Distributions 
684*1b191cb5SApple OSS Distributions 	addr = (uintptr_t)mmap((void*)addr, size, PROT_READ, MAP_ANON | MAP_PRIVATE, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
685*1b191cb5SApple OSS Distributions 	if (addr == (uintptr_t)MAP_FAILED) {
686*1b191cb5SApple OSS Distributions 		sprintf(error, "mmap()");
687*1b191cb5SApple OSS Distributions 		return FALSE;
688*1b191cb5SApple OSS Distributions 	}
689*1b191cb5SApple OSS Distributions 	if (!(ret = check_addr0(addr, "mach_vm_allocate"))) {
690*1b191cb5SApple OSS Distributions 		return ret;
691*1b191cb5SApple OSS Distributions 	}
692*1b191cb5SApple OSS Distributions 	if (!(ret = check_align(addr))) {
693*1b191cb5SApple OSS Distributions 		return ret;
694*1b191cb5SApple OSS Distributions 	}
695*1b191cb5SApple OSS Distributions 	if (!(ret = check_r(addr, SUPERPAGE_SIZE, NULL))) {
696*1b191cb5SApple OSS Distributions 		return ret;
697*1b191cb5SApple OSS Distributions 	}
698*1b191cb5SApple OSS Distributions 	if (!(ret = check_nw(addr, SUPERPAGE_SIZE))) {
699*1b191cb5SApple OSS Distributions 		return ret;
700*1b191cb5SApple OSS Distributions 	}
701*1b191cb5SApple OSS Distributions 	kr = munmap((void*)addr, size);
702*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "munmap"))) {
703*1b191cb5SApple OSS Distributions 		return ret;
704*1b191cb5SApple OSS Distributions 	}
705*1b191cb5SApple OSS Distributions 	if (!(ret = check_nr(addr, size, NULL))) {
706*1b191cb5SApple OSS Distributions 		return ret;
707*1b191cb5SApple OSS Distributions 	}
708*1b191cb5SApple OSS Distributions 
709*1b191cb5SApple OSS Distributions 	return TRUE;
710*1b191cb5SApple OSS Distributions }
711*1b191cb5SApple OSS Distributions 
712*1b191cb5SApple OSS Distributions /*
713*1b191cb5SApple OSS Distributions  * Tests one allocation/deallocaton cycle; used in a loop this tests for leaks
714*1b191cb5SApple OSS Distributions  */
715*1b191cb5SApple OSS Distributions boolean_t
test_alloc_dealloc()716*1b191cb5SApple OSS Distributions test_alloc_dealloc()
717*1b191cb5SApple OSS Distributions {
718*1b191cb5SApple OSS Distributions 	mach_vm_address_t addr = 0;
719*1b191cb5SApple OSS Distributions 	mach_vm_size_t  size = SUPERPAGE_SIZE;
720*1b191cb5SApple OSS Distributions 	int kr, ret;
721*1b191cb5SApple OSS Distributions 
722*1b191cb5SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
723*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
724*1b191cb5SApple OSS Distributions 		return ret;
725*1b191cb5SApple OSS Distributions 	}
726*1b191cb5SApple OSS Distributions 	if (!(ret = check_addr0(addr, "mach_vm_allocate"))) {
727*1b191cb5SApple OSS Distributions 		return ret;
728*1b191cb5SApple OSS Distributions 	}
729*1b191cb5SApple OSS Distributions 	if (!(ret = check_align(addr))) {
730*1b191cb5SApple OSS Distributions 		return ret;
731*1b191cb5SApple OSS Distributions 	}
732*1b191cb5SApple OSS Distributions 	if (!(ret = check_rw(addr, size))) {
733*1b191cb5SApple OSS Distributions 		return ret;
734*1b191cb5SApple OSS Distributions 	}
735*1b191cb5SApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), addr, size);
736*1b191cb5SApple OSS Distributions 	if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
737*1b191cb5SApple OSS Distributions 		return ret;
738*1b191cb5SApple OSS Distributions 	}
739*1b191cb5SApple OSS Distributions 	return TRUE;
740*1b191cb5SApple OSS Distributions }
741*1b191cb5SApple OSS Distributions 
742*1b191cb5SApple OSS Distributions test_t test[] = {
743*1b191cb5SApple OSS Distributions 	{ "allocate one page anywhere", test_allocate },
744*1b191cb5SApple OSS Distributions 	{ "deallocate a page", test_deallocate },
745*1b191cb5SApple OSS Distributions 	{ "allocate a SIZE_ANY page anywhere", test_allocate_size_any },
746*1b191cb5SApple OSS Distributions 	{ "allocate one page at a fixed address", test_allocatefixed },
747*1b191cb5SApple OSS Distributions 	{ "allocate one page at an unaligned fixed address", test_allocateunalignedfixed },
748*1b191cb5SApple OSS Distributions 	{ "deallocate sub-page", test_deallocatesubpage },
749*1b191cb5SApple OSS Distributions 	{ "allocate already allocated subpage", test_reallocate },
750*1b191cb5SApple OSS Distributions 	{ "wire a page", test_wire },
751*1b191cb5SApple OSS Distributions 	{ "unwire a page", test_unwire },
752*1b191cb5SApple OSS Distributions 	{ "make page readonly", test_readonly },
753*1b191cb5SApple OSS Distributions 	{ "make sub-page readonly", test_readonlysubpage },
754*1b191cb5SApple OSS Distributions 	{ "file I/O", test_fileio },
755*1b191cb5SApple OSS Distributions 	{ "mmap()", test_mmap },
756*1b191cb5SApple OSS Distributions 	{ "fork", test_fork },
757*1b191cb5SApple OSS Distributions };
758*1b191cb5SApple OSS Distributions #define TESTS ((int)(sizeof(test)/sizeof(*test)))
759*1b191cb5SApple OSS Distributions 
760*1b191cb5SApple OSS Distributions boolean_t
testit(int i)761*1b191cb5SApple OSS Distributions testit(int i)
762*1b191cb5SApple OSS Distributions {
763*1b191cb5SApple OSS Distributions 	boolean_t ret;
764*1b191cb5SApple OSS Distributions 
765*1b191cb5SApple OSS Distributions 	error[0] = 0;
766*1b191cb5SApple OSS Distributions 	printf("Test #%d \"%s\"...", i + 1, test[i].description);
767*1b191cb5SApple OSS Distributions 	ret = test[i].fn();
768*1b191cb5SApple OSS Distributions 	if (ret) {
769*1b191cb5SApple OSS Distributions 		printf("OK\n");
770*1b191cb5SApple OSS Distributions 	} else {
771*1b191cb5SApple OSS Distributions 		printf("FAILED!");
772*1b191cb5SApple OSS Distributions 		if (error[0]) {
773*1b191cb5SApple OSS Distributions 			printf(" (%s)\n", error);
774*1b191cb5SApple OSS Distributions 		} else {
775*1b191cb5SApple OSS Distributions 			printf("\n");
776*1b191cb5SApple OSS Distributions 		}
777*1b191cb5SApple OSS Distributions 	}
778*1b191cb5SApple OSS Distributions }
779*1b191cb5SApple OSS Distributions 
780*1b191cb5SApple OSS Distributions int
main(int argc,char ** argv)781*1b191cb5SApple OSS Distributions main(int argc, char **argv)
782*1b191cb5SApple OSS Distributions {
783*1b191cb5SApple OSS Distributions 	int i;
784*1b191cb5SApple OSS Distributions 	uint64_t time1, time2;
785*1b191cb5SApple OSS Distributions 
786*1b191cb5SApple OSS Distributions 	int mode = 0;
787*1b191cb5SApple OSS Distributions 	if (argc > 1) {
788*1b191cb5SApple OSS Distributions 		if (!strcmp(argv[1], "-h")) {
789*1b191cb5SApple OSS Distributions 			printf("Usage: %s <mode>\n", argv[0]);
790*1b191cb5SApple OSS Distributions 			printf("\tmode = 0:  test all cases\n");
791*1b191cb5SApple OSS Distributions 			printf("\tmode = -1: allocate/deallocate until failure\n");
792*1b191cb5SApple OSS Distributions 			printf("\tmode > 0:  run test <tmode>\n");
793*1b191cb5SApple OSS Distributions 			exit(0);
794*1b191cb5SApple OSS Distributions 		}
795*1b191cb5SApple OSS Distributions 		mode = atoi(argv[1]);
796*1b191cb5SApple OSS Distributions 	}
797*1b191cb5SApple OSS Distributions 
798*1b191cb5SApple OSS Distributions 	/* install SIGBUS handler */
799*1b191cb5SApple OSS Distributions 	struct sigaction my_sigaction;
800*1b191cb5SApple OSS Distributions 	my_sigaction.sa_handler = test_signal_handler;
801*1b191cb5SApple OSS Distributions 	my_sigaction.sa_flags = SA_RESTART;
802*1b191cb5SApple OSS Distributions 	my_sigaction.sa_mask = 0;
803*1b191cb5SApple OSS Distributions 	sigaction( SIGBUS, &my_sigaction, NULL );
804*1b191cb5SApple OSS Distributions 	sigaction( SIGSEGV, &my_sigaction, NULL );
805*1b191cb5SApple OSS Distributions 
806*1b191cb5SApple OSS Distributions 	if (mode > 0) {           /* one specific test */
807*1b191cb5SApple OSS Distributions 		testit(mode - 1);
808*1b191cb5SApple OSS Distributions 	}
809*1b191cb5SApple OSS Distributions 
810*1b191cb5SApple OSS Distributions 	if (mode == 0) {  /* test all cases */
811*1b191cb5SApple OSS Distributions 		printf("Running %d tests:\n", TESTS);
812*1b191cb5SApple OSS Distributions 		for (i = 0; i < TESTS; i++) {
813*1b191cb5SApple OSS Distributions 			testit(i);
814*1b191cb5SApple OSS Distributions 		}
815*1b191cb5SApple OSS Distributions 	}
816*1b191cb5SApple OSS Distributions 	if (mode == -1) { /* alloc/dealloc */
817*1b191cb5SApple OSS Distributions 		boolean_t ret;
818*1b191cb5SApple OSS Distributions 		do {
819*1b191cb5SApple OSS Distributions 			ret = test_alloc_dealloc(TRUE);
820*1b191cb5SApple OSS Distributions 			printf(".");
821*1b191cb5SApple OSS Distributions 			fflush(stdout);
822*1b191cb5SApple OSS Distributions 		} while (ret);
823*1b191cb5SApple OSS Distributions 		if (error[0]) {
824*1b191cb5SApple OSS Distributions 			printf(" (%s)\n", error);
825*1b191cb5SApple OSS Distributions 		}
826*1b191cb5SApple OSS Distributions 	}
827*1b191cb5SApple OSS Distributions 	return 0;
828*1b191cb5SApple OSS Distributions }
829