arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / kernel / events / hw_breakpoint_test.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * KUnit test for hw_breakpoint constraints accounting logic.
4  *
5  * Copyright (C) 2022, Google LLC.
6  */
7
8 #include <kunit/test.h>
9 #include <linux/cpumask.h>
10 #include <linux/hw_breakpoint.h>
11 #include <linux/kthread.h>
12 #include <linux/perf_event.h>
13 #include <asm/hw_breakpoint.h>
14
15 #define TEST_REQUIRES_BP_SLOTS(test, slots)                                             \
16         do {                                                                            \
17                 if ((slots) > get_test_bp_slots()) {                                    \
18                         kunit_skip((test), "Requires breakpoint slots: %d > %d", slots, \
19                                    get_test_bp_slots());                                \
20                 }                                                                       \
21         } while (0)
22
23 #define TEST_EXPECT_NOSPC(expr) KUNIT_EXPECT_EQ(test, -ENOSPC, PTR_ERR(expr))
24
25 #define MAX_TEST_BREAKPOINTS 512
26
27 static char break_vars[MAX_TEST_BREAKPOINTS];
28 static struct perf_event *test_bps[MAX_TEST_BREAKPOINTS];
29 static struct task_struct *__other_task;
30
31 static struct perf_event *register_test_bp(int cpu, struct task_struct *tsk, int idx)
32 {
33         struct perf_event_attr attr = {};
34
35         if (WARN_ON(idx < 0 || idx >= MAX_TEST_BREAKPOINTS))
36                 return NULL;
37
38         hw_breakpoint_init(&attr);
39         attr.bp_addr = (unsigned long)&break_vars[idx];
40         attr.bp_len = HW_BREAKPOINT_LEN_1;
41         attr.bp_type = HW_BREAKPOINT_RW;
42         return perf_event_create_kernel_counter(&attr, cpu, tsk, NULL, NULL);
43 }
44
45 static void unregister_test_bp(struct perf_event **bp)
46 {
47         if (WARN_ON(IS_ERR(*bp)))
48                 return;
49         if (WARN_ON(!*bp))
50                 return;
51         unregister_hw_breakpoint(*bp);
52         *bp = NULL;
53 }
54
55 static int get_test_bp_slots(void)
56 {
57         static int slots;
58
59         if (!slots)
60                 slots = hw_breakpoint_slots(TYPE_DATA);
61
62         return slots;
63 }
64
65 static void fill_one_bp_slot(struct kunit *test, int *id, int cpu, struct task_struct *tsk)
66 {
67         struct perf_event *bp = register_test_bp(cpu, tsk, *id);
68
69         KUNIT_ASSERT_NOT_NULL(test, bp);
70         KUNIT_ASSERT_FALSE(test, IS_ERR(bp));
71         KUNIT_ASSERT_NULL(test, test_bps[*id]);
72         test_bps[(*id)++] = bp;
73 }
74
75 /*
76  * Fills up the given @cpu/@tsk with breakpoints, only leaving @skip slots free.
77  *
78  * Returns true if this can be called again, continuing at @id.
79  */
80 static bool fill_bp_slots(struct kunit *test, int *id, int cpu, struct task_struct *tsk, int skip)
81 {
82         for (int i = 0; i < get_test_bp_slots() - skip; ++i)
83                 fill_one_bp_slot(test, id, cpu, tsk);
84
85         return *id + get_test_bp_slots() <= MAX_TEST_BREAKPOINTS;
86 }
87
88 static int dummy_kthread(void *arg)
89 {
90         return 0;
91 }
92
93 static struct task_struct *get_other_task(struct kunit *test)
94 {
95         struct task_struct *tsk;
96
97         if (__other_task)
98                 return __other_task;
99
100         tsk = kthread_create(dummy_kthread, NULL, "hw_breakpoint_dummy_task");
101         KUNIT_ASSERT_FALSE(test, IS_ERR(tsk));
102         __other_task = tsk;
103         return __other_task;
104 }
105
106 static int get_test_cpu(int num)
107 {
108         int cpu;
109
110         WARN_ON(num < 0);
111
112         for_each_online_cpu(cpu) {
113                 if (num-- <= 0)
114                         break;
115         }
116
117         return cpu;
118 }
119
120 /* ===== Test cases ===== */
121
122 static void test_one_cpu(struct kunit *test)
123 {
124         int idx = 0;
125
126         fill_bp_slots(test, &idx, get_test_cpu(0), NULL, 0);
127         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
128         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
129 }
130
131 static void test_many_cpus(struct kunit *test)
132 {
133         int idx = 0;
134         int cpu;
135
136         /* Test that CPUs are independent. */
137         for_each_online_cpu(cpu) {
138                 bool do_continue = fill_bp_slots(test, &idx, cpu, NULL, 0);
139
140                 TEST_EXPECT_NOSPC(register_test_bp(cpu, NULL, idx));
141                 if (!do_continue)
142                         break;
143         }
144 }
145
146 static void test_one_task_on_all_cpus(struct kunit *test)
147 {
148         int idx = 0;
149
150         fill_bp_slots(test, &idx, -1, current, 0);
151         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
152         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
153         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
154         /* Remove one and adding back CPU-target should work. */
155         unregister_test_bp(&test_bps[0]);
156         fill_one_bp_slot(test, &idx, get_test_cpu(0), NULL);
157 }
158
159 static void test_two_tasks_on_all_cpus(struct kunit *test)
160 {
161         int idx = 0;
162
163         /* Test that tasks are independent. */
164         fill_bp_slots(test, &idx, -1, current, 0);
165         fill_bp_slots(test, &idx, -1, get_other_task(test), 0);
166
167         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
168         TEST_EXPECT_NOSPC(register_test_bp(-1, get_other_task(test), idx));
169         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
170         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), get_other_task(test), idx));
171         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
172         /* Remove one from first task and adding back CPU-target should not work. */
173         unregister_test_bp(&test_bps[0]);
174         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
175 }
176
177 static void test_one_task_on_one_cpu(struct kunit *test)
178 {
179         int idx = 0;
180
181         fill_bp_slots(test, &idx, get_test_cpu(0), current, 0);
182         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
183         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
184         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
185         /*
186          * Remove one and adding back CPU-target should work; this case is
187          * special vs. above because the task's constraints are CPU-dependent.
188          */
189         unregister_test_bp(&test_bps[0]);
190         fill_one_bp_slot(test, &idx, get_test_cpu(0), NULL);
191 }
192
193 static void test_one_task_mixed(struct kunit *test)
194 {
195         int idx = 0;
196
197         TEST_REQUIRES_BP_SLOTS(test, 3);
198
199         fill_one_bp_slot(test, &idx, get_test_cpu(0), current);
200         fill_bp_slots(test, &idx, -1, current, 1);
201         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
202         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
203         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
204
205         /* Transition from CPU-dependent pinned count to CPU-independent. */
206         unregister_test_bp(&test_bps[0]);
207         unregister_test_bp(&test_bps[1]);
208         fill_one_bp_slot(test, &idx, get_test_cpu(0), NULL);
209         fill_one_bp_slot(test, &idx, get_test_cpu(0), NULL);
210         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
211 }
212
213 static void test_two_tasks_on_one_cpu(struct kunit *test)
214 {
215         int idx = 0;
216
217         fill_bp_slots(test, &idx, get_test_cpu(0), current, 0);
218         fill_bp_slots(test, &idx, get_test_cpu(0), get_other_task(test), 0);
219
220         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
221         TEST_EXPECT_NOSPC(register_test_bp(-1, get_other_task(test), idx));
222         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
223         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), get_other_task(test), idx));
224         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
225         /* Can still create breakpoints on some other CPU. */
226         fill_bp_slots(test, &idx, get_test_cpu(1), NULL, 0);
227 }
228
229 static void test_two_tasks_on_one_all_cpus(struct kunit *test)
230 {
231         int idx = 0;
232
233         fill_bp_slots(test, &idx, get_test_cpu(0), current, 0);
234         fill_bp_slots(test, &idx, -1, get_other_task(test), 0);
235
236         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
237         TEST_EXPECT_NOSPC(register_test_bp(-1, get_other_task(test), idx));
238         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
239         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), get_other_task(test), idx));
240         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
241         /* Cannot create breakpoints on some other CPU either. */
242         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(1), NULL, idx));
243 }
244
245 static void test_task_on_all_and_one_cpu(struct kunit *test)
246 {
247         int tsk_on_cpu_idx, cpu_idx;
248         int idx = 0;
249
250         TEST_REQUIRES_BP_SLOTS(test, 3);
251
252         fill_bp_slots(test, &idx, -1, current, 2);
253         /* Transitioning from only all CPU breakpoints to mixed. */
254         tsk_on_cpu_idx = idx;
255         fill_one_bp_slot(test, &idx, get_test_cpu(0), current);
256         fill_one_bp_slot(test, &idx, -1, current);
257
258         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
259         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
260         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
261
262         /* We should still be able to use up another CPU's slots. */
263         cpu_idx = idx;
264         fill_one_bp_slot(test, &idx, get_test_cpu(1), NULL);
265         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(1), NULL, idx));
266
267         /* Transitioning back to task target on all CPUs. */
268         unregister_test_bp(&test_bps[tsk_on_cpu_idx]);
269         /* Still have a CPU target breakpoint in get_test_cpu(1). */
270         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
271         /* Remove it and try again. */
272         unregister_test_bp(&test_bps[cpu_idx]);
273         fill_one_bp_slot(test, &idx, -1, current);
274
275         TEST_EXPECT_NOSPC(register_test_bp(-1, current, idx));
276         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), current, idx));
277         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(0), NULL, idx));
278         TEST_EXPECT_NOSPC(register_test_bp(get_test_cpu(1), NULL, idx));
279 }
280
281 static struct kunit_case hw_breakpoint_test_cases[] = {
282         KUNIT_CASE(test_one_cpu),
283         KUNIT_CASE(test_many_cpus),
284         KUNIT_CASE(test_one_task_on_all_cpus),
285         KUNIT_CASE(test_two_tasks_on_all_cpus),
286         KUNIT_CASE(test_one_task_on_one_cpu),
287         KUNIT_CASE(test_one_task_mixed),
288         KUNIT_CASE(test_two_tasks_on_one_cpu),
289         KUNIT_CASE(test_two_tasks_on_one_all_cpus),
290         KUNIT_CASE(test_task_on_all_and_one_cpu),
291         {},
292 };
293
294 static int test_init(struct kunit *test)
295 {
296         /* Most test cases want 2 distinct CPUs. */
297         if (num_online_cpus() < 2)
298                 kunit_skip(test, "not enough cpus");
299
300         /* Want the system to not use breakpoints elsewhere. */
301         if (hw_breakpoint_is_used())
302                 kunit_skip(test, "hw breakpoint already in use");
303
304         return 0;
305 }
306
307 static void test_exit(struct kunit *test)
308 {
309         for (int i = 0; i < MAX_TEST_BREAKPOINTS; ++i) {
310                 if (test_bps[i])
311                         unregister_test_bp(&test_bps[i]);
312         }
313
314         if (__other_task) {
315                 kthread_stop(__other_task);
316                 __other_task = NULL;
317         }
318
319         /* Verify that internal state agrees that no breakpoints are in use. */
320         KUNIT_EXPECT_FALSE(test, hw_breakpoint_is_used());
321 }
322
323 static struct kunit_suite hw_breakpoint_test_suite = {
324         .name = "hw_breakpoint",
325         .test_cases = hw_breakpoint_test_cases,
326         .init = test_init,
327         .exit = test_exit,
328 };
329
330 kunit_test_suites(&hw_breakpoint_test_suite);
331
332 MODULE_AUTHOR("Marco Elver <elver@google.com>");