xref: /kvm-unit-tests/riscv/sbi-dbtr.c (revision f81e4fa4e7cfeefd6d97e6a8f7d57951277af4f8)
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 */
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 arch, -c\n"
138 		      "nop\n"
139 		      "ret\n"
140 		      ".option pop\n");
141 }
142 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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