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