]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/tests/superpages/testsp.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / tools / tests / superpages / testsp.c
index 97fe85c967ed31c2f358a6a1de80d013577b4f27..018a62583a4ae60e292f98dfa20858a95fe6e93a 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * This tests the Mac OS X Superpage API introduced in 10.7
+ *
+ * Note that most of these calls go through the mach_vm_allocate() interface,
+ * but the actually supported and documented interface is the mmap() one
+ * (see mmap(2)).
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
@@ -12,8 +19,6 @@
 #define SUPERPAGE_SIZE (2*1024*1024)
 #define SUPERPAGE_MASK (-SUPERPAGE_SIZE)
 
-#define MAP_SUPERPAGE          0x2000
-
 #ifdef __LP64__
 #define FIXED_ADDRESS1 (0x100000000ULL+500*1024*1024) /* at 4 GB + 500 MB virtual */
 #define FIXED_ADDRESS2 (0x100000000ULL+502*1024*1024 + 4*1024) /* at 4 GB + 502 MB + 4 KB virtual */
@@ -25,8 +30,9 @@
 char error[100];
 
 jmp_buf resume;
-void test_signal_handler(int signo)
-{       
+void
+test_signal_handler(int signo)
+{
        longjmp(resume, signo);
 }
 
@@ -41,7 +47,8 @@ typedef struct {
 } test_t;
 
 boolean_t
-check_kr(int kr, char *fn) {
+check_kr(int kr, char *fn)
+{
        if (kr) {
                sprintf(error, "%s() returned %d", fn, kr);
                return FALSE;
@@ -50,7 +57,8 @@ check_kr(int kr, char *fn) {
 }
 
 boolean_t
-check_addr0(mach_vm_address_t addr, char *fn) {
+check_addr0(mach_vm_address_t addr, char *fn)
+{
        if (!addr) {
                sprintf(error, "%s() returned address 0", fn);
                return FALSE;
@@ -59,7 +67,8 @@ check_addr0(mach_vm_address_t addr, char *fn) {
 }
 
 boolean_t
-check_addr(mach_vm_address_t addr1, mach_vm_address_t addr2, char *fn) {
+check_addr(mach_vm_address_t addr1, mach_vm_address_t addr2, char *fn)
+{
        if (addr1 != addr2) {
                sprintf(error, "%s() returned address %llx instead of %llx", fn, addr1, addr2);
                return FALSE;
@@ -68,7 +77,8 @@ check_addr(mach_vm_address_t addr1, mach_vm_address_t addr2, char *fn) {
 }
 
 boolean_t
-check_align(mach_vm_address_t addr) {
+check_align(mach_vm_address_t addr)
+{
        if (addr & !SUPERPAGE_MASK) {
                sprintf(error, "address not aligned properly: 0x%llx", addr);
                return FALSE;
@@ -77,32 +87,35 @@ check_align(mach_vm_address_t addr) {
 }
 
 boolean_t
-check_r(mach_vm_address_t addr, mach_vm_size_t size, int *res) {
+check_r(mach_vm_address_t addr, mach_vm_size_t size, int *res)
+{
        volatile char *data = (char*)(uintptr_t)addr;
        int i, sig, test;
-       
+
        if ((sig = setjmp(resume)) != 0) {
                sprintf(error, "%s when reading", signame[sig]);
                return FALSE;
        }
        test = 0;
-       for (i=0; i<size; i++)
+       for (i = 0; i < size; i++) {
                test += (data)[i];
+       }
 
-       if (res)
+       if (res) {
                *res = test;
-       
+       }
+
        return TRUE;
 }
 
 /* check that no subpage of the superpage is readable */
 boolean_t
-check_nr(mach_vm_address_t addr, mach_vm_size_t size, int *res) {
+check_nr(mach_vm_address_t addr, mach_vm_size_t size, int *res)
+{
        int i;
        boolean_t ret;
-//printf("%d\n", __LINE__);    
-       for (i=0; i<size/PAGE_SIZE; i++) {
-               if ((ret = check_r(addr+i*PAGE_SIZE, PAGE_SIZE, res))) {
+       for (i = 0; i < size / PAGE_SIZE; i++) {
+               if ((ret = check_r(addr + i * PAGE_SIZE, PAGE_SIZE, res))) {
                        sprintf(error, "page still readable");
                        return FALSE;
                }
@@ -111,7 +124,8 @@ check_nr(mach_vm_address_t addr, mach_vm_size_t size, int *res) {
 }
 
 boolean_t
-check_w(mach_vm_address_t addr, mach_vm_size_t size) {
+check_w(mach_vm_address_t addr, mach_vm_size_t size)
+{
        char *data = (char*)(uintptr_t)addr;
        int i, sig;
 
@@ -120,19 +134,21 @@ check_w(mach_vm_address_t addr, mach_vm_size_t size) {
                return FALSE;
        }
 
-       for (i=0; i<size; i++)
+       for (i = 0; i < size; i++) {
                (data)[i] = i & 0xFF;
+       }
 
        return TRUE;
 }
 
 boolean_t
-check_nw(mach_vm_address_t addr, mach_vm_size_t size) {
+check_nw(mach_vm_address_t addr, mach_vm_size_t size)
+{
        int i;
        boolean_t ret;
 
-       for (i=0; i<size/PAGE_SIZE; i++) {
-               if ((ret = check_w(addr+i*PAGE_SIZE, PAGE_SIZE))) {
+       for (i = 0; i < size / PAGE_SIZE; i++) {
+               if ((ret = check_w(addr + i * PAGE_SIZE, PAGE_SIZE))) {
                        sprintf(error, "page still writable");
                        return FALSE;
                }
@@ -141,13 +157,17 @@ check_nw(mach_vm_address_t addr, mach_vm_size_t size) {
 }
 
 boolean_t
-check_rw(mach_vm_address_t addr, mach_vm_size_t size) {
+check_rw(mach_vm_address_t addr, mach_vm_size_t size)
+{
        int ret;
        int res;
-       if (!(ret = check_w(addr, size))) return ret;
-       if (!(ret = check_r(addr, size, &res))) return ret;
-//     printf("res = %x\n", res);
-       if ((size==SUPERPAGE_SIZE) && (res!=0xfff00000)) {
+       if (!(ret = check_w(addr, size))) {
+               return ret;
+       }
+       if (!(ret = check_r(addr, size, &res))) {
+               return ret;
+       }
+       if ((size == SUPERPAGE_SIZE) && (res != 0xfff00000)) {
                sprintf(error, "checksum error");
                return FALSE;
        }
@@ -156,30 +176,49 @@ check_rw(mach_vm_address_t addr, mach_vm_size_t size) {
 }
 
 mach_vm_address_t global_addr = 0;
-mach_vm_size_t global_size = 0;
+mach_vm_size_t  global_size = 0;
 
+/*
+ * If we allocate a 2 MB superpage read-write without specifying an address,
+ * - the call should succeed
+ * - not return 0
+ * - return a 2 MB aligned address
+ * - the memory should be readable and writable
+ */
 boolean_t
-test_allocate() {
+test_allocate()
+{
        int kr, ret;
 
        global_addr = 0;
        global_size = SUPERPAGE_SIZE;
-       
+
        kr = mach_vm_allocate(mach_task_self(), &global_addr, global_size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       //printf("%llx", addr);
-       //printf("\n%d\n", __LINE__);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(global_addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(global_addr))) return ret;
-       if (!(ret = check_rw(global_addr, global_size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_addr0(global_addr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_align(global_addr))) {
+               return ret;
+       }
+       if (!(ret = check_rw(global_addr, global_size))) {
+               return ret;
+       }
 
        return TRUE;
 }
 
+/*
+ * If we deallocate a superpage,
+ * - the call should succeed
+ * - make the memory inaccessible
+ */
 boolean_t
-test_deallocate() {
-       mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+test_deallocate()
+{
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
        int kr, ret;
 
        if (!global_addr) {
@@ -187,88 +226,178 @@ test_deallocate() {
                return FALSE;
        }
        kr = mach_vm_deallocate(mach_task_self(), global_addr, global_size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
+       if (!(ret = check_nr(global_addr, size, NULL))) {
+               return ret;
+       }
        return TRUE;
 }
 
+/*
+ * If we allocate a superpage of any size read-write without specifying an address
+ * - the call should succeed
+ * - not return 0
+ * - the memory should be readable and writable
+ * If we deallocate it,
+ * - the call should succeed
+ * - make the memory inaccessible
+ */
+boolean_t
+test_allocate_size_any()
+{
+       int kr;
+       int ret;
+       mach_vm_address_t addr = 0;
+       mach_vm_size_t  size = 2 * PAGE_SIZE; /* will be rounded up to some superpage size */
+
+       kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_ANY);
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_rw(addr, size))) {
+               return ret;
+       }
+       kr = mach_vm_deallocate(mach_task_self(), addr, size);
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
+       if (!(ret = check_nr(addr, size, NULL))) {
+               return ret;
+       }
+       return TRUE;
+}
 
+/*
+ * If we allocate a 2 MB superpage read-write at a 2 MB aligned address,
+ * - the call should succeed
+ * - return the address we wished for
+ * - the memory should be readable and writable
+ * If we deallocate it,
+ * - the call should succeed
+ * - make the memory inaccessible
+ */
 boolean_t
-test_allocatefixed() {
+test_allocatefixed()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = FIXED_ADDRESS1;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
 
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr(addr, FIXED_ADDRESS1, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_addr(addr, FIXED_ADDRESS1, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_rw(addr, size))) {
+               return ret;
+       }
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
+       if (!(ret = check_nr(addr, size, NULL))) {
+               return ret;
+       }
        return TRUE;
 }
 
+/*
+ * If we allocate a 2 MB superpage read-write at an unaligned address,
+ * - the call should fail
+ */
 boolean_t
-test_allocateunalignedfixed() {
+test_allocateunalignedfixed()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = FIXED_ADDRESS2;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
-       
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
+
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB);
-#if 0
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr(addr, FIXED_ADDRESS2 & SUPERPAGE_MASK, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
-       kr = mach_vm_deallocate(mach_task_self(), addr & SUPERPAGE_MASK, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
-#else /* is supposed to fail */
+       /* is supposed to fail */
+       if ((ret = check_kr(kr, "mach_vm_allocate"))) {
+               sprintf(error, "mach_vm_allocate() should have failed");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/*
+ * If we allocate an amount of memory not divisible by 2 MB as a 2 MB superpage
+ * - the call should fail
+ */
+boolean_t
+test_allocateoddsize()
+{
+       int kr;
+       int ret;
+       mach_vm_address_t addr = FIXED_ADDRESS1;
+       mach_vm_size_t  size = PAGE_SIZE; /* != 2 MB */
+
+       kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB);
+       /* is supposed to fail */
        if ((ret = check_kr(kr, "mach_vm_allocate"))) {
                sprintf(error, "mach_vm_allocate() should have failed");
                return FALSE;
        }
-#endif
        return TRUE;
 }
 
+/*
+ * If we deallocate a sub-page of a superpage,
+ * - the call should succeed
+ * - make the complete memory inaccessible
+ */
 boolean_t
-test_deallocatesubpage() {
+test_deallocatesubpage()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
-       
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
+
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
        kr = mach_vm_deallocate(mach_task_self(), addr + PAGE_SIZE, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
-       if (!(ret = check_nr(addr, size, NULL))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
+       if (!(ret = check_nr(addr, size, NULL))) {
+               return ret;
+       }
        return TRUE;
 }
 
+/*
+ * If we try to allocate memory occupied by superpages as normal pages
+ * - the call should fail
+ */
 boolean_t
-test_reallocate() {
+test_reallocate()
+{
        mach_vm_address_t addr = 0, addr2;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
        int kr, ret;
        int i;
 
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
 
        /* attempt to allocate every sub-page of superpage */
-       for (i=0; i<SUPERPAGE_SIZE/PAGE_SIZE; i++) {
-               addr2 = addr + i*PAGE_SIZE;
+       for (i = 0; i < SUPERPAGE_SIZE / PAGE_SIZE; i++) {
+               addr2 = addr + i * PAGE_SIZE;
                size = PAGE_SIZE;
                kr = mach_vm_allocate(mach_task_self(), &addr2, size, 0);
                if ((ret = check_kr(kr, "mach_vm_allocate"))) {
@@ -278,50 +407,68 @@ test_reallocate() {
                }
        }
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
        return TRUE;
 }
 
+/*
+ * If we try to wire superpages
+ * - the call should succeed
+ * - the memory should remain readable and writable
+ */
 boolean_t
-test_wire() {
+test_wire()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
 
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
 
        kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_WRITE | VM_PROT_READ);
 
-       if (kr && geteuid()) /* may fail as user */
-               return TRUE;
-
-       if (!(ret = check_kr(kr, "mach_vm_wire"))) return ret;
+       if (!geteuid()) { /* may fail as user */
+               if (!(ret = check_kr(kr, "mach_vm_wire"))) {
+                       return ret;
+               }
+       }
 
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_rw(addr, size))) {
+               return ret;
+       }
 
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
 
        return TRUE;
 }
 
+/*
+ * If we try to wire superpages
+ * - the call should fail
+ * - the memory should remain readable and writable
+ * Currently, superpages are always wired.
+ */
 boolean_t
-test_unwire() {
+test_unwire()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
 
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
 
        kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_NONE);
        if ((ret = check_kr(kr, "mach_vm_wire"))) {
@@ -329,118 +476,167 @@ test_unwire() {
                return FALSE;
        }
 
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_rw(addr, size))) {
+               return ret;
+       }
 
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
 
        return TRUE;
 }
 
+/*
+ * If we try to write-protect superpages
+ * - the call should succeed
+ * - the memory should remain readable
+ * - the memory should not be writable
+ */
 boolean_t
-test_readonly() {
+test_readonly()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
 
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
 
        mach_vm_protect(mach_task_self(), addr, size, 0, VM_PROT_READ);
-       if (!(ret = check_kr(kr, "mach_vm_protect"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_protect"))) {
+               return ret;
+       }
 
-       if (!(ret = check_r(addr, size, NULL))) return ret;
-       if (!(ret = check_nw(addr, size))) return ret;
+       if (!(ret = check_r(addr, size, NULL))) {
+               return ret;
+       }
+       if (!(ret = check_nw(addr, size))) {
+               return ret;
+       }
 
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
 
        return TRUE;
 }
 
+/*
+ * If we try to write-protect a sub-page of a superpage
+ * - the call should succeed
+ * - the complete memory should remain readable
+ * - the complete memory should not be writable
+ */
 boolean_t
-test_readonlysubpage() {
+test_readonlysubpage()
+{
        int kr;
        int ret;
        mach_vm_address_t addr = 0;
-//     mach_vm_size_t  size = SUPERPAGE_SIZE;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
 
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
 
-       /* changing protection on a single sub-page has to change protection for the whole superpage */
-       /* write protect second page from start */
-//printf("+mach_vm_protect\n");
-       mach_vm_protect(mach_task_self(), addr+PAGE_SIZE, PAGE_SIZE, 0, VM_PROT_READ);
-//printf("-mach_vm_protect\n");
-       if (!(ret = check_kr(kr, "mach_vm_protect"))) return ret;
+       mach_vm_protect(mach_task_self(), addr + PAGE_SIZE, PAGE_SIZE, 0, VM_PROT_READ);
+       if (!(ret = check_kr(kr, "mach_vm_protect"))) {
+               return ret;
+       }
 
-       if (!(ret = check_r(addr, size, NULL))) return ret;
-       if (!(ret = check_nw(addr, size))) return ret;
+       if (!(ret = check_r(addr, size, NULL))) {
+               return ret;
+       }
+       if (!(ret = check_nw(addr, size))) {
+               return ret;
+       }
 
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
 
        return TRUE;
 }
 
+/*
+ * If we fork with active superpages
+ * - the parent should still be able to access the superpages
+ * - the child should not be able to access the superpages
+ */
 boolean_t
-test_fork() {
+test_fork()
+{
        mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
        int kr, ret;
        pid_t pid;
-       
+
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
 
        fflush(stdout);
-       if ((pid=fork())) {
-               if (!(ret = check_rw(addr, size))) return ret;
+       if ((pid = fork())) { /* parent */
+               if (!(ret = check_rw(addr, size))) {
+                       return ret;
+               }
                waitpid(pid, &ret, 0);
                if (!ret) {
                        sprintf(error, "child could access superpage");
                        return ret;
                }
-       } else {
-               /* for the child, the superpage should not be mapped */
-               if (!(ret = check_nr(addr, size, NULL))) exit(ret);
+       } else { /* child */
+               if (!(ret = check_nr(addr, size, NULL))) {
+                       exit(ret);
+               }
                exit(TRUE);
        }
-       
+
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
        return TRUE;
 }
 
-#define FILENAME "/mach_kernel"
+/*
+ * Doing file I/O with superpages
+ * - should succeed
+ * - should behave the same as with base pages (i.e. no bad data)
+ */
+#define FILENAME "/System/Library/Kernels/kernel"
 boolean_t
-test_fileio() {
+test_fileio()
+{
        mach_vm_address_t addr1 = 0;
        mach_vm_address_t addr2 = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
        int kr, ret;
        int fd;
        unsigned int bytes;
-       
+
        /* allocate one superpage */
        kr = mach_vm_allocate(mach_task_self(), &addr1, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate (1)"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate (1)"))) {
+               return ret;
+       }
 
        /* allocate base pages (superpage-sized) */
        kr = mach_vm_allocate(mach_task_self(), &addr2, size, VM_FLAGS_ANYWHERE);
-       if (!(ret = check_kr(kr, "mach_vm_allocate (2)"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate (2)"))) {
+               return ret;
+       }
 
-       if ((fd = open(FILENAME, O_RDONLY))<0) {
+       if ((fd = open(FILENAME, O_RDONLY)) < 0) {
                sprintf(error, "couldn't open %s", FILENAME);
                return FALSE;
        }
@@ -457,7 +653,7 @@ test_fileio() {
                return FALSE;
        }
        close(fd);
-       
+
        /* compare */
        if (memcmp((void*)(uintptr_t)addr1, (void*)(uintptr_t)addr2, bytes)) {
                sprintf(error, "read data corrupt");
@@ -465,60 +661,88 @@ test_fileio() {
        }
 
        kr = mach_vm_deallocate(mach_task_self(), addr1, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate (1)"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate (1)"))) {
+               return ret;
+       }
        kr = mach_vm_deallocate(mach_task_self(), addr2, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate (2)"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate (2)"))) {
+               return ret;
+       }
        return TRUE;
 }
 
-#ifdef MMAP
 /*
- * this tests several things at once:
- * - we pass a non-superpage-aligned address and expect it to be rounded up
- * - we pass a size < SUPERPAGE_SIZE and expect SUPERPAGE_SIZE bytes to be mapped
- * - we set the address range to read-only and make sure it's readable, but not writable
+ * The mmap() interface should work just as well!
  */
 boolean_t
-test_mmap() {
+test_mmap()
+{
        int kr, ret;
-       void *addr = (void*)(1*1024*1024*1024 + 4096); /* 1 GB + base page (i.e. not superpage-aligned) */
-       int size = 4096;
-       
-       addr = mmap(addr, size, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_SUPERPAGE, -1, 0);
-       if (addr == MAP_FAILED) {
+       uintptr_t addr = 0;
+       int size = SUPERPAGE_SIZE;
+
+       addr = (uintptr_t)mmap((void*)addr, size, PROT_READ, MAP_ANON | MAP_PRIVATE, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
+       if (addr == (uintptr_t)MAP_FAILED) {
                sprintf(error, "mmap()");
                return FALSE;
        }
-       if (!(ret = check_align((uintptr_t)addr))) return ret;
-       if (!(ret = check_r((uintptr_t)addr, SUPERPAGE_SIZE, NULL))) return ret;
-       if (!(ret = check_nw((uintptr_t)addr, SUPERPAGE_SIZE))) return ret;
-
-       kr = munmap(addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate (2)"))) return ret;
+       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_align(addr))) {
+               return ret;
+       }
+       if (!(ret = check_r(addr, SUPERPAGE_SIZE, NULL))) {
+               return ret;
+       }
+       if (!(ret = check_nw(addr, SUPERPAGE_SIZE))) {
+               return ret;
+       }
+       kr = munmap((void*)addr, size);
+       if (!(ret = check_kr(kr, "munmap"))) {
+               return ret;
+       }
+       if (!(ret = check_nr(addr, size, NULL))) {
+               return ret;
+       }
 
        return TRUE;
 }
-#endif
 
+/*
+ * Tests one allocation/deallocaton cycle; used in a loop this tests for leaks
+ */
 boolean_t
-test_alloc_dealloc() {
+test_alloc_dealloc()
+{
        mach_vm_address_t addr = 0;
-       mach_vm_size_t  size = SUPERPAGE_SIZE;
+       mach_vm_size_t  size = SUPERPAGE_SIZE;
        int kr, ret;
-       
+
        kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB);
-       if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret;
-       if (!(ret = check_align(addr))) return ret;
-       if (!(ret = check_rw(addr, size))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_addr0(addr, "mach_vm_allocate"))) {
+               return ret;
+       }
+       if (!(ret = check_align(addr))) {
+               return ret;
+       }
+       if (!(ret = check_rw(addr, size))) {
+               return ret;
+       }
        kr = mach_vm_deallocate(mach_task_self(), addr, size);
-       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret;
+       if (!(ret = check_kr(kr, "mach_vm_deallocate"))) {
+               return ret;
+       }
        return TRUE;
 }
 
 test_t test[] = {
        { "allocate one page anywhere", test_allocate },
        { "deallocate a page", test_deallocate },
+       { "allocate a SIZE_ANY page anywhere", test_allocate_size_any },
        { "allocate one page at a fixed address", test_allocatefixed },
        { "allocate one page at an unaligned fixed address", test_allocateunalignedfixed },
        { "deallocate sub-page", test_deallocatesubpage },
@@ -528,37 +752,39 @@ test_t test[] = {
        { "make page readonly", test_readonly },
        { "make sub-page readonly", test_readonlysubpage },
        { "file I/O", test_fileio },
-#ifdef MMAP
        { "mmap()", test_mmap },
-#endif
        { "fork", test_fork },
 };
 #define TESTS ((int)(sizeof(test)/sizeof(*test)))
 
 boolean_t
-testit(int i) {
+testit(int i)
+{
        boolean_t ret;
 
        error[0] = 0;
-       printf ("Test #%d \"%s\"...", i+1, test[i].description);
+       printf("Test #%d \"%s\"...", i + 1, test[i].description);
        ret = test[i].fn();
-       if (ret)
-               printf ("OK\n");
-       else {
-               printf ("FAILED!");
-               if (error[0])
-                       printf (" (%s)\n", error);
-               else
-                       printf ("\n");
+       if (ret) {
+               printf("OK\n");
+       } else {
+               printf("FAILED!");
+               if (error[0]) {
+                       printf(" (%s)\n", error);
+               } else {
+                       printf("\n");
+               }
        }
 }
 
-int main(int argc, char **argv) {
+int
+main(int argc, char **argv)
+{
        int i;
        uint64_t time1, time2;
 
        int mode = 0;
-       if (argc>1) {
+       if (argc > 1) {
                if (!strcmp(argv[1], "-h")) {
                        printf("Usage: %s <mode>\n", argv[0]);
                        printf("\tmode = 0:  test all cases\n");
@@ -566,9 +792,9 @@ int main(int argc, char **argv) {
                        printf("\tmode > 0:  run test <tmode>\n");
                        exit(0);
                }
-               mode=atoi(argv[1]);
+               mode = atoi(argv[1]);
        }
-       
+
        /* install SIGBUS handler */
        struct sigaction my_sigaction;
        my_sigaction.sa_handler = test_signal_handler;
@@ -576,25 +802,27 @@ int main(int argc, char **argv) {
        my_sigaction.sa_mask = 0;
        sigaction( SIGBUS, &my_sigaction, NULL );
        sigaction( SIGSEGV, &my_sigaction, NULL );
-       
-       if (mode>0)             /* one specific test */
-               testit(mode-1);
 
-       if (mode==0) {  /* test all cases */
+       if (mode > 0) {           /* one specific test */
+               testit(mode - 1);
+       }
+
+       if (mode == 0) {  /* test all cases */
                printf("Running %d tests:\n", TESTS);
-               for (i=0; i<TESTS; i++) {
+               for (i = 0; i < TESTS; i++) {
                        testit(i);
                }
        }
-       if (mode==-1) { /* alloc/dealloc */
-                       boolean_t ret;
+       if (mode == -1) { /* alloc/dealloc */
+               boolean_t ret;
                do {
                        ret = test_alloc_dealloc(TRUE);
                        printf(".");
                        fflush(stdout);
                } while (ret);
-               if (error[0])
-                       printf (" (%s)\n", error);
+               if (error[0]) {
+                       printf(" (%s)\n", error);
+               }
        }
        return 0;
 }