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 { 23 kern_return_t kr; 24 mach_vm_address_t vm_addr; 25 mach_vm_size_t vm_size; 26 unsigned char *cp; 27 int ret; 28 unsigned char vec; 29 30 /* allocate the largest anonymous size possible */ 31 vm_size = ANON_MAX_SIZE; 32 /* truncate to avoid going over actual max size when rounding up */ 33 vm_size &= ~PAGE_MASK; 34 vm_addr = 0; 35 kr = mach_vm_allocate(mach_task_self(), 36 &vm_addr, 37 vm_size, 38 VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE); 39 if (kr == KERN_NO_SPACE) { 40 T_SKIP("not enough address space..."); 41 } 42 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate(0x%llx)", ANON_MAX_SIZE); 43 44 /* dirty the first and last pages */ 45 cp = (unsigned char *)(uintptr_t)vm_addr; 46 cp[0] = 'a'; 47 cp[vm_size - 1] = 'z'; 48 49 /* trigger the VM compressor for that VM object */ 50 ret = madvise(cp, (size_t)vm_size, MADV_PAGEOUT); 51 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "madvise(MADV_PAGEOUT)"); 52 53 /* wait for the pages to be (asynchronously) compressed */ 54 T_QUIET; T_LOG("waiting for first page to be paged out..."); 55 do { 56 ret = mincore(&cp[0], 1, (char *)&vec); 57 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "mincore(1st)"); 58 } while (vec & MINCORE_INCORE); 59 T_QUIET; T_LOG("waiting for last page to be paged out..."); 60 do { 61 ret = mincore(&cp[vm_size - 1], 1, (char *)&vec); 62 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "mincore(last)"); 63 } while (vec & MINCORE_INCORE); 64 65 /* trigger pageins and check the contents */ 66 T_QUIET; T_ASSERT_EQ(cp[0], 'a', "first page intact"); 67 T_QUIET; T_ASSERT_EQ(cp[vm_size - 1], 'z', "last page intact"); 68 69 /* success */ 70 return; 71 } 72