]> git.saurik.com Git - apple/xnu.git/blob - bsd/tests/bsd_tests.c
3a3622fc781d3d2a3ec20470a4869891537fc858
[apple/xnu.git] / bsd / tests / bsd_tests.c
1 /*
2 * Copyright (c) 2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <tests/ktest.h>
30 #include <tests/xnupost.h>
31 #include <kern/assert.h>
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/types.h>
35 #include <sys/kdebug.h>
36 #include <libkern/libkern.h>
37 #include <kern/kalloc.h>
38 #include <sys/cdefs.h>
39 #include <libkern/version.h>
40 #include <kern/clock.h>
41 #include <kern/kern_cdata.h>
42 #include <pexpert/pexpert.h>
43
44
45 #if !(DEVELOPMENT || DEBUG)
46 #error "Testing is not enabled on RELEASE configurations"
47 #endif
48
49 #ifdef __arm64__
50 extern kern_return_t arm64_lock_test(void);
51 #endif
52 kern_return_t kalloc_test(void);
53 kern_return_t ipi_test(void);
54 #if __ARM_PAN_AVAILABLE__
55 extern kern_return_t arm64_late_pan_test(void);
56 #endif
57 #if HAS_TWO_STAGE_SPR_LOCK
58 extern kern_return_t arm64_spr_lock_test(void);
59 #endif
60 extern kern_return_t copyio_test(void);
61
62 struct xnupost_test bsd_post_tests[] = {
63 #ifdef __arm64__
64 XNUPOST_TEST_CONFIG_BASIC(arm64_lock_test),
65 #endif
66 #if __ARM_PAN_AVAILABLE__
67 XNUPOST_TEST_CONFIG_BASIC(arm64_late_pan_test),
68 #endif
69 XNUPOST_TEST_CONFIG_BASIC(kalloc_test),
70 XNUPOST_TEST_CONFIG_BASIC(ipi_test),
71 #if HAS_TWO_STAGE_SPR_LOCK
72 XNUPOST_TEST_CONFIG_BASIC(arm64_spr_lock_test),
73 #endif
74 XNUPOST_TEST_CONFIG_BASIC(copyio_test),
75 };
76
77 uint32_t bsd_post_tests_count = sizeof(bsd_post_tests) / sizeof(xnupost_test_data_t);
78
79 extern uint64_t last_loaded_timestamp; /* updated by OSKext::load() */
80 extern uint64_t kernel_post_args;
81 int
82 bsd_list_tests()
83 {
84 if (kernel_post_args == 0) {
85 return 0;
86 }
87
88 uint64_t prev_load_time = last_loaded_timestamp;
89 int no_load_counter = 5;
90 int absolute_break_counter = 15;
91 int delay_duration_usecs = 300000; /* 0.3 second for kext loading to stabilize */
92
93 while (no_load_counter > 0) {
94 printf("bsd_list_tests:INFO waiting for %d usecs\n", delay_duration_usecs);
95 printf("bsd_list_tests: prev: %llu current: %llu\n", prev_load_time, last_loaded_timestamp);
96
97 delay(delay_duration_usecs);
98 absolute_break_counter -= 1;
99
100 if (absolute_break_counter <= 0) {
101 printf("bsd_list_tests: WARNING: Waiting beyond normal time for stabilizing kext loading\n");
102 break;
103 }
104
105 if (prev_load_time == last_loaded_timestamp) {
106 no_load_counter -= 1;
107 printf("bsd_list_tests: INFO: no new kexts loaded. remaining checks: %d\n", no_load_counter);
108 }
109
110 prev_load_time = last_loaded_timestamp;
111 }
112
113 return xnupost_list_tests(bsd_post_tests, bsd_post_tests_count);
114 }
115
116 int
117 bsd_do_post()
118 {
119 return xnupost_run_tests(bsd_post_tests, bsd_post_tests_count);
120 }
121
122 kern_return_t
123 kalloc_test()
124 {
125 uint64_t * data_ptr;
126 size_t alloc_size;
127
128 T_LOG("Running kalloc test.\n");
129
130 alloc_size = sizeof(uint64_t);
131 data_ptr = kalloc(alloc_size);
132 T_ASSERT_NOTNULL(data_ptr, "kalloc sizeof(uint64_t) return not null");
133 kfree(data_ptr, alloc_size);
134
135 alloc_size = 3544;
136 data_ptr = kalloc(alloc_size);
137 T_ASSERT_NOTNULL(data_ptr, "kalloc 3544 return not null");
138 kfree(data_ptr, alloc_size);
139
140 return KERN_SUCCESS;
141 }
142
143 /* kcdata type definition */
144 #define XNUPOST_TNAME_MAXLEN 132
145
146 struct kcdata_subtype_descriptor kc_xnupost_test_def[] = {
147 {.kcs_flags = KCS_SUBTYPE_FLAGS_NONE, .kcs_elem_type = KC_ST_UINT16, .kcs_elem_offset = 0, .kcs_elem_size = sizeof(uint16_t), .kcs_name = "config"},
148 {.kcs_flags = KCS_SUBTYPE_FLAGS_NONE, .kcs_elem_type = KC_ST_UINT16, .kcs_elem_offset = 1 * sizeof(uint16_t), .kcs_elem_size = sizeof(uint16_t), .kcs_name = "test_num"},
149 {.kcs_flags = KCS_SUBTYPE_FLAGS_NONE, .kcs_elem_type = KC_ST_INT32, .kcs_elem_offset = 2 * sizeof(uint16_t), .kcs_elem_size = sizeof(int32_t), .kcs_name = "retval"},
150 {.kcs_flags = KCS_SUBTYPE_FLAGS_NONE, .kcs_elem_type = KC_ST_INT32, .kcs_elem_offset = 2 * sizeof(uint16_t) + sizeof(int32_t), .kcs_elem_size = sizeof(int32_t), .kcs_name = "expected_retval"},
151 {.kcs_flags = KCS_SUBTYPE_FLAGS_NONE, .kcs_elem_type = KC_ST_UINT64, .kcs_elem_offset = 2 * (sizeof(uint16_t) + sizeof(int32_t)), .kcs_elem_size = sizeof(uint64_t), .kcs_name = "begin_time"},
152 {.kcs_flags = KCS_SUBTYPE_FLAGS_NONE, .kcs_elem_type = KC_ST_UINT64, .kcs_elem_offset = 2 * (sizeof(uint16_t) + sizeof(int32_t)) + sizeof(uint64_t), .kcs_elem_size = sizeof(uint64_t), .kcs_name = "end_time"},
153 {.kcs_flags = KCS_SUBTYPE_FLAGS_ARRAY,
154 .kcs_elem_type = KC_ST_CHAR,
155 .kcs_elem_offset = 2 * (sizeof(uint16_t) + sizeof(int32_t) + sizeof(uint64_t)),
156 .kcs_elem_size = KCS_SUBTYPE_PACK_SIZE(XNUPOST_TNAME_MAXLEN * sizeof(char), sizeof(char)),
157 .kcs_name = "test_name"}
158 };
159
160 const uint32_t kc_xnupost_test_def_count = sizeof(kc_xnupost_test_def) / sizeof(struct kcdata_subtype_descriptor);
161
162 kern_return_t xnupost_copyout_test(xnupost_test_t t, mach_vm_address_t outaddr);
163
164 int
165 xnupost_copyout_test(xnupost_test_t t, mach_vm_address_t outaddr)
166 {
167 /* code to copyout test config */
168 int kret = 0;
169 uint32_t namelen = 0;
170
171 kret = copyout(&t->xt_config, outaddr, sizeof(uint16_t));
172 if (kret) {
173 return kret;
174 }
175 outaddr += sizeof(uint16_t);
176
177 kret = copyout(&t->xt_test_num, outaddr, sizeof(uint16_t));
178 if (kret) {
179 return kret;
180 }
181 outaddr += sizeof(uint16_t);
182
183 kret = copyout(&t->xt_retval, outaddr, sizeof(uint32_t));
184 if (kret) {
185 return kret;
186 }
187 outaddr += sizeof(uint32_t);
188
189 kret = copyout(&t->xt_expected_retval, outaddr, sizeof(uint32_t));
190 if (kret) {
191 return kret;
192 }
193 outaddr += sizeof(uint32_t);
194
195 kret = copyout(&t->xt_begin_time, outaddr, sizeof(uint64_t));
196 if (kret) {
197 return kret;
198 }
199 outaddr += sizeof(uint64_t);
200
201 kret = copyout(&t->xt_end_time, outaddr, sizeof(uint64_t));
202 if (kret) {
203 return kret;
204 }
205 outaddr += sizeof(uint64_t);
206
207 namelen = strnlen(t->xt_name, XNUPOST_TNAME_MAXLEN);
208 kret = copyout(t->xt_name, outaddr, namelen);
209 if (kret) {
210 return kret;
211 }
212 outaddr += namelen;
213
214 return 0;
215 }
216
217 uint32_t
218 xnupost_get_estimated_testdata_size(void)
219 {
220 uint32_t total_tests = bsd_post_tests_count + kernel_post_tests_count;
221 uint32_t elem_size = kc_xnupost_test_def[kc_xnupost_test_def_count - 1].kcs_elem_offset +
222 kcs_get_elem_size(&kc_xnupost_test_def[kc_xnupost_test_def_count - 1]);
223 uint32_t retval = 1024; /* account for type definition and mach timebase */
224 retval += 1024; /* kernel version and boot-args string data */
225 retval += (total_tests * elem_size);
226
227 return retval;
228 }
229
230 int
231 xnupost_export_testdata(void * outp, uint32_t size, uint32_t * lenp)
232 {
233 struct kcdata_descriptor kcd;
234 mach_vm_address_t user_addr = 0;
235 mach_vm_address_t tmp_entry_addr = 0;
236 kern_return_t kret = 0;
237 uint32_t i = 0;
238 char kctype_name[32] = "xnupost_test_config";
239 mach_timebase_info_data_t timebase = {0, 0};
240 uint32_t length_to_copy = 0;
241
242 #define RET_IF_OP_FAIL \
243 do { \
244 if (kret != KERN_SUCCESS) { \
245 return (kret == KERN_NO_ACCESS) ? EACCES : ((kret == KERN_RESOURCE_SHORTAGE) ? ENOMEM : EINVAL); \
246 } \
247 } while (0)
248
249 kret = kcdata_memory_static_init(&kcd, (mach_vm_address_t)outp, KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG, size, KCFLAG_USE_COPYOUT);
250 RET_IF_OP_FAIL;
251
252 /* add mach timebase info */
253 clock_timebase_info(&timebase);
254 kret = kcdata_get_memory_addr(&kcd, KCDATA_TYPE_TIMEBASE, sizeof(timebase), &user_addr);
255 RET_IF_OP_FAIL;
256 kret = copyout(&timebase, user_addr, sizeof(timebase));
257 RET_IF_OP_FAIL;
258
259 /* save boot-args and osversion string */
260 length_to_copy = MIN((uint32_t)(strlen(version) + 1), OSVERSIZE);
261 kret = kcdata_get_memory_addr(&kcd, STACKSHOT_KCTYPE_OSVERSION, length_to_copy, &user_addr);
262 RET_IF_OP_FAIL;
263 kret = copyout(&version[0], user_addr, length_to_copy);
264 RET_IF_OP_FAIL;
265
266 length_to_copy = MIN((uint32_t)(strlen(PE_boot_args()) + 1), OSVERSIZE);
267 kret = kcdata_get_memory_addr(&kcd, STACKSHOT_KCTYPE_BOOTARGS, length_to_copy, &user_addr);
268 RET_IF_OP_FAIL;
269 kret = copyout(PE_boot_args(), user_addr, length_to_copy);
270 RET_IF_OP_FAIL;
271
272 /* add type definition to buffer */
273 kret = kcdata_add_type_definition(&kcd, XNUPOST_KCTYPE_TESTCONFIG, kctype_name, &kc_xnupost_test_def[0],
274 kc_xnupost_test_def_count);
275 RET_IF_OP_FAIL;
276
277 /* add the tests to buffer as array */
278 uint32_t total_tests = bsd_post_tests_count + kernel_post_tests_count;
279 uint32_t elem_size = kc_xnupost_test_def[kc_xnupost_test_def_count - 1].kcs_elem_offset +
280 kcs_get_elem_size(&kc_xnupost_test_def[kc_xnupost_test_def_count - 1]);
281
282 kret = kcdata_get_memory_addr_for_array(&kcd, XNUPOST_KCTYPE_TESTCONFIG, elem_size, total_tests, &user_addr);
283 RET_IF_OP_FAIL;
284
285 for (i = 0; i < bsd_post_tests_count; i++) {
286 tmp_entry_addr = (mach_vm_address_t)((uint64_t)(user_addr) + (uint64_t)(i * elem_size));
287 kret = xnupost_copyout_test(&bsd_post_tests[i], tmp_entry_addr);
288 RET_IF_OP_FAIL;
289 }
290 user_addr = (mach_vm_address_t)((uint64_t)(user_addr) + (uint64_t)(i * elem_size));
291
292 for (i = 0; i < kernel_post_tests_count; i++) {
293 tmp_entry_addr = (mach_vm_address_t)((uint64_t)(user_addr) + (uint64_t)(i * elem_size));
294 kret = xnupost_copyout_test(&kernel_post_tests[i], tmp_entry_addr);
295 RET_IF_OP_FAIL;
296 }
297
298 if (kret == KERN_SUCCESS && lenp != NULL) {
299 *lenp = (uint32_t)kcdata_memory_get_used_bytes(&kcd);
300 }
301 RET_IF_OP_FAIL;
302
303 #undef RET_IF_OP_FAIL
304 return kret;
305 }
306
307 int
308 xnupost_reset_all_tests(void)
309 {
310 xnupost_reset_tests(&bsd_post_tests[0], bsd_post_tests_count);
311 xnupost_reset_tests(&kernel_post_tests[0], kernel_post_tests_count);
312 return 0;
313 }