1*d4514f0bSApple OSS Distributions // Copyright (c) 2021-2022 Apple Inc. All rights reserved.
2*d4514f0bSApple OSS Distributions
3*d4514f0bSApple OSS Distributions #include <darwintest.h>
4*d4514f0bSApple OSS Distributions #include "test_utils.h"
5*d4514f0bSApple OSS Distributions #include <fcntl.h>
6*d4514f0bSApple OSS Distributions #include <inttypes.h>
7*d4514f0bSApple OSS Distributions #ifndef PRIVATE
8*d4514f0bSApple OSS Distributions /*
9*d4514f0bSApple OSS Distributions * Need new CPU families.
10*d4514f0bSApple OSS Distributions */
11*d4514f0bSApple OSS Distributions #define PRIVATE
12*d4514f0bSApple OSS Distributions #include <mach/machine.h>
13*d4514f0bSApple OSS Distributions #undef PRIVATE
14*d4514f0bSApple OSS Distributions #else /* !defined(PRIVATE) */
15*d4514f0bSApple OSS Distributions #include <mach/machine.h>
16*d4514f0bSApple OSS Distributions #endif /* defined(PRIVATE) */
17*d4514f0bSApple OSS Distributions #include <ktrace.h>
18*d4514f0bSApple OSS Distributions #include <mach/mach.h>
19*d4514f0bSApple OSS Distributions #include <stdint.h>
20*d4514f0bSApple OSS Distributions #include <System/sys/guarded.h>
21*d4514f0bSApple OSS Distributions #include <System/sys/monotonic.h>
22*d4514f0bSApple OSS Distributions #include <sys/ioctl.h>
23*d4514f0bSApple OSS Distributions #include <sys/kdebug.h>
24*d4514f0bSApple OSS Distributions #include <sys/resource.h>
25*d4514f0bSApple OSS Distributions #include <sys/resource_private.h>
26*d4514f0bSApple OSS Distributions #include <sys/sysctl.h>
27*d4514f0bSApple OSS Distributions #include <unistd.h>
28*d4514f0bSApple OSS Distributions
29*d4514f0bSApple OSS Distributions T_GLOBAL_META(
30*d4514f0bSApple OSS Distributions T_META_NAMESPACE("xnu.monotonic"),
31*d4514f0bSApple OSS Distributions T_META_CHECK_LEAKS(false)
32*d4514f0bSApple OSS Distributions );
33*d4514f0bSApple OSS Distributions
34*d4514f0bSApple OSS Distributions static void
skip_if_unsupported(void)35*d4514f0bSApple OSS Distributions skip_if_unsupported(void)
36*d4514f0bSApple OSS Distributions {
37*d4514f0bSApple OSS Distributions int r;
38*d4514f0bSApple OSS Distributions int supported = 0;
39*d4514f0bSApple OSS Distributions size_t supported_size = sizeof(supported);
40*d4514f0bSApple OSS Distributions
41*d4514f0bSApple OSS Distributions r = sysctlbyname("kern.monotonic.supported", &supported, &supported_size,
42*d4514f0bSApple OSS Distributions NULL, 0);
43*d4514f0bSApple OSS Distributions if (r < 0) {
44*d4514f0bSApple OSS Distributions T_WITH_ERRNO;
45*d4514f0bSApple OSS Distributions T_SKIP("could not find \"kern.monotonic.supported\" sysctl");
46*d4514f0bSApple OSS Distributions }
47*d4514f0bSApple OSS Distributions
48*d4514f0bSApple OSS Distributions if (!supported) {
49*d4514f0bSApple OSS Distributions T_SKIP("monotonic is not supported on this platform");
50*d4514f0bSApple OSS Distributions }
51*d4514f0bSApple OSS Distributions }
52*d4514f0bSApple OSS Distributions
53*d4514f0bSApple OSS Distributions static void
check_fixed_counts(struct thsc_cpi counts[2])54*d4514f0bSApple OSS Distributions check_fixed_counts(struct thsc_cpi counts[2])
55*d4514f0bSApple OSS Distributions {
56*d4514f0bSApple OSS Distributions T_QUIET;
57*d4514f0bSApple OSS Distributions T_EXPECT_GT(counts[0].tcpi_instructions, UINT64_C(0), "non-zero instructions");
58*d4514f0bSApple OSS Distributions T_QUIET;
59*d4514f0bSApple OSS Distributions T_EXPECT_GT(counts[0].tcpi_cycles, UINT64_C(0), "non-zero cycles");
60*d4514f0bSApple OSS Distributions
61*d4514f0bSApple OSS Distributions T_EXPECT_GT(counts[1].tcpi_instructions, counts[0].tcpi_instructions,
62*d4514f0bSApple OSS Distributions "monotonically-increasing instructions");
63*d4514f0bSApple OSS Distributions T_EXPECT_GT(counts[1].tcpi_cycles, counts[0].tcpi_cycles,
64*d4514f0bSApple OSS Distributions "monotonically-increasing cycles");
65*d4514f0bSApple OSS Distributions }
66*d4514f0bSApple OSS Distributions
67*d4514f0bSApple OSS Distributions T_DECL(core_fixed_task, "check that task counting is working",
68*d4514f0bSApple OSS Distributions XNU_T_META_SOC_SPECIFIC, T_META_ASROOT(true), T_META_TAG_VM_NOT_ELIGIBLE)
69*d4514f0bSApple OSS Distributions {
70*d4514f0bSApple OSS Distributions task_t task = mach_task_self();
71*d4514f0bSApple OSS Distributions kern_return_t kr;
72*d4514f0bSApple OSS Distributions mach_msg_type_number_t size = TASK_INSPECT_BASIC_COUNTS_COUNT;
73*d4514f0bSApple OSS Distributions struct thsc_cpi counts[2];
74*d4514f0bSApple OSS Distributions
75*d4514f0bSApple OSS Distributions skip_if_unsupported();
76*d4514f0bSApple OSS Distributions
77*d4514f0bSApple OSS Distributions kr = task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
78*d4514f0bSApple OSS Distributions (task_inspect_info_t)&counts[0], &size);
79*d4514f0bSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr,
80*d4514f0bSApple OSS Distributions "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
81*d4514f0bSApple OSS Distributions
82*d4514f0bSApple OSS Distributions size = TASK_INSPECT_BASIC_COUNTS_COUNT;
83*d4514f0bSApple OSS Distributions kr = task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
84*d4514f0bSApple OSS Distributions (task_inspect_info_t)&counts[1], &size);
85*d4514f0bSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr,
86*d4514f0bSApple OSS Distributions "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
87*d4514f0bSApple OSS Distributions
88*d4514f0bSApple OSS Distributions check_fixed_counts(counts);
89*d4514f0bSApple OSS Distributions }
90*d4514f0bSApple OSS Distributions
91*d4514f0bSApple OSS Distributions T_DECL(core_fixed_kdebug, "check that the kdebug macros for monotonic work",
92*d4514f0bSApple OSS Distributions T_META_ASROOT(true), T_META_TAG_VM_NOT_ELIGIBLE)
93*d4514f0bSApple OSS Distributions {
94*d4514f0bSApple OSS Distributions __block bool saw_events = false;
95*d4514f0bSApple OSS Distributions ktrace_session_t s;
96*d4514f0bSApple OSS Distributions int r;
97*d4514f0bSApple OSS Distributions int set = 1;
98*d4514f0bSApple OSS Distributions
99*d4514f0bSApple OSS Distributions T_SETUPBEGIN;
100*d4514f0bSApple OSS Distributions skip_if_unsupported();
101*d4514f0bSApple OSS Distributions
102*d4514f0bSApple OSS Distributions s = ktrace_session_create();
103*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(s, "ktrace_session_create");
104*d4514f0bSApple OSS Distributions
105*d4514f0bSApple OSS Distributions ktrace_events_single_paired(s,
106*d4514f0bSApple OSS Distributions KDBG_EVENTID(DBG_MONOTONIC, DBG_MT_TMPCPU, 0x3fff),
107*d4514f0bSApple OSS Distributions ^(struct trace_point *start, struct trace_point *end)
108*d4514f0bSApple OSS Distributions {
109*d4514f0bSApple OSS Distributions struct thsc_cpi counts[2];
110*d4514f0bSApple OSS Distributions
111*d4514f0bSApple OSS Distributions saw_events = true;
112*d4514f0bSApple OSS Distributions
113*d4514f0bSApple OSS Distributions counts[0].tcpi_instructions = start->arg1;
114*d4514f0bSApple OSS Distributions counts[0].tcpi_cycles = start->arg2;
115*d4514f0bSApple OSS Distributions counts[1].tcpi_instructions = end->arg1;
116*d4514f0bSApple OSS Distributions counts[1].tcpi_cycles = end->arg2;
117*d4514f0bSApple OSS Distributions
118*d4514f0bSApple OSS Distributions check_fixed_counts(counts);
119*d4514f0bSApple OSS Distributions });
120*d4514f0bSApple OSS Distributions
121*d4514f0bSApple OSS Distributions ktrace_set_completion_handler(s, ^{
122*d4514f0bSApple OSS Distributions T_ASSERT_TRUE(saw_events, "should see monotonic kdebug events");
123*d4514f0bSApple OSS Distributions T_END;
124*d4514f0bSApple OSS Distributions });
125*d4514f0bSApple OSS Distributions T_SETUPEND;
126*d4514f0bSApple OSS Distributions
127*d4514f0bSApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s,
128*d4514f0bSApple OSS Distributions dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)), NULL);
129*d4514f0bSApple OSS Distributions
130*d4514f0bSApple OSS Distributions r = sysctlbyname("kern.monotonic.kdebug_test", NULL, NULL, &set,
131*d4514f0bSApple OSS Distributions sizeof(set));
132*d4514f0bSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r,
133*d4514f0bSApple OSS Distributions "sysctlbyname(\"kern.monotonic.kdebug_test\", ...)");
134*d4514f0bSApple OSS Distributions
135*d4514f0bSApple OSS Distributions ktrace_end(s, 0);
136*d4514f0bSApple OSS Distributions dispatch_main();
137*d4514f0bSApple OSS Distributions }
138*d4514f0bSApple OSS Distributions
139*d4514f0bSApple OSS Distributions static void *
spin_thread_self_counts(__unused void * arg)140*d4514f0bSApple OSS Distributions spin_thread_self_counts(__unused void *arg)
141*d4514f0bSApple OSS Distributions {
142*d4514f0bSApple OSS Distributions struct thsc_cpi counts = { 0 };
143*d4514f0bSApple OSS Distributions while (true) {
144*d4514f0bSApple OSS Distributions (void)thread_selfcounts(THSC_CPI, &counts, sizeof(counts));
145*d4514f0bSApple OSS Distributions }
146*d4514f0bSApple OSS Distributions }
147*d4514f0bSApple OSS Distributions
148*d4514f0bSApple OSS Distributions static void *
spin_task_inspect(__unused void * arg)149*d4514f0bSApple OSS Distributions spin_task_inspect(__unused void *arg)
150*d4514f0bSApple OSS Distributions {
151*d4514f0bSApple OSS Distributions task_t task = mach_task_self();
152*d4514f0bSApple OSS Distributions uint64_t counts[2] = { 0 };
153*d4514f0bSApple OSS Distributions unsigned int size = 0;
154*d4514f0bSApple OSS Distributions while (true) {
155*d4514f0bSApple OSS Distributions size = (unsigned int)sizeof(counts);
156*d4514f0bSApple OSS Distributions (void)task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
157*d4514f0bSApple OSS Distributions (task_inspect_info_t)&counts[0], &size);
158*d4514f0bSApple OSS Distributions /*
159*d4514f0bSApple OSS Distributions * Not realistic for a process to see count values with the high bit
160*d4514f0bSApple OSS Distributions * set, but kernel pointers will be that high.
161*d4514f0bSApple OSS Distributions */
162*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_LT(counts[0], 1ULL << 63,
163*d4514f0bSApple OSS Distributions "check for valid count entry 1");
164*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_LT(counts[1], 1ULL << 63,
165*d4514f0bSApple OSS Distributions "check for valid count entry 2");
166*d4514f0bSApple OSS Distributions }
167*d4514f0bSApple OSS Distributions }
168*d4514f0bSApple OSS Distributions
169*d4514f0bSApple OSS Distributions T_DECL(core_fixed_stack_leak_race,
170*d4514f0bSApple OSS Distributions "ensure no stack data is leaked by TASK_INSPECT_BASIC_COUNTS", T_META_TAG_VM_NOT_ELIGIBLE)
171*d4514f0bSApple OSS Distributions {
172*d4514f0bSApple OSS Distributions T_SETUPBEGIN;
173*d4514f0bSApple OSS Distributions
174*d4514f0bSApple OSS Distributions int ncpus = 0;
175*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("hw.logicalcpu_max", &ncpus,
176*d4514f0bSApple OSS Distributions &(size_t){ sizeof(ncpus) }, NULL, 0), "get number of CPUs");
177*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_GT(ncpus, 0, "got non-zero number of CPUs");
178*d4514f0bSApple OSS Distributions pthread_t *threads = calloc((unsigned long)ncpus, sizeof(*threads));
179*d4514f0bSApple OSS Distributions
180*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(threads, "allocated space for threads");
181*d4514f0bSApple OSS Distributions
182*d4514f0bSApple OSS Distributions T_LOG("creating %d threads to attempt to race around task counts", ncpus);
183*d4514f0bSApple OSS Distributions /*
184*d4514f0bSApple OSS Distributions * Have half the threads hammering thread_self_counts and the other half
185*d4514f0bSApple OSS Distributions * trying to get an error to occur inside TASK_INSPECT_BASIC_COUNTS and see
186*d4514f0bSApple OSS Distributions * uninitialized kernel memory.
187*d4514f0bSApple OSS Distributions */
188*d4514f0bSApple OSS Distributions for (int i = 0; i < ncpus; i++) {
189*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&threads[i], NULL,
190*d4514f0bSApple OSS Distributions i & 1 ? spin_task_inspect : spin_thread_self_counts, NULL),
191*d4514f0bSApple OSS Distributions NULL);
192*d4514f0bSApple OSS Distributions }
193*d4514f0bSApple OSS Distributions
194*d4514f0bSApple OSS Distributions T_SETUPEND;
195*d4514f0bSApple OSS Distributions
196*d4514f0bSApple OSS Distributions sleep(10);
197*d4514f0bSApple OSS Distributions T_PASS("ending test after 10 seconds");
198*d4514f0bSApple OSS Distributions }
199*d4514f0bSApple OSS Distributions
200*d4514f0bSApple OSS Distributions static void
perf_sysctl_deltas(const char * sysctl_name,const char * stat_name)201*d4514f0bSApple OSS Distributions perf_sysctl_deltas(const char *sysctl_name, const char *stat_name)
202*d4514f0bSApple OSS Distributions {
203*d4514f0bSApple OSS Distributions uint64_t deltas[2];
204*d4514f0bSApple OSS Distributions size_t deltas_size;
205*d4514f0bSApple OSS Distributions int r;
206*d4514f0bSApple OSS Distributions
207*d4514f0bSApple OSS Distributions T_SETUPBEGIN;
208*d4514f0bSApple OSS Distributions skip_if_unsupported();
209*d4514f0bSApple OSS Distributions
210*d4514f0bSApple OSS Distributions dt_stat_t instrs = dt_stat_create("instructions", "%s_instrs",
211*d4514f0bSApple OSS Distributions stat_name);
212*d4514f0bSApple OSS Distributions dt_stat_t cycles = dt_stat_create("cycles", "%s_cycles", stat_name);
213*d4514f0bSApple OSS Distributions T_SETUPEND;
214*d4514f0bSApple OSS Distributions
215*d4514f0bSApple OSS Distributions while (!dt_stat_stable(instrs) || !dt_stat_stable(cycles)) {
216*d4514f0bSApple OSS Distributions deltas_size = sizeof(deltas);
217*d4514f0bSApple OSS Distributions r = sysctlbyname(sysctl_name, deltas, &deltas_size, NULL, 0);
218*d4514f0bSApple OSS Distributions T_QUIET;
219*d4514f0bSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r, "sysctlbyname(\"%s\", ...)", sysctl_name);
220*d4514f0bSApple OSS Distributions dt_stat_add(instrs, (double)deltas[0]);
221*d4514f0bSApple OSS Distributions dt_stat_add(cycles, (double)deltas[1]);
222*d4514f0bSApple OSS Distributions }
223*d4514f0bSApple OSS Distributions
224*d4514f0bSApple OSS Distributions dt_stat_finalize(instrs);
225*d4514f0bSApple OSS Distributions dt_stat_finalize(cycles);
226*d4514f0bSApple OSS Distributions }
227*d4514f0bSApple OSS Distributions
228*d4514f0bSApple OSS Distributions T_DECL(perf_core_fixed_cpu, "test the performance of fixed CPU counter access",
229*d4514f0bSApple OSS Distributions T_META_ASROOT(true), XNU_T_META_SOC_SPECIFIC, T_META_TAG_PERF, T_META_TAG_VM_NOT_ELIGIBLE)
230*d4514f0bSApple OSS Distributions {
231*d4514f0bSApple OSS Distributions perf_sysctl_deltas("kern.monotonic.fixed_cpu_perf", "fixed_cpu_counters");
232*d4514f0bSApple OSS Distributions }
233*d4514f0bSApple OSS Distributions
234*d4514f0bSApple OSS Distributions T_DECL(perf_core_fixed_thread, "test the performance of fixed thread counter access",
235*d4514f0bSApple OSS Distributions T_META_ASROOT(true), XNU_T_META_SOC_SPECIFIC, T_META_TAG_PERF, T_META_TAG_VM_NOT_ELIGIBLE)
236*d4514f0bSApple OSS Distributions {
237*d4514f0bSApple OSS Distributions perf_sysctl_deltas("kern.monotonic.fixed_thread_perf",
238*d4514f0bSApple OSS Distributions "fixed_thread_counters");
239*d4514f0bSApple OSS Distributions }
240*d4514f0bSApple OSS Distributions
241*d4514f0bSApple OSS Distributions T_DECL(perf_core_fixed_task, "test the performance of fixed task counter access",
242*d4514f0bSApple OSS Distributions T_META_ASROOT(true), XNU_T_META_SOC_SPECIFIC, T_META_TAG_PERF, T_META_TAG_VM_NOT_ELIGIBLE)
243*d4514f0bSApple OSS Distributions {
244*d4514f0bSApple OSS Distributions perf_sysctl_deltas("kern.monotonic.fixed_task_perf", "fixed_task_counters");
245*d4514f0bSApple OSS Distributions }
246