Skip to content

Commit de2e752

Browse files
author
Marc Zyngier
committed
KVM: arm64: Add selftest checking how the absence of GICv3 is handled
Given how tortuous and fragile the whole lack-of-GICv3 story is, add a selftest checking that we don't regress it. Reviewed-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent cd08d32 commit de2e752

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
163163
TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq
164164
TEST_GEN_PROGS_aarch64 += aarch64/vgic_lpi_stress
165165
TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access
166+
TEST_GEN_PROGS_aarch64 += aarch64/no-vgic-v3
166167
TEST_GEN_PROGS_aarch64 += access_tracking_perf_test
167168
TEST_GEN_PROGS_aarch64 += arch_timer
168169
TEST_GEN_PROGS_aarch64 += demand_paging_test
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
// Check that, on a GICv3 system, not configuring GICv3 correctly
4+
// results in all of the sysregs generating an UNDEF exception.
5+
6+
#include <test_util.h>
7+
#include <kvm_util.h>
8+
#include <processor.h>
9+
10+
static volatile bool handled;
11+
12+
#define __check_sr_read(r) \
13+
({ \
14+
uint64_t val; \
15+
\
16+
handled = false; \
17+
dsb(sy); \
18+
val = read_sysreg_s(SYS_ ## r); \
19+
val; \
20+
})
21+
22+
#define __check_sr_write(r) \
23+
do { \
24+
handled = false; \
25+
dsb(sy); \
26+
write_sysreg_s(0, SYS_ ## r); \
27+
isb(); \
28+
} while(0)
29+
30+
/* Fatal checks */
31+
#define check_sr_read(r) \
32+
do { \
33+
__check_sr_read(r); \
34+
__GUEST_ASSERT(handled, #r " no read trap"); \
35+
} while(0)
36+
37+
#define check_sr_write(r) \
38+
do { \
39+
__check_sr_write(r); \
40+
__GUEST_ASSERT(handled, #r " no write trap"); \
41+
} while(0)
42+
43+
#define check_sr_rw(r) \
44+
do { \
45+
check_sr_read(r); \
46+
check_sr_write(r); \
47+
} while(0)
48+
49+
static void guest_code(void)
50+
{
51+
uint64_t val;
52+
53+
/*
54+
* Check that we advertise that ID_AA64PFR0_EL1.GIC == 0, having
55+
* hidden the feature at runtime without any other userspace action.
56+
*/
57+
__GUEST_ASSERT(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC),
58+
read_sysreg(id_aa64pfr0_el1)) == 0,
59+
"GICv3 wrongly advertised");
60+
61+
/*
62+
* Access all GICv3 registers, and fail if we don't get an UNDEF.
63+
* Note that we happily access all the APxRn registers without
64+
* checking their existance, as all we want to see is a failure.
65+
*/
66+
check_sr_rw(ICC_PMR_EL1);
67+
check_sr_read(ICC_IAR0_EL1);
68+
check_sr_write(ICC_EOIR0_EL1);
69+
check_sr_rw(ICC_HPPIR0_EL1);
70+
check_sr_rw(ICC_BPR0_EL1);
71+
check_sr_rw(ICC_AP0R0_EL1);
72+
check_sr_rw(ICC_AP0R1_EL1);
73+
check_sr_rw(ICC_AP0R2_EL1);
74+
check_sr_rw(ICC_AP0R3_EL1);
75+
check_sr_rw(ICC_AP1R0_EL1);
76+
check_sr_rw(ICC_AP1R1_EL1);
77+
check_sr_rw(ICC_AP1R2_EL1);
78+
check_sr_rw(ICC_AP1R3_EL1);
79+
check_sr_write(ICC_DIR_EL1);
80+
check_sr_read(ICC_RPR_EL1);
81+
check_sr_write(ICC_SGI1R_EL1);
82+
check_sr_write(ICC_ASGI1R_EL1);
83+
check_sr_write(ICC_SGI0R_EL1);
84+
check_sr_read(ICC_IAR1_EL1);
85+
check_sr_write(ICC_EOIR1_EL1);
86+
check_sr_rw(ICC_HPPIR1_EL1);
87+
check_sr_rw(ICC_BPR1_EL1);
88+
check_sr_rw(ICC_CTLR_EL1);
89+
check_sr_rw(ICC_IGRPEN0_EL1);
90+
check_sr_rw(ICC_IGRPEN1_EL1);
91+
92+
/*
93+
* ICC_SRE_EL1 may not be trappable, as ICC_SRE_EL2.Enable can
94+
* be RAO/WI. Engage in non-fatal accesses, starting with a
95+
* write of 0 to try and disable SRE, and let's see if it
96+
* sticks.
97+
*/
98+
__check_sr_write(ICC_SRE_EL1);
99+
if (!handled)
100+
GUEST_PRINTF("ICC_SRE_EL1 write not trapping (OK)\n");
101+
102+
val = __check_sr_read(ICC_SRE_EL1);
103+
if (!handled) {
104+
__GUEST_ASSERT((val & BIT(0)),
105+
"ICC_SRE_EL1 not trapped but ICC_SRE_EL1.SRE not set\n");
106+
GUEST_PRINTF("ICC_SRE_EL1 read not trapping (OK)\n");
107+
}
108+
109+
GUEST_DONE();
110+
}
111+
112+
static void guest_undef_handler(struct ex_regs *regs)
113+
{
114+
/* Success, we've gracefully exploded! */
115+
handled = true;
116+
regs->pc += 4;
117+
}
118+
119+
static void test_run_vcpu(struct kvm_vcpu *vcpu)
120+
{
121+
struct ucall uc;
122+
123+
do {
124+
vcpu_run(vcpu);
125+
126+
switch (get_ucall(vcpu, &uc)) {
127+
case UCALL_ABORT:
128+
REPORT_GUEST_ASSERT(uc);
129+
break;
130+
case UCALL_PRINTF:
131+
printf("%s", uc.buffer);
132+
break;
133+
case UCALL_DONE:
134+
break;
135+
default:
136+
TEST_FAIL("Unknown ucall %lu", uc.cmd);
137+
}
138+
} while (uc.cmd != UCALL_DONE);
139+
}
140+
141+
static void test_guest_no_gicv3(void)
142+
{
143+
struct kvm_vcpu *vcpu;
144+
struct kvm_vm *vm;
145+
146+
/* Create a VM without a GICv3 */
147+
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
148+
149+
vm_init_descriptor_tables(vm);
150+
vcpu_init_descriptor_tables(vcpu);
151+
152+
vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
153+
ESR_EC_UNKNOWN, guest_undef_handler);
154+
155+
test_run_vcpu(vcpu);
156+
157+
kvm_vm_free(vm);
158+
}
159+
160+
int main(int argc, char *argv[])
161+
{
162+
struct kvm_vcpu *vcpu;
163+
struct kvm_vm *vm;
164+
uint64_t pfr0;
165+
166+
vm = vm_create_with_one_vcpu(&vcpu, NULL);
167+
vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), &pfr0);
168+
__TEST_REQUIRE(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_GIC), pfr0),
169+
"GICv3 not supported.");
170+
kvm_vm_free(vm);
171+
172+
test_guest_no_gicv3();
173+
174+
return 0;
175+
}

0 commit comments

Comments
 (0)