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