2 * Copyright (c) 2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
45 #if !(DEVELOPMENT || DEBUG)
46 #error "Testing is not enabled on RELEASE configurations"
50 extern kern_return_t
arm64_lock_test(void);
52 #if defined(__arm__) || defined(__arm64__)
53 extern kern_return_t
pmap_test(void);
54 #endif /* defined(__arm__) || defined(__arm64__) */
55 kern_return_t
kalloc_test(void);
56 kern_return_t
ipi_test(void);
57 #if defined(KERNEL_INTEGRITY_CTRR)
58 extern kern_return_t
ctrr_test(void);
60 #if __ARM_PAN_AVAILABLE__
61 extern kern_return_t
arm64_late_pan_test(void);
63 #if HAS_TWO_STAGE_SPR_LOCK
64 extern kern_return_t
arm64_spr_lock_test(void);
66 extern kern_return_t
copyio_test(void);
68 struct xnupost_test bsd_post_tests
[] = {
70 XNUPOST_TEST_CONFIG_BASIC(arm64_lock_test
),
72 #if !KASAN // <rdar://71151361>
73 #if defined(__arm__) || defined(__arm64__)
74 XNUPOST_TEST_CONFIG_BASIC(pmap_test
),
75 #endif /* defined(__arm__) || defined(__arm64__) */
76 #if defined(KERNEL_INTEGRITY_CTRR)
77 XNUPOST_TEST_CONFIG_BASIC(ctrr_test
),
79 #if __ARM_PAN_AVAILABLE__
80 XNUPOST_TEST_CONFIG_BASIC(arm64_late_pan_test
),
83 XNUPOST_TEST_CONFIG_BASIC(kalloc_test
),
84 XNUPOST_TEST_CONFIG_BASIC(ipi_test
),
85 #if HAS_TWO_STAGE_SPR_LOCK
86 XNUPOST_TEST_CONFIG_BASIC(arm64_spr_lock_test
),
89 XNUPOST_TEST_CONFIG_BASIC(copyio_test
),
93 uint32_t bsd_post_tests_count
= sizeof(bsd_post_tests
) / sizeof(xnupost_test_data_t
);
95 extern uint64_t last_loaded_timestamp
; /* updated by OSKext::load() */
96 extern uint64_t kernel_post_args
;
100 if (kernel_post_args
== 0) {
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 */
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
);
113 delay(delay_duration_usecs
);
114 absolute_break_counter
-= 1;
116 if (absolute_break_counter
<= 0) {
117 printf("bsd_list_tests: WARNING: Waiting beyond normal time for stabilizing kext loading\n");
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
);
126 prev_load_time
= last_loaded_timestamp
;
129 return xnupost_list_tests(bsd_post_tests
, bsd_post_tests_count
);
135 return xnupost_run_tests(bsd_post_tests
, bsd_post_tests_count
);
144 T_LOG("Running kalloc test.\n");
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
);
152 data_ptr
= kalloc(alloc_size
);
153 T_ASSERT_NOTNULL(data_ptr
, "kalloc 3544 return not null");
154 kfree(data_ptr
, alloc_size
);
159 /* kcdata type definition */
160 #define XNUPOST_TNAME_MAXLEN 132
162 struct kcdata_subtype_descriptor kc_xnupost_test_def
[] = {
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"}
176 const uint32_t kc_xnupost_test_def_count
= sizeof(kc_xnupost_test_def
) / sizeof(struct kcdata_subtype_descriptor
);
178 kern_return_t
xnupost_copyout_test(xnupost_test_t t
, mach_vm_address_t outaddr
);
181 xnupost_copyout_test(xnupost_test_t t
, mach_vm_address_t outaddr
)
183 /* code to copyout test config */
187 kret
= copyout(&t
->xt_config
, (user_addr_t
)outaddr
, sizeof(uint16_t));
191 outaddr
+= sizeof(uint16_t);
193 kret
= copyout(&t
->xt_test_num
, (user_addr_t
)outaddr
, sizeof(uint16_t));
197 outaddr
+= sizeof(uint16_t);
199 kret
= copyout(&t
->xt_retval
, (user_addr_t
)outaddr
, sizeof(uint32_t));
203 outaddr
+= sizeof(uint32_t);
205 kret
= copyout(&t
->xt_expected_retval
, (user_addr_t
)outaddr
, sizeof(uint32_t));
209 outaddr
+= sizeof(uint32_t);
211 kret
= copyout(&t
->xt_begin_time
, (user_addr_t
)outaddr
, sizeof(uint64_t));
215 outaddr
+= sizeof(uint64_t);
217 kret
= copyout(&t
->xt_end_time
, (user_addr_t
)outaddr
, sizeof(uint64_t));
221 outaddr
+= sizeof(uint64_t);
223 namelen
= strnlen(t
->xt_name
, XNUPOST_TNAME_MAXLEN
);
224 kret
= copyout(t
->xt_name
, (user_addr_t
)outaddr
, namelen
);
234 xnupost_get_estimated_testdata_size(void)
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
+
238 kcs_get_elem_size(&kc_xnupost_test_def
[kc_xnupost_test_def_count
- 1]);
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
);
247 xnupost_export_testdata(void * outp
, size_t size_in
, uint32_t * lenp
)
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;
254 char kctype_name
[32] = "xnupost_test_config";
255 mach_timebase_info_data_t timebase
= {0, 0};
256 uint32_t length_to_copy
= 0;
257 unsigned int size
= (unsigned int)size_in
;
259 if (size_in
> UINT_MAX
) {
263 #define RET_IF_OP_FAIL \
265 if (kret != KERN_SUCCESS) { \
266 return (kret == KERN_NO_ACCESS) ? EACCES : ((kret == KERN_RESOURCE_SHORTAGE) ? ENOMEM : EINVAL); \
270 kret
= kcdata_memory_static_init(&kcd
, (mach_vm_address_t
)outp
, KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG
, size
, KCFLAG_USE_COPYOUT
);
273 /* add mach timebase info */
274 clock_timebase_info(&timebase
);
275 kret
= kcdata_get_memory_addr(&kcd
, KCDATA_TYPE_TIMEBASE
, sizeof(timebase
), &user_addr
);
277 kret
= copyout(&timebase
, (user_addr_t
)user_addr
, sizeof(timebase
));
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
);
284 kret
= copyout(&version
[0], (user_addr_t
)user_addr
, length_to_copy
);
287 length_to_copy
= MIN((uint32_t)(strlen(PE_boot_args()) + 1), BOOT_LINE_LENGTH
);
288 kret
= kcdata_get_memory_addr(&kcd
, STACKSHOT_KCTYPE_BOOTARGS
, length_to_copy
, &user_addr
);
290 kret
= copyout(PE_boot_args(), (user_addr_t
)user_addr
, length_to_copy
);
293 /* add type definition to buffer */
294 kret
= kcdata_add_type_definition(&kcd
, XNUPOST_KCTYPE_TESTCONFIG
, kctype_name
, &kc_xnupost_test_def
[0],
295 kc_xnupost_test_def_count
);
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
+
301 kcs_get_elem_size(&kc_xnupost_test_def
[kc_xnupost_test_def_count
- 1]);
303 kret
= kcdata_get_memory_addr_for_array(&kcd
, XNUPOST_KCTYPE_TESTCONFIG
, elem_size
, total_tests
, &user_addr
);
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
);
311 user_addr
= (mach_vm_address_t
)((uint64_t)(user_addr
) + (uint64_t)(i
* elem_size
));
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
);
319 if (kret
== KERN_SUCCESS
&& lenp
!= NULL
) {
320 *lenp
= (uint32_t)kcdata_memory_get_used_bytes(&kcd
);
324 #undef RET_IF_OP_FAIL
329 xnupost_reset_all_tests(void)
331 xnupost_reset_tests(&bsd_post_tests
[0], bsd_post_tests_count
);
332 xnupost_reset_tests(&kernel_post_tests
[0], kernel_post_tests_count
);