]> git.saurik.com Git - apple/xnu.git/blame - bsd/tests/bsd_tests.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / tests / bsd_tests.c
CommitLineData
d9a64523 1/*
cb323159 2 * Copyright (c) 2019 Apple Inc. All rights reserved.
d9a64523
A
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__
50extern kern_return_t arm64_lock_test(void);
51#endif
f427ee49
A
52#if defined(__arm__) || defined(__arm64__)
53extern kern_return_t pmap_test(void);
54#endif /* defined(__arm__) || defined(__arm64__) */
d9a64523
A
55kern_return_t kalloc_test(void);
56kern_return_t ipi_test(void);
c6bf4f31
A
57#if defined(KERNEL_INTEGRITY_CTRR)
58extern kern_return_t ctrr_test(void);
59#endif
cb323159
A
60#if __ARM_PAN_AVAILABLE__
61extern kern_return_t arm64_late_pan_test(void);
62#endif
63#if HAS_TWO_STAGE_SPR_LOCK
64extern kern_return_t arm64_spr_lock_test(void);
65#endif
66extern kern_return_t copyio_test(void);
d9a64523
A
67
68struct xnupost_test bsd_post_tests[] = {
69#ifdef __arm64__
70 XNUPOST_TEST_CONFIG_BASIC(arm64_lock_test),
cb323159 71#endif
c3c9b80d 72#if !KASAN // <rdar://71151361>
f427ee49
A
73#if defined(__arm__) || defined(__arm64__)
74 XNUPOST_TEST_CONFIG_BASIC(pmap_test),
75#endif /* defined(__arm__) || defined(__arm64__) */
c6bf4f31
A
76#if defined(KERNEL_INTEGRITY_CTRR)
77 XNUPOST_TEST_CONFIG_BASIC(ctrr_test),
78#endif
cb323159
A
79#if __ARM_PAN_AVAILABLE__
80 XNUPOST_TEST_CONFIG_BASIC(arm64_late_pan_test),
d9a64523 81#endif
c3c9b80d 82#endif /* !KASAN */
d9a64523 83 XNUPOST_TEST_CONFIG_BASIC(kalloc_test),
cb323159
A
84 XNUPOST_TEST_CONFIG_BASIC(ipi_test),
85#if HAS_TWO_STAGE_SPR_LOCK
86 XNUPOST_TEST_CONFIG_BASIC(arm64_spr_lock_test),
87#endif
c3c9b80d 88#if !KASAN
cb323159 89 XNUPOST_TEST_CONFIG_BASIC(copyio_test),
c3c9b80d 90#endif /* KASAN */
d9a64523
A
91};
92
93uint32_t bsd_post_tests_count = sizeof(bsd_post_tests) / sizeof(xnupost_test_data_t);
94
95extern uint64_t last_loaded_timestamp; /* updated by OSKext::load() */
96extern uint64_t kernel_post_args;
97int
98bsd_list_tests()
99{
100 if (kernel_post_args == 0) {
101 return 0;
102 }
103
104 uint64_t prev_load_time = last_loaded_timestamp;
105 int no_load_counter = 5;
106 int absolute_break_counter = 15;
107 int delay_duration_usecs = 300000; /* 0.3 second for kext loading to stabilize */
108
109 while (no_load_counter > 0) {
110 printf("bsd_list_tests:INFO waiting for %d usecs\n", delay_duration_usecs);
111 printf("bsd_list_tests: prev: %llu current: %llu\n", prev_load_time, last_loaded_timestamp);
112
113 delay(delay_duration_usecs);
114 absolute_break_counter -= 1;
115
116 if (absolute_break_counter <= 0) {
117 printf("bsd_list_tests: WARNING: Waiting beyond normal time for stabilizing kext loading\n");
118 break;
119 }
120
121 if (prev_load_time == last_loaded_timestamp) {
122 no_load_counter -= 1;
123 printf("bsd_list_tests: INFO: no new kexts loaded. remaining checks: %d\n", no_load_counter);
124 }
125
126 prev_load_time = last_loaded_timestamp;
127 }
128
129 return xnupost_list_tests(bsd_post_tests, bsd_post_tests_count);
130}
131
132int
133bsd_do_post()
134{
135 return xnupost_run_tests(bsd_post_tests, bsd_post_tests_count);
136}
137
138kern_return_t
139kalloc_test()
140{
141 uint64_t * data_ptr;
142 size_t alloc_size;
143
144 T_LOG("Running kalloc test.\n");
145
146 alloc_size = sizeof(uint64_t);
147 data_ptr = kalloc(alloc_size);
148 T_ASSERT_NOTNULL(data_ptr, "kalloc sizeof(uint64_t) return not null");
149 kfree(data_ptr, alloc_size);
150
151 alloc_size = 3544;
152 data_ptr = kalloc(alloc_size);
153 T_ASSERT_NOTNULL(data_ptr, "kalloc 3544 return not null");
154 kfree(data_ptr, alloc_size);
155
156 return KERN_SUCCESS;
157}
158
159/* kcdata type definition */
160#define XNUPOST_TNAME_MAXLEN 132
161
162struct kcdata_subtype_descriptor kc_xnupost_test_def[] = {
cb323159
A
163 {.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"},
164 {.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"},
165 {.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"},
166 {.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"},
167 {.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"},
168 {.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"},
169 {.kcs_flags = KCS_SUBTYPE_FLAGS_ARRAY,
170 .kcs_elem_type = KC_ST_CHAR,
171 .kcs_elem_offset = 2 * (sizeof(uint16_t) + sizeof(int32_t) + sizeof(uint64_t)),
172 .kcs_elem_size = KCS_SUBTYPE_PACK_SIZE(XNUPOST_TNAME_MAXLEN * sizeof(char), sizeof(char)),
173 .kcs_name = "test_name"}
0a7de745 174};
d9a64523
A
175
176const uint32_t kc_xnupost_test_def_count = sizeof(kc_xnupost_test_def) / sizeof(struct kcdata_subtype_descriptor);
177
178kern_return_t xnupost_copyout_test(xnupost_test_t t, mach_vm_address_t outaddr);
179
180int
181xnupost_copyout_test(xnupost_test_t t, mach_vm_address_t outaddr)
182{
183 /* code to copyout test config */
184 int kret = 0;
f427ee49 185 size_t namelen = 0;
d9a64523 186
f427ee49 187 kret = copyout(&t->xt_config, (user_addr_t)outaddr, sizeof(uint16_t));
0a7de745 188 if (kret) {
d9a64523 189 return kret;
0a7de745 190 }
d9a64523
A
191 outaddr += sizeof(uint16_t);
192
f427ee49 193 kret = copyout(&t->xt_test_num, (user_addr_t)outaddr, sizeof(uint16_t));
0a7de745 194 if (kret) {
d9a64523 195 return kret;
0a7de745 196 }
d9a64523
A
197 outaddr += sizeof(uint16_t);
198
f427ee49 199 kret = copyout(&t->xt_retval, (user_addr_t)outaddr, sizeof(uint32_t));
0a7de745 200 if (kret) {
d9a64523 201 return kret;
0a7de745 202 }
d9a64523
A
203 outaddr += sizeof(uint32_t);
204
f427ee49 205 kret = copyout(&t->xt_expected_retval, (user_addr_t)outaddr, sizeof(uint32_t));
0a7de745 206 if (kret) {
d9a64523 207 return kret;
0a7de745 208 }
d9a64523
A
209 outaddr += sizeof(uint32_t);
210
f427ee49 211 kret = copyout(&t->xt_begin_time, (user_addr_t)outaddr, sizeof(uint64_t));
0a7de745 212 if (kret) {
d9a64523 213 return kret;
0a7de745 214 }
d9a64523
A
215 outaddr += sizeof(uint64_t);
216
f427ee49 217 kret = copyout(&t->xt_end_time, (user_addr_t)outaddr, sizeof(uint64_t));
0a7de745 218 if (kret) {
d9a64523 219 return kret;
0a7de745 220 }
d9a64523
A
221 outaddr += sizeof(uint64_t);
222
223 namelen = strnlen(t->xt_name, XNUPOST_TNAME_MAXLEN);
f427ee49 224 kret = copyout(t->xt_name, (user_addr_t)outaddr, namelen);
0a7de745 225 if (kret) {
d9a64523 226 return kret;
0a7de745 227 }
d9a64523
A
228 outaddr += namelen;
229
230 return 0;
231}
232
233uint32_t
234xnupost_get_estimated_testdata_size(void)
235{
236 uint32_t total_tests = bsd_post_tests_count + kernel_post_tests_count;
237 uint32_t elem_size = kc_xnupost_test_def[kc_xnupost_test_def_count - 1].kcs_elem_offset +
0a7de745 238 kcs_get_elem_size(&kc_xnupost_test_def[kc_xnupost_test_def_count - 1]);
d9a64523
A
239 uint32_t retval = 1024; /* account for type definition and mach timebase */
240 retval += 1024; /* kernel version and boot-args string data */
241 retval += (total_tests * elem_size);
242
243 return retval;
244}
245
246int
f427ee49 247xnupost_export_testdata(void * outp, size_t size_in, uint32_t * lenp)
d9a64523
A
248{
249 struct kcdata_descriptor kcd;
250 mach_vm_address_t user_addr = 0;
251 mach_vm_address_t tmp_entry_addr = 0;
252 kern_return_t kret = 0;
253 uint32_t i = 0;
254 char kctype_name[32] = "xnupost_test_config";
255 mach_timebase_info_data_t timebase = {0, 0};
256 uint32_t length_to_copy = 0;
f427ee49
A
257 unsigned int size = (unsigned int)size_in;
258
259 if (size_in > UINT_MAX) {
260 return ENOSPC;
261 }
d9a64523
A
262
263#define RET_IF_OP_FAIL \
264 do { \
0a7de745
A
265 if (kret != KERN_SUCCESS) { \
266 return (kret == KERN_NO_ACCESS) ? EACCES : ((kret == KERN_RESOURCE_SHORTAGE) ? ENOMEM : EINVAL); \
267 } \
d9a64523
A
268 } while (0)
269
270 kret = kcdata_memory_static_init(&kcd, (mach_vm_address_t)outp, KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG, size, KCFLAG_USE_COPYOUT);
271 RET_IF_OP_FAIL;
272
273 /* add mach timebase info */
274 clock_timebase_info(&timebase);
275 kret = kcdata_get_memory_addr(&kcd, KCDATA_TYPE_TIMEBASE, sizeof(timebase), &user_addr);
276 RET_IF_OP_FAIL;
f427ee49 277 kret = copyout(&timebase, (user_addr_t)user_addr, sizeof(timebase));
d9a64523
A
278 RET_IF_OP_FAIL;
279
280 /* save boot-args and osversion string */
281 length_to_copy = MIN((uint32_t)(strlen(version) + 1), OSVERSIZE);
282 kret = kcdata_get_memory_addr(&kcd, STACKSHOT_KCTYPE_OSVERSION, length_to_copy, &user_addr);
283 RET_IF_OP_FAIL;
f427ee49 284 kret = copyout(&version[0], (user_addr_t)user_addr, length_to_copy);
d9a64523
A
285 RET_IF_OP_FAIL;
286
4ba76501 287 length_to_copy = MIN((uint32_t)(strlen(PE_boot_args()) + 1), BOOT_LINE_LENGTH);
d9a64523
A
288 kret = kcdata_get_memory_addr(&kcd, STACKSHOT_KCTYPE_BOOTARGS, length_to_copy, &user_addr);
289 RET_IF_OP_FAIL;
f427ee49 290 kret = copyout(PE_boot_args(), (user_addr_t)user_addr, length_to_copy);
d9a64523
A
291 RET_IF_OP_FAIL;
292
293 /* add type definition to buffer */
294 kret = kcdata_add_type_definition(&kcd, XNUPOST_KCTYPE_TESTCONFIG, kctype_name, &kc_xnupost_test_def[0],
0a7de745 295 kc_xnupost_test_def_count);
d9a64523
A
296 RET_IF_OP_FAIL;
297
298 /* add the tests to buffer as array */
299 uint32_t total_tests = bsd_post_tests_count + kernel_post_tests_count;
300 uint32_t elem_size = kc_xnupost_test_def[kc_xnupost_test_def_count - 1].kcs_elem_offset +
0a7de745 301 kcs_get_elem_size(&kc_xnupost_test_def[kc_xnupost_test_def_count - 1]);
d9a64523
A
302
303 kret = kcdata_get_memory_addr_for_array(&kcd, XNUPOST_KCTYPE_TESTCONFIG, elem_size, total_tests, &user_addr);
304 RET_IF_OP_FAIL;
305
306 for (i = 0; i < bsd_post_tests_count; i++) {
307 tmp_entry_addr = (mach_vm_address_t)((uint64_t)(user_addr) + (uint64_t)(i * elem_size));
308 kret = xnupost_copyout_test(&bsd_post_tests[i], tmp_entry_addr);
309 RET_IF_OP_FAIL;
310 }
311 user_addr = (mach_vm_address_t)((uint64_t)(user_addr) + (uint64_t)(i * elem_size));
312
313 for (i = 0; i < kernel_post_tests_count; i++) {
314 tmp_entry_addr = (mach_vm_address_t)((uint64_t)(user_addr) + (uint64_t)(i * elem_size));
315 kret = xnupost_copyout_test(&kernel_post_tests[i], tmp_entry_addr);
316 RET_IF_OP_FAIL;
317 }
318
0a7de745 319 if (kret == KERN_SUCCESS && lenp != NULL) {
d9a64523 320 *lenp = (uint32_t)kcdata_memory_get_used_bytes(&kcd);
0a7de745 321 }
d9a64523
A
322 RET_IF_OP_FAIL;
323
324#undef RET_IF_OP_FAIL
325 return kret;
326}
327
328int
329xnupost_reset_all_tests(void)
330{
331 xnupost_reset_tests(&bsd_post_tests[0], bsd_post_tests_count);
332 xnupost_reset_tests(&kernel_post_tests[0], kernel_post_tests_count);
333 return 0;
334}