1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_util.h>
3 #include <kvm_util.h>
4 #include <processor.h>
5 
6 #define MDSCR_KDE	(1 << 13)
7 #define MDSCR_MDE	(1 << 15)
8 #define MDSCR_SS	(1 << 0)
9 
10 #define DBGBCR_LEN8	(0xff << 5)
11 #define DBGBCR_EXEC	(0x0 << 3)
12 #define DBGBCR_EL1	(0x1 << 1)
13 #define DBGBCR_E	(0x1 << 0)
14 
15 #define DBGWCR_LEN8	(0xff << 5)
16 #define DBGWCR_RD	(0x1 << 3)
17 #define DBGWCR_WR	(0x2 << 3)
18 #define DBGWCR_EL1	(0x1 << 1)
19 #define DBGWCR_E	(0x1 << 0)
20 
21 #define SPSR_D		(1 << 9)
22 #define SPSR_SS		(1 << 21)
23 
24 extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start;
25 static volatile uint64_t sw_bp_addr, hw_bp_addr;
26 static volatile uint64_t wp_addr, wp_data_addr;
27 static volatile uint64_t svc_addr;
28 static volatile uint64_t ss_addr[4], ss_idx;
29 #define  PC(v)  ((uint64_t)&(v))
30 
31 static void reset_debug_state(void)
32 {
33 	asm volatile("msr daifset, #8");
34 
35 	write_sysreg(0, osdlr_el1);
36 	write_sysreg(0, oslar_el1);
37 	isb();
38 
39 	write_sysreg(0, mdscr_el1);
40 	/* This test only uses the first bp and wp slot. */
41 	write_sysreg(0, dbgbvr0_el1);
42 	write_sysreg(0, dbgbcr0_el1);
43 	write_sysreg(0, dbgwcr0_el1);
44 	write_sysreg(0, dbgwvr0_el1);
45 	isb();
46 }
47 
48 static void enable_os_lock(void)
49 {
50 	write_sysreg(1, oslar_el1);
51 	isb();
52 
53 	GUEST_ASSERT(read_sysreg(oslsr_el1) & 2);
54 }
55 
56 static void install_wp(uint64_t addr)
57 {
58 	uint32_t wcr;
59 	uint32_t mdscr;
60 
61 	wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E;
62 	write_sysreg(wcr, dbgwcr0_el1);
63 	write_sysreg(addr, dbgwvr0_el1);
64 	isb();
65 
66 	asm volatile("msr daifclr, #8");
67 
68 	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
69 	write_sysreg(mdscr, mdscr_el1);
70 	isb();
71 }
72 
73 static void install_hw_bp(uint64_t addr)
74 {
75 	uint32_t bcr;
76 	uint32_t mdscr;
77 
78 	bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E;
79 	write_sysreg(bcr, dbgbcr0_el1);
80 	write_sysreg(addr, dbgbvr0_el1);
81 	isb();
82 
83 	asm volatile("msr daifclr, #8");
84 
85 	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
86 	write_sysreg(mdscr, mdscr_el1);
87 	isb();
88 }
89 
90 static void install_ss(void)
91 {
92 	uint32_t mdscr;
93 
94 	asm volatile("msr daifclr, #8");
95 
96 	mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_SS;
97 	write_sysreg(mdscr, mdscr_el1);
98 	isb();
99 }
100 
101 static volatile char write_data;
102 
103 static void guest_code(void)
104 {
105 	GUEST_SYNC(0);
106 
107 	/* Software-breakpoint */
108 	reset_debug_state();
109 	asm volatile("sw_bp: brk #0");
110 	GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp));
111 
112 	GUEST_SYNC(1);
113 
114 	/* Hardware-breakpoint */
115 	reset_debug_state();
116 	install_hw_bp(PC(hw_bp));
117 	asm volatile("hw_bp: nop");
118 	GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp));
119 
120 	GUEST_SYNC(2);
121 
122 	/* Hardware-breakpoint + svc */
123 	reset_debug_state();
124 	install_hw_bp(PC(bp_svc));
125 	asm volatile("bp_svc: svc #0");
126 	GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_svc));
127 	GUEST_ASSERT_EQ(svc_addr, PC(bp_svc) + 4);
128 
129 	GUEST_SYNC(3);
130 
131 	/* Hardware-breakpoint + software-breakpoint */
132 	reset_debug_state();
133 	install_hw_bp(PC(bp_brk));
134 	asm volatile("bp_brk: brk #0");
135 	GUEST_ASSERT_EQ(sw_bp_addr, PC(bp_brk));
136 	GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_brk));
137 
138 	GUEST_SYNC(4);
139 
140 	/* Watchpoint */
141 	reset_debug_state();
142 	install_wp(PC(write_data));
143 	write_data = 'x';
144 	GUEST_ASSERT_EQ(write_data, 'x');
145 	GUEST_ASSERT_EQ(wp_data_addr, PC(write_data));
146 
147 	GUEST_SYNC(5);
148 
149 	/* Single-step */
150 	reset_debug_state();
151 	install_ss();
152 	ss_idx = 0;
153 	asm volatile("ss_start:\n"
154 		     "mrs x0, esr_el1\n"
155 		     "add x0, x0, #1\n"
156 		     "msr daifset, #8\n"
157 		     : : : "x0");
158 	GUEST_ASSERT_EQ(ss_addr[0], PC(ss_start));
159 	GUEST_ASSERT_EQ(ss_addr[1], PC(ss_start) + 4);
160 	GUEST_ASSERT_EQ(ss_addr[2], PC(ss_start) + 8);
161 
162 	GUEST_SYNC(6);
163 
164 	/* OS Lock does not block software-breakpoint */
165 	reset_debug_state();
166 	enable_os_lock();
167 	sw_bp_addr = 0;
168 	asm volatile("sw_bp2: brk #0");
169 	GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp2));
170 
171 	GUEST_SYNC(7);
172 
173 	/* OS Lock blocking hardware-breakpoint */
174 	reset_debug_state();
175 	enable_os_lock();
176 	install_hw_bp(PC(hw_bp2));
177 	hw_bp_addr = 0;
178 	asm volatile("hw_bp2: nop");
179 	GUEST_ASSERT_EQ(hw_bp_addr, 0);
180 
181 	GUEST_SYNC(8);
182 
183 	/* OS Lock blocking watchpoint */
184 	reset_debug_state();
185 	enable_os_lock();
186 	write_data = '\0';
187 	wp_data_addr = 0;
188 	install_wp(PC(write_data));
189 	write_data = 'x';
190 	GUEST_ASSERT_EQ(write_data, 'x');
191 	GUEST_ASSERT_EQ(wp_data_addr, 0);
192 
193 	GUEST_SYNC(9);
194 
195 	/* OS Lock blocking single-step */
196 	reset_debug_state();
197 	enable_os_lock();
198 	ss_addr[0] = 0;
199 	install_ss();
200 	ss_idx = 0;
201 	asm volatile("mrs x0, esr_el1\n\t"
202 		     "add x0, x0, #1\n\t"
203 		     "msr daifset, #8\n\t"
204 		     : : : "x0");
205 	GUEST_ASSERT_EQ(ss_addr[0], 0);
206 
207 	GUEST_DONE();
208 }
209 
210 static void guest_sw_bp_handler(struct ex_regs *regs)
211 {
212 	sw_bp_addr = regs->pc;
213 	regs->pc += 4;
214 }
215 
216 static void guest_hw_bp_handler(struct ex_regs *regs)
217 {
218 	hw_bp_addr = regs->pc;
219 	regs->pstate |= SPSR_D;
220 }
221 
222 static void guest_wp_handler(struct ex_regs *regs)
223 {
224 	wp_data_addr = read_sysreg(far_el1);
225 	wp_addr = regs->pc;
226 	regs->pstate |= SPSR_D;
227 }
228 
229 static void guest_ss_handler(struct ex_regs *regs)
230 {
231 	GUEST_ASSERT_1(ss_idx < 4, ss_idx);
232 	ss_addr[ss_idx++] = regs->pc;
233 	regs->pstate |= SPSR_SS;
234 }
235 
236 static void guest_svc_handler(struct ex_regs *regs)
237 {
238 	svc_addr = regs->pc;
239 }
240 
241 static int debug_version(struct kvm_vcpu *vcpu)
242 {
243 	uint64_t id_aa64dfr0;
244 
245 	vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0);
246 	return id_aa64dfr0 & 0xf;
247 }
248 
249 int main(int argc, char *argv[])
250 {
251 	struct kvm_vcpu *vcpu;
252 	struct kvm_vm *vm;
253 	struct ucall uc;
254 	int stage;
255 
256 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
257 	ucall_init(vm, NULL);
258 
259 	vm_init_descriptor_tables(vm);
260 	vcpu_init_descriptor_tables(vcpu);
261 
262 	__TEST_REQUIRE(debug_version(vcpu) >= 6,
263 		       "Armv8 debug architecture not supported.");
264 
265 	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
266 				ESR_EC_BRK_INS, guest_sw_bp_handler);
267 	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
268 				ESR_EC_HW_BP_CURRENT, guest_hw_bp_handler);
269 	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
270 				ESR_EC_WP_CURRENT, guest_wp_handler);
271 	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
272 				ESR_EC_SSTEP_CURRENT, guest_ss_handler);
273 	vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
274 				ESR_EC_SVC64, guest_svc_handler);
275 
276 	for (stage = 0; stage < 11; stage++) {
277 		vcpu_run(vcpu);
278 
279 		switch (get_ucall(vcpu, &uc)) {
280 		case UCALL_SYNC:
281 			TEST_ASSERT(uc.args[1] == stage,
282 				"Stage %d: Unexpected sync ucall, got %lx",
283 				stage, (ulong)uc.args[1]);
284 			break;
285 		case UCALL_ABORT:
286 			REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx");
287 			break;
288 		case UCALL_DONE:
289 			goto done;
290 		default:
291 			TEST_FAIL("Unknown ucall %lu", uc.cmd);
292 		}
293 	}
294 
295 done:
296 	kvm_vm_free(vm);
297 	return 0;
298 }
299