Skip to content

Commit 4f05223

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: Add aarch64/debug-exceptions test
Covers fundamental tests for debug exceptions. The guest installs and handle its debug exceptions itself, without KVM_SET_GUEST_DEBUG. Signed-off-by: Ricardo Koller <ricarkol@google.com> Reviewed-by: Andrew Jones <drjones@redhat.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20210611011020.3420067-7-ricarkol@google.com
1 parent e3db757 commit 4f05223

4 files changed

Lines changed: 268 additions & 6 deletions

File tree

tools/testing/selftests/kvm/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
2+
/aarch64/debug-exceptions
23
/aarch64/get-reg-list
34
/aarch64/get-reg-list-sve
45
/aarch64/vgic_init

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ TEST_GEN_PROGS_x86_64 += memslot_perf_test
7878
TEST_GEN_PROGS_x86_64 += set_memory_region_test
7979
TEST_GEN_PROGS_x86_64 += steal_time
8080

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

tools/testing/selftests/kvm/include/aarch64/processor.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
#define ARM64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
1515
KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
1616

17-
#define CPACR_EL1 3, 0, 1, 0, 2
18-
#define TCR_EL1 3, 0, 2, 0, 2
19-
#define MAIR_EL1 3, 0, 10, 2, 0
20-
#define TTBR0_EL1 3, 0, 2, 0, 0
21-
#define SCTLR_EL1 3, 0, 1, 0, 0
22-
#define VBAR_EL1 3, 0, 12, 0, 0
17+
#define CPACR_EL1 3, 0, 1, 0, 2
18+
#define TCR_EL1 3, 0, 2, 0, 2
19+
#define MAIR_EL1 3, 0, 10, 2, 0
20+
#define TTBR0_EL1 3, 0, 2, 0, 0
21+
#define SCTLR_EL1 3, 0, 1, 0, 0
22+
#define VBAR_EL1 3, 0, 12, 0, 0
23+
24+
#define ID_AA64DFR0_EL1 3, 0, 0, 5, 0
2325

2426
/*
2527
* Default MAIR
@@ -98,6 +100,12 @@ enum {
98100
#define ESR_EC_SHIFT 26
99101
#define ESR_EC_MASK (ESR_EC_NUM - 1)
100102

103+
#define ESR_EC_SVC64 0x15
104+
#define ESR_EC_HW_BP_CURRENT 0x31
105+
#define ESR_EC_SSTEP_CURRENT 0x33
106+
#define ESR_EC_WP_CURRENT 0x35
107+
#define ESR_EC_BRK_INS 0x3c
108+
101109
void vm_init_descriptor_tables(struct kvm_vm *vm);
102110
void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
103111

@@ -119,4 +127,6 @@ void vm_install_sync_handler(struct kvm_vm *vm,
119127
val; \
120128
})
121129

130+
#define isb() asm volatile("isb" : : : "memory")
131+
122132
#endif /* SELFTEST_KVM_PROCESSOR_H */

0 commit comments

Comments
 (0)