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