xref: /linux/tools/testing/selftests/kvm/arm64/vgic_v5.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/kernel.h>
4 #include <sys/syscall.h>
5 #include <asm/kvm.h>
6 #include <asm/kvm_para.h>
7 
8 #include <arm64/gic_v5.h>
9 
10 #include "test_util.h"
11 #include "kvm_util.h"
12 #include "processor.h"
13 #include "vgic.h"
14 
15 #define NR_VCPUS		1
16 
17 struct vm_gic {
18 	struct kvm_vm *vm;
19 	int gic_fd;
20 	u32 gic_dev_type;
21 };
22 
23 #define GUEST_CMD_IRQ_CDIA	10
24 #define GUEST_CMD_IRQ_DIEOI	11
25 #define GUEST_CMD_IS_AWAKE	12
26 #define GUEST_CMD_IS_READY	13
27 
28 static void guest_irq_handler(struct ex_regs *regs)
29 {
30 	bool valid;
31 	u32 hwirq;
32 	u64 ia;
33 	static int count;
34 
35 	/*
36 	 * We have pending interrupts. Should never actually enter WFI
37 	 * here!
38 	 */
39 	wfi();
40 	GUEST_SYNC(GUEST_CMD_IS_AWAKE);
41 
42 	ia = gicr_insn(CDIA);
43 	valid = GICV5_GICR_CDIA_VALID(ia);
44 
45 	GUEST_SYNC(GUEST_CMD_IRQ_CDIA);
46 
47 	if (!valid)
48 		return;
49 
50 	gsb_ack();
51 	isb();
52 
53 	hwirq = FIELD_GET(GICV5_GICR_CDIA_INTID, ia);
54 
55 	gic_insn(hwirq, CDDI);
56 	gic_insn(0, CDEOI);
57 
58 	GUEST_SYNC(GUEST_CMD_IRQ_DIEOI);
59 
60 	if (++count >= 2)
61 		GUEST_DONE();
62 
63 	/* Ask for the next interrupt to be injected */
64 	GUEST_SYNC(GUEST_CMD_IS_READY);
65 }
66 
67 static void guest_code(void)
68 {
69 	local_irq_disable();
70 
71 	gicv5_cpu_enable_interrupts();
72 	local_irq_enable();
73 
74 	/* Enable the SW_PPI (3) */
75 	write_sysreg_s(BIT_ULL(3), SYS_ICC_PPI_ENABLER0_EL1);
76 
77 	/* Ask for the first interrupt to be injected */
78 	GUEST_SYNC(GUEST_CMD_IS_READY);
79 
80 	/* Loop forever waiting for interrupts */
81 	while (1);
82 }
83 
84 
85 /* we don't want to assert on run execution, hence that helper */
86 static int run_vcpu(struct kvm_vcpu *vcpu)
87 {
88 	return __vcpu_run(vcpu) ? -errno : 0;
89 }
90 
91 static void vm_gic_destroy(struct vm_gic *v)
92 {
93 	close(v->gic_fd);
94 	kvm_vm_free(v->vm);
95 }
96 
97 static void test_vgic_v5_ppis(u32 gic_dev_type)
98 {
99 	struct kvm_vcpu *vcpus[NR_VCPUS];
100 	struct ucall uc;
101 	u64 user_ppis[2];
102 	struct vm_gic v;
103 	int ret, i;
104 
105 	v.gic_dev_type = gic_dev_type;
106 	v.vm = __vm_create(VM_SHAPE_DEFAULT, NR_VCPUS, 0);
107 
108 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
109 
110 	for (i = 0; i < NR_VCPUS; i++)
111 		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
112 
113 	vm_init_descriptor_tables(v.vm);
114 	vm_install_exception_handler(v.vm, VECTOR_IRQ_CURRENT, guest_irq_handler);
115 
116 	for (i = 0; i < NR_VCPUS; i++)
117 		vcpu_init_descriptor_tables(vcpus[i]);
118 
119 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
120 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
121 
122 	/* Read out the PPIs that user space is allowed to drive. */
123 	kvm_device_attr_get(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
124 			    KVM_DEV_ARM_VGIC_USERSPACE_PPIS, &user_ppis);
125 
126 	/* We should always be able to drive the SW_PPI. */
127 	TEST_ASSERT(user_ppis[0] & BIT(GICV5_ARCH_PPI_SW_PPI),
128 		"SW_PPI is not drivable by userspace");
129 
130 	while (1) {
131 		ret = run_vcpu(vcpus[0]);
132 		if (ret)
133 			break;
134 
135 		switch (get_ucall(vcpus[0], &uc)) {
136 		case UCALL_SYNC:
137 			/*
138 			 * The guest is ready for the next level change. Set
139 			 * high if ready, and lower if it has been consumed.
140 			 */
141 			if (uc.args[1] == GUEST_CMD_IS_READY ||
142 			    uc.args[1] == GUEST_CMD_IRQ_DIEOI) {
143 				u64 irq;
144 				bool level = uc.args[1] == GUEST_CMD_IRQ_DIEOI ? 0 : 1;
145 
146 				irq = FIELD_PREP(KVM_ARM_IRQ_NUM_MASK, 3);
147 				irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
148 
149 				kvm_irq_line(v.vm, irq, level);
150 			} else if (uc.args[1] == GUEST_CMD_IS_AWAKE) {
151 				pr_info("Guest skipping WFI due to pending IRQ\n");
152 			} else if (uc.args[1] == GUEST_CMD_IRQ_CDIA) {
153 				pr_info("Guest acknowledged IRQ\n");
154 			}
155 
156 			continue;
157 		case UCALL_ABORT:
158 			REPORT_GUEST_ASSERT(uc);
159 			break;
160 		case UCALL_DONE:
161 			goto done;
162 		default:
163 			TEST_FAIL("Unknown ucall %lu", uc.cmd);
164 		}
165 	}
166 
167 done:
168 	TEST_ASSERT(ret == 0, "Failed to test GICv5 PPIs");
169 
170 	vm_gic_destroy(&v);
171 }
172 
173 /*
174  * Returns 0 if it's possible to create GIC device of a given type (V5).
175  */
176 int test_kvm_device(u32 gic_dev_type)
177 {
178 	struct kvm_vcpu *vcpus[NR_VCPUS];
179 	struct vm_gic v;
180 	int ret;
181 
182 	v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
183 
184 	/* try to create a non existing KVM device */
185 	ret = __kvm_test_create_device(v.vm, 0);
186 	TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
187 
188 	/* trial mode */
189 	ret = __kvm_test_create_device(v.vm, gic_dev_type);
190 	if (ret)
191 		return ret;
192 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
193 
194 	ret = __kvm_create_device(v.vm, gic_dev_type);
195 	TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
196 
197 	vm_gic_destroy(&v);
198 
199 	return 0;
200 }
201 
202 void run_tests(u32 gic_dev_type)
203 {
204 	pr_info("Test VGICv5 PPIs\n");
205 	test_vgic_v5_ppis(gic_dev_type);
206 }
207 
208 int main(int ac, char **av)
209 {
210 	int ret;
211 
212 	test_disable_default_vgic();
213 
214 	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V5);
215 	if (ret) {
216 		pr_info("No GICv5 support; Not running GIC_v5 tests.\n");
217 		exit(KSFT_SKIP);
218 	}
219 
220 	pr_info("Running VGIC_V5 tests.\n");
221 	run_tests(KVM_DEV_TYPE_ARM_VGIC_V5);
222 
223 	return 0;
224 }
225