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