xref: /xnu-11215.41.3/tests/vm/mmap.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 #include <darwintest.h>
2 #include <mach/mach.h>
3 #include <mach/mach_vm.h>
4 #include <sys/mman.h>
5 #include <sys/param.h>
6 #include <stdlib.h>
7 #include <fcntl.h>
8 
9 extern __typeof__(mmap) __mmap;
10 
11 #define N_INTS    (32 * 1024)
12 #define N_SIZE    (N_INTS * 4)
13 
14 static int
make_temp_fd(void)15 make_temp_fd(void)
16 {
17 	char path[MAXPATHLEN] = "/tmp/mapfile.XXXXXX";
18 	const int batch = 128;
19 	int fd;
20 
21 	T_ASSERT_POSIX_SUCCESS(fd = mkstemp(path), "mkstemp");
22 	T_ASSERT_POSIX_SUCCESS(unlink(path), "unlink");
23 
24 	for (uint32_t i = 1; i <= N_INTS; i += batch) {
25 		uint32_t arr[batch];
26 
27 		for (uint32_t j = 0; j < batch; j++) {
28 			arr[j] = i + j;
29 		}
30 		T_QUIET; T_ASSERT_EQ(write(fd, arr, sizeof(arr)), sizeof(arr), "write");
31 	}
32 
33 	return fd;
34 }
35 
36 #define K(n) ((n) << 10)
37 
38 static struct mmap_spec {
39 	int             prot;
40 	int             flags;
41 	uint32_t        offs;
42 	uint32_t        size;
43 } specs[] = {
44 	{ PROT_READ, MAP_PRIVATE, K(0), N_SIZE - K(0)  },
45 	{ PROT_READ, MAP_PRIVATE, K(1), N_SIZE - K(1)  },
46 	{ PROT_READ, MAP_PRIVATE, K(4), N_SIZE - K(4)  },
47 	{ PROT_READ, MAP_PRIVATE, K(8), N_SIZE - K(8)  },
48 	{ PROT_READ, MAP_PRIVATE, K(16), N_SIZE - K(16) },
49 	{ PROT_READ, MAP_PRIVATE, K(32), N_SIZE - K(32) },
50 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(0), N_SIZE - K(0)  },
51 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(1), N_SIZE - K(1)  },
52 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(4), N_SIZE - K(4)  },
53 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(8), N_SIZE - K(8)  },
54 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16), N_SIZE - K(16) },
55 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(32), N_SIZE - K(32) },
56 
57 	{ PROT_READ, MAP_PRIVATE, K(16) + K(0), K(16) },
58 	{ PROT_READ, MAP_PRIVATE, K(16) + K(1), K(16) },
59 	{ PROT_READ, MAP_PRIVATE, K(16) + K(4), K(16) },
60 	{ PROT_READ, MAP_PRIVATE, K(16) + K(8), K(16) },
61 	{ PROT_READ, MAP_PRIVATE, K(16) + K(16), K(16) },
62 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(0), K(16) },
63 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(1), K(16) },
64 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(4), K(16) },
65 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(8), K(16) },
66 	{ PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(16), K(16) },
67 
68 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(0), N_SIZE - K(0)  },
69 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(1), N_SIZE - K(1)  },
70 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(4), N_SIZE - K(4)  },
71 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(8), N_SIZE - K(8)  },
72 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16), N_SIZE - K(16) },
73 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(32), N_SIZE - K(32) },
74 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(0), N_SIZE - K(0)  },
75 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(1), N_SIZE - K(1)  },
76 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(4), N_SIZE - K(4)  },
77 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(8), N_SIZE - K(8)  },
78 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16), N_SIZE - K(16) },
79 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(32), N_SIZE - K(32) },
80 
81 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(0), K(16) },
82 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(1), K(16) },
83 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(4), K(16) },
84 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(8), K(16) },
85 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(16), K(16) },
86 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(0), K(16) },
87 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(1), K(16) },
88 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(4), K(16) },
89 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(8), K(16) },
90 	{ PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(16), K(16) },
91 	{ ~0 }
92 };
93 
94 T_DECL(mmap_unaligned, "basic testing of mmap with various sizes and alignments")
95 {
96 	vm_region_basic_info_data_64_t info;
97 	mach_msg_type_number_t         icount = VM_REGION_BASIC_INFO_COUNT_64;
98 	mach_vm_address_t              f_addr, r_addr;
99 	mach_vm_size_t                 f_size, r_size;
100 	uint32_t                       delta, size;
101 	uint32_t                      *p, *want_p;
102 	kern_return_t                  kr;
103 	int                            fd;
104 
105 	fd = make_temp_fd();
106 
107 	for (struct mmap_spec *it = specs; it->prot != ~0; it++) {
108 		T_LOG("mmap(NULL, prot=%#x, flags=%#x, fd=%d, offs=%d, size=%d)",
109 		    it->prot, it->flags, fd, it->offs, it->size);
110 
111 		if (it->flags & MAP_FIXED) {
112 			f_size = PAGE_SIZE * 2 + it->size;
113 			kr = mach_vm_allocate(mach_task_self(), &f_addr, f_size,
114 			    VM_FLAGS_ANYWHERE);
115 			T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "allocate VA");
116 			want_p = (uint32_t *)(f_addr + PAGE_SIZE +
117 			    (it->offs & PAGE_MASK));
118 		} else {
119 			f_addr = 0;
120 			f_size = 0;
121 			want_p = NULL;
122 		}
123 
124 		p = __mmap(want_p, it->size, it->prot, it->flags, fd, it->offs);
125 
126 		if ((it->flags & MAP_UNIX03) && (it->offs & PAGE_MASK)) {
127 			errno_t rc = errno;
128 			T_QUIET; T_EXPECT_EQ((void *)p, MAP_FAILED, "mmap failure");
129 			T_QUIET; T_EXPECT_EQ(rc, EINVAL, "check errno");
130 			continue;
131 		} else if (want_p) {
132 			T_QUIET; T_EXPECT_EQ((void *)p, want_p, "mmap success");
133 		} else {
134 			T_QUIET; T_EXPECT_NE((void *)p, MAP_FAILED, "mmap success");
135 		}
136 		T_QUIET; T_EXPECT_EQ((uint32_t)p & PAGE_MASK, it->offs & PAGE_MASK,
137 		    "check offset");
138 
139 		delta = it->offs & PAGE_MASK;
140 		size  = (delta + it->size + PAGE_MASK) & ~PAGE_MASK;
141 		r_addr = (vm_offset_t)p;
142 		kr = mach_vm_region(mach_task_self(), &r_addr, &r_size,
143 		    VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &icount,
144 		    &(mach_port_t){0});
145 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "region");
146 		T_QUIET; T_EXPECT_EQ(r_addr, (mach_vm_address_t)p - delta,
147 		    "validate addr");
148 		T_QUIET; T_EXPECT_EQ(r_size, (mach_vm_size_t)size,
149 		    "validate size");
150 
151 		for (uint32_t i = 0; i < it->size / 4; i += PAGE_SIZE / 4) {
152 			T_QUIET; T_EXPECT_EQ(p[i], it->offs / 4 + i + 1u,
153 			    "check value");
154 		}
155 
156 		if (f_addr) {
157 			kr = mach_vm_deallocate(mach_task_self(), f_addr, f_size);
158 			T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "deallocate VA");
159 		} else {
160 			/* mmap doesn't allow misaligned things ... */
161 			p    -= delta / 4;
162 			T_QUIET; T_EXPECT_POSIX_SUCCESS(munmap(p, size), 0,
163 			    "munmap(%p, %d)", p, size);
164 		}
165 	}
166 }
167