1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * SBI DBTR testsuite
4 *
5 * Copyright (C) 2025, Rivos Inc., Jesse Taube <jesse@rivosinc.com>
6 */
7
8 #include <libcflat.h>
9 #include <bitops.h>
10
11 #include <asm/io.h>
12 #include <asm/processor.h>
13
14 #include "sbi-tests.h"
15
16 #define RV_MAX_TRIGGERS 32
17
18 #define SBI_DBTR_TRIG_STATE_MAPPED BIT(0)
19 #define SBI_DBTR_TRIG_STATE_U BIT(1)
20 #define SBI_DBTR_TRIG_STATE_S BIT(2)
21 #define SBI_DBTR_TRIG_STATE_VU BIT(3)
22 #define SBI_DBTR_TRIG_STATE_VS BIT(4)
23 #define SBI_DBTR_TRIG_STATE_HAVE_HW_TRIG BIT(5)
24 #define SBI_DBTR_TRIG_STATE_RESERVED GENMASK(7, 6)
25
26 #define SBI_DBTR_TRIG_STATE_HW_TRIG_IDX_SHIFT 8
27 #define SBI_DBTR_TRIG_STATE_HW_TRIG_IDX(trig_state) (trig_state >> SBI_DBTR_TRIG_STATE_HW_TRIG_IDX_SHIFT)
28
29 #define SBI_DBTR_TDATA1_TYPE_SHIFT (__riscv_xlen - 4)
30 #define SBI_DBTR_TDATA1_DMODE BIT_UL(__riscv_xlen - 5)
31
32 #define SBI_DBTR_TDATA1_MCONTROL6_LOAD BIT(0)
33 #define SBI_DBTR_TDATA1_MCONTROL6_STORE BIT(1)
34 #define SBI_DBTR_TDATA1_MCONTROL6_EXECUTE BIT(2)
35 #define SBI_DBTR_TDATA1_MCONTROL6_U BIT(3)
36 #define SBI_DBTR_TDATA1_MCONTROL6_S BIT(4)
37 #define SBI_DBTR_TDATA1_MCONTROL6_M BIT(6)
38 #define SBI_DBTR_TDATA1_MCONTROL6_SIZE_SHIFT 16
39 #define SBI_DBTR_TDATA1_MCONTROL6_SIZE_MASK 0x7
40 #define SBI_DBTR_TDATA1_MCONTROL6_SELECT BIT(21)
41 #define SBI_DBTR_TDATA1_MCONTROL6_VU BIT(23)
42 #define SBI_DBTR_TDATA1_MCONTROL6_VS BIT(24)
43
44 #define SBI_DBTR_TDATA1_MCONTROL_LOAD BIT(0)
45 #define SBI_DBTR_TDATA1_MCONTROL_STORE BIT(1)
46 #define SBI_DBTR_TDATA1_MCONTROL_EXECUTE BIT(2)
47 #define SBI_DBTR_TDATA1_MCONTROL_U BIT(3)
48 #define SBI_DBTR_TDATA1_MCONTROL_S BIT(4)
49 #define SBI_DBTR_TDATA1_MCONTROL_M BIT(6)
50 #define SBI_DBTR_TDATA1_MCONTROL_SIZELO_SHIFT 16
51 #define SBI_DBTR_TDATA1_MCONTROL_SIZELO_MASK 0x3
52 #define SBI_DBTR_TDATA1_MCONTROL_SELECT BIT(19)
53 #define SBI_DBTR_TDATA1_MCONTROL_SIZEHI_SHIFT 21
54 #define SBI_DBTR_TDATA1_MCONTROL_SIZEHI_MASK 0x3
55
56 enum McontrolType {
57 SBI_DBTR_TDATA1_TYPE_NONE = (0UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
58 SBI_DBTR_TDATA1_TYPE_LEGACY = (1UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
59 SBI_DBTR_TDATA1_TYPE_MCONTROL = (2UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
60 SBI_DBTR_TDATA1_TYPE_ICOUNT = (3UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
61 SBI_DBTR_TDATA1_TYPE_ITRIGGER = (4UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
62 SBI_DBTR_TDATA1_TYPE_ETRIGGER = (5UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
63 SBI_DBTR_TDATA1_TYPE_MCONTROL6 = (6UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
64 SBI_DBTR_TDATA1_TYPE_TMEXTTRIGGER = (7UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
65 SBI_DBTR_TDATA1_TYPE_RESERVED0 = (8UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
66 SBI_DBTR_TDATA1_TYPE_RESERVED1 = (9UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
67 SBI_DBTR_TDATA1_TYPE_RESERVED2 = (10UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
68 SBI_DBTR_TDATA1_TYPE_RESERVED3 = (11UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
69 SBI_DBTR_TDATA1_TYPE_CUSTOM0 = (12UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
70 SBI_DBTR_TDATA1_TYPE_CUSTOM1 = (13UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
71 SBI_DBTR_TDATA1_TYPE_CUSTOM2 = (14UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
72 SBI_DBTR_TDATA1_TYPE_DISABLED = (15UL << SBI_DBTR_TDATA1_TYPE_SHIFT),
73 };
74
75 enum Tdata1Size {
76 SIZE_ANY = 0,
77 SIZE_8BIT,
78 SIZE_16BIT,
79 SIZE_32BIT,
80 SIZE_48BIT,
81 SIZE_64BIT,
82 };
83
84 enum Tdata1Value {
85 VALUE_NONE = 0,
86 VALUE_LOAD = BIT(0),
87 VALUE_STORE = BIT(1),
88 VALUE_EXECUTE = BIT(2),
89 };
90
91 enum Tdata1Mode {
92 MODE_NONE = 0,
93 MODE_M = BIT(0),
94 MODE_U = BIT(1),
95 MODE_S = BIT(2),
96 MODE_VU = BIT(3),
97 MODE_VS = BIT(4),
98 };
99
100 enum sbi_ext_dbtr_fid {
101 SBI_EXT_DBTR_NUM_TRIGGERS = 0,
102 SBI_EXT_DBTR_SETUP_SHMEM,
103 SBI_EXT_DBTR_TRIGGER_READ,
104 SBI_EXT_DBTR_TRIGGER_INSTALL,
105 SBI_EXT_DBTR_TRIGGER_UPDATE,
106 SBI_EXT_DBTR_TRIGGER_UNINSTALL,
107 SBI_EXT_DBTR_TRIGGER_ENABLE,
108 SBI_EXT_DBTR_TRIGGER_DISABLE,
109 };
110
111 struct sbi_dbtr_data_msg {
112 unsigned long tstate;
113 unsigned long tdata1;
114 unsigned long tdata2;
115 unsigned long tdata3;
116 };
117
118 struct sbi_dbtr_id_msg {
119 unsigned long idx;
120 };
121
122 /* SBI shared mem messages layout */
123 struct sbi_dbtr_shmem_entry {
124 union {
125 struct sbi_dbtr_data_msg data;
126 struct sbi_dbtr_id_msg id;
127 };
128 };
129
130 static bool dbtr_handled;
131
132 /* Expected to be leaf function as not to disrupt frame-pointer */
exec_call(void)133 static __attribute__((naked)) void exec_call(void)
134 {
135 /* skip over nop when triggered instead of ret. */
136 asm volatile (".option push\n"
137 ".option norvc\n"
138 "nop\n"
139 "ret\n"
140 ".option pop\n");
141 }
142
dbtr_exception_handler(struct pt_regs * regs)143 static void dbtr_exception_handler(struct pt_regs *regs)
144 {
145 dbtr_handled = true;
146
147 /* Reading *epc may cause a fault, skip over nop */
148 if ((void *)regs->epc == exec_call) {
149 regs->epc += 4;
150 return;
151 }
152
153 /* WARNING: Skips over the trapped intruction */
154 regs->epc += RV_INSN_LEN(readw((void *)regs->epc));
155 }
156
do_store(void * tdata2)157 static bool do_store(void *tdata2)
158 {
159 bool ret;
160
161 writel(0, tdata2);
162
163 ret = dbtr_handled;
164 dbtr_handled = false;
165
166 return ret;
167 }
168
do_load(void * tdata2)169 static bool do_load(void *tdata2)
170 {
171 bool ret;
172
173 readl(tdata2);
174
175 ret = dbtr_handled;
176 dbtr_handled = false;
177
178 return ret;
179 }
180
do_exec(void)181 static bool do_exec(void)
182 {
183 bool ret;
184
185 exec_call();
186
187 ret = dbtr_handled;
188 dbtr_handled = false;
189
190 return ret;
191 }
192
mcontrol_size(enum Tdata1Size mode)193 static unsigned long mcontrol_size(enum Tdata1Size mode)
194 {
195 unsigned long ret = 0;
196
197 ret |= ((mode >> 2) & SBI_DBTR_TDATA1_MCONTROL_SIZEHI_MASK)
198 << SBI_DBTR_TDATA1_MCONTROL_SIZEHI_SHIFT;
199 ret |= (mode & SBI_DBTR_TDATA1_MCONTROL_SIZELO_MASK)
200 << SBI_DBTR_TDATA1_MCONTROL_SIZELO_SHIFT;
201
202 return ret;
203 }
204
mcontrol6_size(enum Tdata1Size mode)205 static unsigned long mcontrol6_size(enum Tdata1Size mode)
206 {
207 return (mode & SBI_DBTR_TDATA1_MCONTROL6_SIZE_MASK)
208 << SBI_DBTR_TDATA1_MCONTROL6_SIZE_SHIFT;
209 }
210
gen_tdata1_mcontrol(enum Tdata1Mode mode,enum Tdata1Value value)211 static unsigned long gen_tdata1_mcontrol(enum Tdata1Mode mode, enum Tdata1Value value)
212 {
213 unsigned long tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL;
214
215 if (value & VALUE_LOAD)
216 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_LOAD;
217
218 if (value & VALUE_STORE)
219 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_STORE;
220
221 if (value & VALUE_EXECUTE)
222 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_EXECUTE;
223
224 if (mode & MODE_M)
225 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_M;
226
227 if (mode & MODE_U)
228 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_U;
229
230 if (mode & MODE_S)
231 tdata1 |= SBI_DBTR_TDATA1_MCONTROL_S;
232
233 return tdata1;
234 }
235
gen_tdata1_mcontrol6(enum Tdata1Mode mode,enum Tdata1Value value)236 static unsigned long gen_tdata1_mcontrol6(enum Tdata1Mode mode, enum Tdata1Value value)
237 {
238 unsigned long tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL6;
239
240 if (value & VALUE_LOAD)
241 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_LOAD;
242
243 if (value & VALUE_STORE)
244 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_STORE;
245
246 if (value & VALUE_EXECUTE)
247 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_EXECUTE;
248
249 if (mode & MODE_M)
250 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_M;
251
252 if (mode & MODE_U)
253 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_U;
254
255 if (mode & MODE_S)
256 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_S;
257
258 if (mode & MODE_VU)
259 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_VU;
260
261 if (mode & MODE_VS)
262 tdata1 |= SBI_DBTR_TDATA1_MCONTROL6_VS;
263
264 return tdata1;
265 }
266
gen_tdata1(enum McontrolType type,enum Tdata1Value value,enum Tdata1Mode mode)267 static unsigned long gen_tdata1(enum McontrolType type, enum Tdata1Value value, enum Tdata1Mode mode)
268 {
269 switch (type) {
270 case SBI_DBTR_TDATA1_TYPE_MCONTROL:
271 return gen_tdata1_mcontrol(mode, value) | mcontrol_size(SIZE_32BIT);
272 case SBI_DBTR_TDATA1_TYPE_MCONTROL6:
273 return gen_tdata1_mcontrol6(mode, value) | mcontrol6_size(SIZE_32BIT);
274 default:
275 assert_msg(false, "Invalid mcontrol type: %lu", (unsigned long)type);
276 }
277 }
278
sbi_debug_num_triggers(unsigned long trig_tdata1)279 static struct sbiret sbi_debug_num_triggers(unsigned long trig_tdata1)
280 {
281 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_NUM_TRIGGERS, trig_tdata1, 0, 0, 0, 0, 0);
282 }
283
sbi_debug_set_shmem_raw(unsigned long shmem_phys_lo,unsigned long shmem_phys_hi,unsigned long flags)284 static struct sbiret sbi_debug_set_shmem_raw(unsigned long shmem_phys_lo,
285 unsigned long shmem_phys_hi,
286 unsigned long flags)
287 {
288 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_SETUP_SHMEM, shmem_phys_lo,
289 shmem_phys_hi, flags, 0, 0, 0);
290 }
291
sbi_debug_set_shmem(void * shmem)292 static struct sbiret sbi_debug_set_shmem(void *shmem)
293 {
294 unsigned long base_addr_lo, base_addr_hi;
295
296 split_phys_addr(virt_to_phys(shmem), &base_addr_hi, &base_addr_lo);
297 return sbi_debug_set_shmem_raw(base_addr_lo, base_addr_hi, 0);
298 }
299
sbi_debug_read_triggers(unsigned long trig_idx_base,unsigned long trig_count)300 static struct sbiret sbi_debug_read_triggers(unsigned long trig_idx_base,
301 unsigned long trig_count)
302 {
303 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_READ, trig_idx_base,
304 trig_count, 0, 0, 0, 0);
305 }
306
sbi_debug_install_triggers(unsigned long trig_count)307 static struct sbiret sbi_debug_install_triggers(unsigned long trig_count)
308 {
309 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_INSTALL, trig_count, 0, 0, 0, 0, 0);
310 }
311
sbi_debug_update_triggers(unsigned long trig_count)312 static struct sbiret sbi_debug_update_triggers(unsigned long trig_count)
313 {
314 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_UPDATE, trig_count, 0, 0, 0, 0, 0);
315 }
316
sbi_debug_uninstall_triggers(unsigned long trig_idx_base,unsigned long trig_idx_mask)317 static struct sbiret sbi_debug_uninstall_triggers(unsigned long trig_idx_base,
318 unsigned long trig_idx_mask)
319 {
320 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_UNINSTALL, trig_idx_base,
321 trig_idx_mask, 0, 0, 0, 0);
322 }
323
sbi_debug_enable_triggers(unsigned long trig_idx_base,unsigned long trig_idx_mask)324 static struct sbiret sbi_debug_enable_triggers(unsigned long trig_idx_base,
325 unsigned long trig_idx_mask)
326 {
327 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_ENABLE, trig_idx_base,
328 trig_idx_mask, 0, 0, 0, 0);
329 }
330
sbi_debug_disable_triggers(unsigned long trig_idx_base,unsigned long trig_idx_mask)331 static struct sbiret sbi_debug_disable_triggers(unsigned long trig_idx_base,
332 unsigned long trig_idx_mask)
333 {
334 return sbi_ecall(SBI_EXT_DBTR, SBI_EXT_DBTR_TRIGGER_DISABLE, trig_idx_base,
335 trig_idx_mask, 0, 0, 0, 0);
336 }
337
dbtr_install_trigger(struct sbi_dbtr_shmem_entry * shmem,void * trigger,unsigned long control)338 static bool dbtr_install_trigger(struct sbi_dbtr_shmem_entry *shmem, void *trigger,
339 unsigned long control)
340 {
341 struct sbiret sbi_ret;
342 bool ret;
343
344 shmem->data.tdata1 = control;
345 shmem->data.tdata2 = (unsigned long)trigger;
346
347 sbi_ret = sbi_debug_install_triggers(1);
348 ret = sbiret_report_error(&sbi_ret, SBI_SUCCESS, "sbi_debug_install_triggers");
349 if (ret)
350 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler);
351
352 return ret;
353 }
354
dbtr_uninstall_trigger(void)355 static bool dbtr_uninstall_trigger(void)
356 {
357 struct sbiret ret;
358
359 install_exception_handler(EXC_BREAKPOINT, NULL);
360
361 ret = sbi_debug_uninstall_triggers(0, 1);
362 return sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers");
363 }
364
dbtr_test_num_triggers(void)365 static unsigned long dbtr_test_num_triggers(void)
366 {
367 struct sbiret ret;
368 unsigned long tdata1 = 0;
369 /* sbi_debug_num_triggers will return trig_max in sbiret.value when trig_tdata1 == 0 */
370
371 report_prefix_push("available triggers");
372
373 /* should be at least one trigger. */
374 ret = sbi_debug_num_triggers(tdata1);
375 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_num_triggers");
376
377 if (ret.value == 0) {
378 report_fail("Returned 0 triggers available");
379 } else {
380 report_pass("Returned triggers available");
381 report_info("Returned %lu triggers available", ret.value);
382 }
383
384 report_prefix_pop();
385 return ret.value;
386 }
387
dbtr_test_type(unsigned long * num_trig)388 static enum McontrolType dbtr_test_type(unsigned long *num_trig)
389 {
390 struct sbiret ret;
391 unsigned long tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL6;
392
393 report_prefix_push("test type");
394 report_prefix_push("sbi_debug_num_triggers");
395
396 ret = sbi_debug_num_triggers(tdata1);
397 sbiret_report_error(&ret, SBI_SUCCESS, "mcontrol6");
398 *num_trig = ret.value;
399 if (ret.value > 0) {
400 report_pass("Returned mcontrol6 triggers available");
401 report_info("Returned %lu mcontrol6 triggers available",
402 ret.value);
403 report_prefix_popn(2);
404 return tdata1;
405 }
406
407 tdata1 = SBI_DBTR_TDATA1_TYPE_MCONTROL;
408
409 ret = sbi_debug_num_triggers(tdata1);
410 sbiret_report_error(&ret, SBI_SUCCESS, "mcontrol");
411 *num_trig = ret.value;
412 if (ret.value > 0) {
413 report_pass("Returned mcontrol triggers available");
414 report_info("Returned %lu mcontrol triggers available",
415 ret.value);
416 report_prefix_popn(2);
417 return tdata1;
418 }
419
420 report_fail("Returned 0 mcontrol(6) triggers available");
421 report_prefix_popn(2);
422
423 return SBI_DBTR_TDATA1_TYPE_NONE;
424 }
425
dbtr_test_store_install_uninstall(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)426 static struct sbiret dbtr_test_store_install_uninstall(struct sbi_dbtr_shmem_entry *shmem,
427 enum McontrolType type)
428 {
429 static unsigned long test;
430 struct sbiret ret;
431
432 report_prefix_push("store trigger");
433
434 shmem->data.tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S);
435 shmem->data.tdata2 = (unsigned long)&test;
436
437 ret = sbi_debug_install_triggers(1);
438 if (!sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_install_triggers")) {
439 report_prefix_pop();
440 return ret;
441 }
442
443 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler);
444
445 report(do_store(&test), "triggered");
446
447 if (do_load(&test))
448 report_fail("triggered by load");
449
450 ret = sbi_debug_uninstall_triggers(0, 1);
451 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers");
452
453 if (do_store(&test))
454 report_fail("triggered after uninstall");
455
456 install_exception_handler(EXC_BREAKPOINT, NULL);
457 report_prefix_pop();
458
459 return ret;
460 }
461
dbtr_test_update(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)462 static void dbtr_test_update(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
463 {
464 static unsigned long test;
465 struct sbiret ret;
466 bool kfail;
467
468 report_prefix_push("update trigger");
469
470 if (!dbtr_install_trigger(shmem, NULL, gen_tdata1(type, VALUE_NONE, MODE_NONE))) {
471 report_prefix_pop();
472 return;
473 }
474
475 shmem->id.idx = 0;
476 shmem->data.tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S);
477 shmem->data.tdata2 = (unsigned long)&test;
478
479 ret = sbi_debug_update_triggers(1);
480 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_update_triggers");
481
482 /*
483 * Known broken update_triggers.
484 * https://lore.kernel.org/opensbi/aDdp1UeUh7GugeHp@ghost/T/#t
485 */
486 kfail = __sbi_get_imp_id() == SBI_IMPL_OPENSBI &&
487 __sbi_get_imp_version() < sbi_impl_opensbi_mk_version(1, 7);
488 report_kfail(kfail, do_store(&test), "triggered");
489
490 dbtr_uninstall_trigger();
491 report_prefix_pop();
492 }
493
dbtr_test_load(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)494 static void dbtr_test_load(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
495 {
496 static unsigned long test;
497
498 report_prefix_push("load trigger");
499 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_LOAD, MODE_S))) {
500 report_prefix_pop();
501 return;
502 }
503
504 report(do_load(&test), "triggered");
505
506 if (do_store(&test))
507 report_fail("triggered by store");
508
509 dbtr_uninstall_trigger();
510 report_prefix_pop();
511 }
512
dbtr_test_disable_enable(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)513 static void dbtr_test_disable_enable(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
514 {
515 static unsigned long test;
516 struct sbiret ret;
517
518 report_prefix_push("disable trigger");
519 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) {
520 report_prefix_pop();
521 return;
522 }
523
524 ret = sbi_debug_disable_triggers(0, 1);
525 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_disable_triggers");
526
527 if (!report(!do_store(&test), "should not trigger")) {
528 dbtr_uninstall_trigger();
529 report_prefix_pop();
530 report_skip("enable trigger: no disable");
531
532 return;
533 }
534
535 report_prefix_pop();
536 report_prefix_push("enable trigger");
537
538 ret = sbi_debug_enable_triggers(0, 1);
539 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_enable_triggers");
540
541 report(do_store(&test), "triggered");
542
543 dbtr_uninstall_trigger();
544 report_prefix_pop();
545 }
546
dbtr_test_exec(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)547 static void dbtr_test_exec(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
548 {
549 static unsigned long test;
550
551 report_prefix_push("exec trigger");
552 /* check if loads and stores trigger exec */
553 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) {
554 report_prefix_pop();
555 return;
556 }
557
558 if (do_load(&test))
559 report_fail("triggered by load");
560
561 if (do_store(&test))
562 report_fail("triggered by store");
563
564 dbtr_uninstall_trigger();
565
566 /* Check if exec works */
567 if (!dbtr_install_trigger(shmem, exec_call, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) {
568 report_prefix_pop();
569 return;
570 }
571 report(do_exec(), "triggered");
572
573 dbtr_uninstall_trigger();
574 report_prefix_pop();
575 }
576
dbtr_test_read(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)577 static void dbtr_test_read(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
578 {
579 const unsigned long tstatus_expected = SBI_DBTR_TRIG_STATE_S | SBI_DBTR_TRIG_STATE_MAPPED;
580 const unsigned long tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S);
581 static unsigned long test;
582 struct sbiret ret;
583
584 report_prefix_push("read trigger");
585 if (!dbtr_install_trigger(shmem, &test, tdata1)) {
586 report_prefix_pop();
587 return;
588 }
589
590 ret = sbi_debug_read_triggers(0, 1);
591 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_read_triggers");
592
593 if (!report(shmem->data.tdata1 == tdata1, "tdata1 expected: 0x%016lx", tdata1))
594 report_info("tdata1 found: 0x%016lx", shmem->data.tdata1);
595 if (!report(shmem->data.tdata2 == ((unsigned long)&test), "tdata2 expected: 0x%016lx",
596 (unsigned long)&test))
597 report_info("tdata2 found: 0x%016lx", shmem->data.tdata2);
598 if (!report(shmem->data.tstate == tstatus_expected, "tstate expected: 0x%016lx", tstatus_expected))
599 report_info("tstate found: 0x%016lx", shmem->data.tstate);
600
601 dbtr_uninstall_trigger();
602 report_prefix_pop();
603 }
604
check_exec(unsigned long base)605 static void check_exec(unsigned long base)
606 {
607 struct sbiret ret;
608
609 report(do_exec(), "exec triggered");
610
611 ret = sbi_debug_uninstall_triggers(base, 1);
612 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers");
613 }
614
dbtr_test_multiple(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type,unsigned long num_trigs)615 static void dbtr_test_multiple(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type,
616 unsigned long num_trigs)
617 {
618 static unsigned long test[2];
619 struct sbiret ret;
620 bool have_three = num_trigs > 2;
621
622 if (num_trigs < 2) {
623 report_skip("test multiple");
624 return;
625 }
626
627 report_prefix_push("test multiple");
628
629 if (!dbtr_install_trigger(shmem, &test[0], gen_tdata1(type, VALUE_STORE, MODE_S))) {
630 report_prefix_pop();
631 return;
632 }
633 if (!dbtr_install_trigger(shmem, &test[1], gen_tdata1(type, VALUE_LOAD, MODE_S)))
634 goto error;
635 if (have_three &&
636 !dbtr_install_trigger(shmem, exec_call, gen_tdata1(type, VALUE_EXECUTE, MODE_S))) {
637 ret = sbi_debug_uninstall_triggers(1, 1);
638 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers");
639 goto error;
640 }
641
642 report(do_store(&test[0]), "store triggered");
643
644 if (do_load(&test[0]))
645 report_fail("store triggered by load");
646
647 report(do_load(&test[1]), "load triggered");
648
649 if (do_store(&test[1]))
650 report_fail("load triggered by store");
651
652 if (have_three)
653 check_exec(2);
654
655 ret = sbi_debug_uninstall_triggers(1, 1);
656 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers");
657
658 if (do_load(&test[1]))
659 report_fail("load triggered after uninstall");
660
661 report(do_store(&test[0]), "store triggered");
662
663 if (!have_three &&
664 dbtr_install_trigger(shmem, exec_call, gen_tdata1(type, VALUE_EXECUTE, MODE_S)))
665 check_exec(1);
666
667 error:
668 ret = sbi_debug_uninstall_triggers(0, 1);
669 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_uninstall_triggers");
670
671 install_exception_handler(EXC_BREAKPOINT, NULL);
672 report_prefix_pop();
673 }
674
dbtr_test_multiple_types(struct sbi_dbtr_shmem_entry * shmem,unsigned long type)675 static void dbtr_test_multiple_types(struct sbi_dbtr_shmem_entry *shmem, unsigned long type)
676 {
677 static unsigned long test;
678
679 report_prefix_push("test multiple types");
680
681 /* check if loads and stores trigger exec */
682 if (!dbtr_install_trigger(shmem, &test,
683 gen_tdata1(type, VALUE_EXECUTE | VALUE_LOAD | VALUE_STORE, MODE_S))) {
684 report_prefix_pop();
685 return;
686 }
687
688 report(do_load(&test), "load triggered");
689
690 report(do_store(&test), "store triggered");
691
692 dbtr_uninstall_trigger();
693
694 /* Check if exec works */
695 if (!dbtr_install_trigger(shmem, exec_call,
696 gen_tdata1(type, VALUE_EXECUTE | VALUE_LOAD | VALUE_STORE, MODE_S))) {
697 report_prefix_pop();
698 return;
699 }
700
701 report(do_exec(), "exec triggered");
702
703 dbtr_uninstall_trigger();
704 report_prefix_pop();
705 }
706
dbtr_test_disable_uninstall(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)707 static void dbtr_test_disable_uninstall(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
708 {
709 static unsigned long test;
710 struct sbiret ret;
711
712 report_prefix_push("disable uninstall");
713 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) {
714 report_prefix_pop();
715 return;
716 }
717
718 ret = sbi_debug_disable_triggers(0, 1);
719 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_disable_triggers");
720
721 dbtr_uninstall_trigger();
722
723 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) {
724 report_prefix_pop();
725 return;
726 }
727
728 report(do_store(&test), "triggered");
729
730 dbtr_uninstall_trigger();
731 report_prefix_pop();
732 }
733
dbtr_test_uninstall_enable(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)734 static void dbtr_test_uninstall_enable(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
735 {
736 static unsigned long test;
737 struct sbiret ret;
738
739 report_prefix_push("uninstall enable");
740 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) {
741 report_prefix_pop();
742 return;
743 }
744 dbtr_uninstall_trigger();
745
746 ret = sbi_debug_enable_triggers(0, 1);
747 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_enable_triggers");
748
749 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler);
750
751 report(!do_store(&test), "should not trigger");
752
753 install_exception_handler(EXC_BREAKPOINT, NULL);
754 report_prefix_pop();
755 }
756
dbtr_test_uninstall_update(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)757 static void dbtr_test_uninstall_update(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
758 {
759 static unsigned long test;
760 struct sbiret ret;
761 bool kfail;
762
763 report_prefix_push("uninstall update");
764 if (!dbtr_install_trigger(shmem, NULL, gen_tdata1(type, VALUE_NONE, MODE_NONE))) {
765 report_prefix_pop();
766 return;
767 }
768
769 dbtr_uninstall_trigger();
770
771 shmem->id.idx = 0;
772 shmem->data.tdata1 = gen_tdata1(type, VALUE_STORE, MODE_S);
773 shmem->data.tdata2 = (unsigned long)&test;
774
775 /*
776 * Known broken update_triggers.
777 * https://lore.kernel.org/opensbi/aDdp1UeUh7GugeHp@ghost/T/#t
778 */
779 kfail = __sbi_get_imp_id() == SBI_IMPL_OPENSBI &&
780 __sbi_get_imp_version() < sbi_impl_opensbi_mk_version(1, 7);
781 ret = sbi_debug_update_triggers(1);
782 sbiret_kfail_error(kfail, &ret, SBI_ERR_FAILURE, "sbi_debug_update_triggers");
783
784 install_exception_handler(EXC_BREAKPOINT, dbtr_exception_handler);
785
786 report(!do_store(&test), "should not trigger");
787
788 install_exception_handler(EXC_BREAKPOINT, NULL);
789 report_prefix_pop();
790 }
791
dbtr_test_disable_read(struct sbi_dbtr_shmem_entry * shmem,enum McontrolType type)792 static void dbtr_test_disable_read(struct sbi_dbtr_shmem_entry *shmem, enum McontrolType type)
793 {
794 const unsigned long tstatus_expected = SBI_DBTR_TRIG_STATE_S | SBI_DBTR_TRIG_STATE_MAPPED;
795 const unsigned long tdata1 = gen_tdata1(type, VALUE_STORE, MODE_NONE);
796 static unsigned long test;
797 struct sbiret ret;
798
799 report_prefix_push("disable read");
800 if (!dbtr_install_trigger(shmem, &test, gen_tdata1(type, VALUE_STORE, MODE_S))) {
801 report_prefix_pop();
802 return;
803 }
804
805 ret = sbi_debug_disable_triggers(0, 1);
806 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_disable_triggers");
807
808 ret = sbi_debug_read_triggers(0, 1);
809 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_read_triggers");
810
811 if (!report(shmem->data.tdata1 == tdata1, "tdata1 expected: 0x%016lx", tdata1))
812 report_info("tdata1 found: 0x%016lx", shmem->data.tdata1);
813 if (!report(shmem->data.tdata2 == ((unsigned long)&test), "tdata2 expected: 0x%016lx",
814 (unsigned long)&test))
815 report_info("tdata2 found: 0x%016lx", shmem->data.tdata2);
816 if (!report(shmem->data.tstate == tstatus_expected, "tstate expected: 0x%016lx", tstatus_expected))
817 report_info("tstate found: 0x%016lx", shmem->data.tstate);
818
819 dbtr_uninstall_trigger();
820 report_prefix_pop();
821 }
822
check_dbtr(void)823 void check_dbtr(void)
824 {
825 static struct sbi_dbtr_shmem_entry shmem[RV_MAX_TRIGGERS] = {};
826 unsigned long num_trigs;
827 enum McontrolType trig_type;
828 struct sbiret ret;
829
830 report_prefix_push("dbtr");
831
832 if (!sbi_probe(SBI_EXT_DBTR)) {
833 report_skip("extension not available");
834 goto exit_test;
835 }
836
837 num_trigs = dbtr_test_num_triggers();
838 if (!num_trigs)
839 goto exit_test;
840
841 trig_type = dbtr_test_type(&num_trigs);
842 if (trig_type == SBI_DBTR_TDATA1_TYPE_NONE)
843 goto exit_test;
844
845 ret = sbi_debug_set_shmem(shmem);
846 sbiret_report_error(&ret, SBI_SUCCESS, "sbi_debug_set_shmem");
847
848 ret = dbtr_test_store_install_uninstall(&shmem[0], trig_type);
849 /* install or uninstall failed */
850 if (ret.error != SBI_SUCCESS)
851 goto exit_test;
852
853 dbtr_test_load(&shmem[0], trig_type);
854 dbtr_test_exec(&shmem[0], trig_type);
855 dbtr_test_read(&shmem[0], trig_type);
856 dbtr_test_disable_enable(&shmem[0], trig_type);
857 dbtr_test_update(&shmem[0], trig_type);
858 dbtr_test_multiple_types(&shmem[0], trig_type);
859 dbtr_test_multiple(shmem, trig_type, num_trigs);
860 dbtr_test_disable_uninstall(&shmem[0], trig_type);
861 dbtr_test_uninstall_enable(&shmem[0], trig_type);
862 dbtr_test_uninstall_update(&shmem[0], trig_type);
863 dbtr_test_disable_read(&shmem[0], trig_type);
864
865 exit_test:
866 report_prefix_pop();
867 }
868