]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/superpages/testsp.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / tools / tests / superpages / testsp.c
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 */
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
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
30 char error[100];
31
32 jmp_buf resume;
33 void test_signal_handler(int signo)
34 {
35 longjmp(resume, signo);
36 }
37
38 char *signame[32] = {
39 [SIGBUS] "SIGBUS",
40 [SIGSEGV] "SIGSEGV"
41 };
42
43 typedef struct {
44 char *description;
45 boolean_t (*fn)();
46 } test_t;
47
48 boolean_t
49 check_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
57 boolean_t
58 check_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
66 boolean_t
67 check_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
75 boolean_t
76 check_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
84 boolean_t
85 check_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 */
104 boolean_t
105 check_nr(mach_vm_address_t addr, mach_vm_size_t size, int *res) {
106 int i;
107 boolean_t ret;
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
117 boolean_t
118 check_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
133 boolean_t
134 check_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
147 boolean_t
148 check_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;
153 if ((size==SUPERPAGE_SIZE) && (res!=0xfff00000)) {
154 sprintf(error, "checksum error");
155 return FALSE;
156 }
157
158 return TRUE;
159 }
160
161 mach_vm_address_t global_addr = 0;
162 mach_vm_size_t global_size = 0;
163
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 */
171 boolean_t
172 test_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);
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
187 /*
188 * If we deallocate a superpage,
189 * - the call should succeed
190 * - make the memory inaccessible
191 */
192 boolean_t
193 test_deallocate() {
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;
203 if (!(ret = check_nr(global_addr, size, NULL))) return ret;
204 return TRUE;
205 }
206
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 */
216 boolean_t
217 test_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 }
232
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 */
242 boolean_t
243 test_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;
251 if (!(ret = check_addr(addr, FIXED_ADDRESS1, "mach_vm_allocate"))) return ret;
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;
255 if (!(ret = check_nr(addr, size, NULL))) return ret;
256 return TRUE;
257 }
258
259 /*
260 * If we allocate a 2 MB superpage read-write at an unaligned address,
261 * - the call should fail
262 */
263 boolean_t
264 test_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);
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 */
283 boolean_t
284 test_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 */
292 if ((ret = check_kr(kr, "mach_vm_allocate"))) {
293 sprintf(error, "mach_vm_allocate() should have failed");
294 return FALSE;
295 }
296 return TRUE;
297 }
298
299 /*
300 * If we deallocate a sub-page of a superpage,
301 * - the call should succeed
302 * - make the complete memory inaccessible
303 */
304 boolean_t
305 test_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;
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
319 /*
320 * If we try to allocate memory occupied by superpages as normal pages
321 * - the call should fail
322 */
323 boolean_t
324 test_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;
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
349 /*
350 * If we try to wire superpages
351 * - the call should succeed
352 * - the memory should remain readable and writable
353 */
354 boolean_t
355 test_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);
362 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
363
364 kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_WRITE | VM_PROT_READ);
365
366 if (!geteuid()) /* may fail as user */
367 if (!(ret = check_kr(kr, "mach_vm_wire"))) return ret;
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
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 */
383 boolean_t
384 test_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;
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
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 */
413 boolean_t
414 test_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;
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
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 */
441 boolean_t
442 test_readonlysubpage() {
443 int kr;
444 int ret;
445 mach_vm_address_t addr = 0;
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;
450
451 mach_vm_protect(mach_task_self(), addr+PAGE_SIZE, PAGE_SIZE, 0, VM_PROT_READ);
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
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 */
468 boolean_t
469 test_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;
477
478 fflush(stdout);
479 if ((pid=fork())) { /* parent */
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 }
486 } else { /* child */
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
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 */
501 #define FILENAME "/System/Library/Kernels/kernel"
502 boolean_t
503 test_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
550 /*
551 * The mmap() interface should work just as well!
552 */
553 boolean_t
554 test_mmap() {
555 int kr, ret;
556 uintptr_t addr = 0;
557 int size = SUPERPAGE_SIZE;
558
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) {
561 sprintf(error, "mmap()");
562 return FALSE;
563 }
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;
571
572 return TRUE;
573 }
574
575 /*
576 * Tests one allocation/deallocaton cycle; used in a loop this tests for leaks
577 */
578 boolean_t
579 test_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
594 test_t test[] = {
595 { "allocate one page anywhere", test_allocate },
596 { "deallocate a page", test_deallocate },
597 { "allocate a SIZE_ANY page anywhere", test_allocate_size_any },
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 },
607 { "mmap()", test_mmap },
608 { "fork", test_fork },
609 };
610 #define TESTS ((int)(sizeof(test)/sizeof(*test)))
611
612 boolean_t
613 testit(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
630 int 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 }