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