1 #include <darwintest.h> 2 3 #include <errno.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #include <sys/mman.h> 9 10 #include <mach/mach_error.h> 11 #include <mach/mach_init.h> 12 #include <mach/mach_vm.h> 13 14 #define ANON_MAX_PAGES 0xFFFFFFFFULL 15 #define ANON_MAX_SIZE (ANON_MAX_PAGES * vm_kernel_page_size) 16 17 T_DECL(anon_max_size, "Test an ALLOC_MAX_SIZE allocation", 18 T_META_NAMESPACE("xnu.vm"), 19 T_META_RADAR_COMPONENT_NAME("xnu"), 20 T_META_RADAR_COMPONENT_VERSION("VM"), 21 T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), 22 T_META_TAG_VM_PREFERRED) 23 { 24 kern_return_t kr; 25 mach_vm_address_t vm_addr; 26 mach_vm_size_t vm_size; 27 unsigned char *cp; 28 int ret; 29 unsigned char vec; 30 31 /* allocate the largest anonymous size possible */ 32 vm_size = ANON_MAX_SIZE; 33 /* truncate to avoid going over actual max size when rounding up */ 34 vm_size &= ~PAGE_MASK; 35 vm_addr = 0; 36 kr = mach_vm_allocate(mach_task_self(), 37 &vm_addr, 38 vm_size, 39 VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE); 40 if (kr == KERN_NO_SPACE) { 41 T_SKIP("not enough address space..."); 42 } 43 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate(0x%llx)", ANON_MAX_SIZE); 44 45 /* dirty the first and last pages */ 46 cp = (unsigned char *)(uintptr_t)vm_addr; 47 cp[0] = 'a'; 48 cp[vm_size - 1] = 'z'; 49 50 /* trigger the VM compressor for that VM object */ 51 ret = madvise(cp, (size_t)vm_size, MADV_PAGEOUT); 52 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "madvise(MADV_PAGEOUT)"); 53 54 /* wait for the pages to be (asynchronously) compressed */ 55 T_QUIET; T_LOG("waiting for first page to be paged out..."); 56 do { 57 ret = mincore(&cp[0], 1, (char *)&vec); 58 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "mincore(1st)"); 59 } while (vec & MINCORE_INCORE); 60 T_QUIET; T_LOG("waiting for last page to be paged out..."); 61 do { 62 ret = mincore(&cp[vm_size - 1], 1, (char *)&vec); 63 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "mincore(last)"); 64 } while (vec & MINCORE_INCORE); 65 66 /* trigger pageins and check the contents */ 67 T_QUIET; T_ASSERT_EQ(cp[0], 'a', "first page intact"); 68 T_QUIET; T_ASSERT_EQ(cp[vm_size - 1], 'z', "last page intact"); 69 70 /* success */ 71 return; 72 } 73