xref: /linux/tools/testing/selftests/kvm/arm64/vgic_v5.c (revision 06bc7ff0a1e0f2b0102e1314e3527a7ec0997851)
10a9f38bfSSascha Bischoff // SPDX-License-Identifier: GPL-2.0
20a9f38bfSSascha Bischoff 
30a9f38bfSSascha Bischoff #include <linux/kernel.h>
40a9f38bfSSascha Bischoff #include <sys/syscall.h>
50a9f38bfSSascha Bischoff #include <asm/kvm.h>
60a9f38bfSSascha Bischoff #include <asm/kvm_para.h>
70a9f38bfSSascha Bischoff 
80a9f38bfSSascha Bischoff #include <arm64/gic_v5.h>
90a9f38bfSSascha Bischoff 
100a9f38bfSSascha Bischoff #include "test_util.h"
110a9f38bfSSascha Bischoff #include "kvm_util.h"
120a9f38bfSSascha Bischoff #include "processor.h"
130a9f38bfSSascha Bischoff #include "vgic.h"
140a9f38bfSSascha Bischoff 
150a9f38bfSSascha Bischoff #define NR_VCPUS		1
160a9f38bfSSascha Bischoff 
170a9f38bfSSascha Bischoff struct vm_gic {
180a9f38bfSSascha Bischoff 	struct kvm_vm *vm;
190a9f38bfSSascha Bischoff 	int gic_fd;
20*0c3a8774SDavid Matlack 	u32 gic_dev_type;
210a9f38bfSSascha Bischoff };
220a9f38bfSSascha Bischoff 
2326f84532SDavid Matlack static u64 max_phys_size;
240a9f38bfSSascha Bischoff 
250a9f38bfSSascha Bischoff #define GUEST_CMD_IRQ_CDIA	10
260a9f38bfSSascha Bischoff #define GUEST_CMD_IRQ_DIEOI	11
270a9f38bfSSascha Bischoff #define GUEST_CMD_IS_AWAKE	12
280a9f38bfSSascha Bischoff #define GUEST_CMD_IS_READY	13
290a9f38bfSSascha Bischoff 
guest_irq_handler(struct ex_regs * regs)300a9f38bfSSascha Bischoff static void guest_irq_handler(struct ex_regs *regs)
310a9f38bfSSascha Bischoff {
320a9f38bfSSascha Bischoff 	bool valid;
330a9f38bfSSascha Bischoff 	u32 hwirq;
340a9f38bfSSascha Bischoff 	u64 ia;
350a9f38bfSSascha Bischoff 	static int count;
360a9f38bfSSascha Bischoff 
370a9f38bfSSascha Bischoff 	/*
380a9f38bfSSascha Bischoff 	 * We have pending interrupts. Should never actually enter WFI
390a9f38bfSSascha Bischoff 	 * here!
400a9f38bfSSascha Bischoff 	 */
410a9f38bfSSascha Bischoff 	wfi();
420a9f38bfSSascha Bischoff 	GUEST_SYNC(GUEST_CMD_IS_AWAKE);
430a9f38bfSSascha Bischoff 
440a9f38bfSSascha Bischoff 	ia = gicr_insn(CDIA);
450a9f38bfSSascha Bischoff 	valid = GICV5_GICR_CDIA_VALID(ia);
460a9f38bfSSascha Bischoff 
470a9f38bfSSascha Bischoff 	GUEST_SYNC(GUEST_CMD_IRQ_CDIA);
480a9f38bfSSascha Bischoff 
490a9f38bfSSascha Bischoff 	if (!valid)
500a9f38bfSSascha Bischoff 		return;
510a9f38bfSSascha Bischoff 
520a9f38bfSSascha Bischoff 	gsb_ack();
530a9f38bfSSascha Bischoff 	isb();
540a9f38bfSSascha Bischoff 
550a9f38bfSSascha Bischoff 	hwirq = FIELD_GET(GICV5_GICR_CDIA_INTID, ia);
560a9f38bfSSascha Bischoff 
570a9f38bfSSascha Bischoff 	gic_insn(hwirq, CDDI);
580a9f38bfSSascha Bischoff 	gic_insn(0, CDEOI);
590a9f38bfSSascha Bischoff 
600a9f38bfSSascha Bischoff 	GUEST_SYNC(GUEST_CMD_IRQ_DIEOI);
610a9f38bfSSascha Bischoff 
620a9f38bfSSascha Bischoff 	if (++count >= 2)
630a9f38bfSSascha Bischoff 		GUEST_DONE();
640a9f38bfSSascha Bischoff 
650a9f38bfSSascha Bischoff 	/* Ask for the next interrupt to be injected */
660a9f38bfSSascha Bischoff 	GUEST_SYNC(GUEST_CMD_IS_READY);
670a9f38bfSSascha Bischoff }
680a9f38bfSSascha Bischoff 
guest_code(void)690a9f38bfSSascha Bischoff static void guest_code(void)
700a9f38bfSSascha Bischoff {
710a9f38bfSSascha Bischoff 	local_irq_disable();
720a9f38bfSSascha Bischoff 
730a9f38bfSSascha Bischoff 	gicv5_cpu_enable_interrupts();
740a9f38bfSSascha Bischoff 	local_irq_enable();
750a9f38bfSSascha Bischoff 
760a9f38bfSSascha Bischoff 	/* Enable the SW_PPI (3) */
770a9f38bfSSascha Bischoff 	write_sysreg_s(BIT_ULL(3), SYS_ICC_PPI_ENABLER0_EL1);
780a9f38bfSSascha Bischoff 
790a9f38bfSSascha Bischoff 	/* Ask for the first interrupt to be injected */
800a9f38bfSSascha Bischoff 	GUEST_SYNC(GUEST_CMD_IS_READY);
810a9f38bfSSascha Bischoff 
820a9f38bfSSascha Bischoff 	/* Loop forever waiting for interrupts */
830a9f38bfSSascha Bischoff 	while (1);
840a9f38bfSSascha Bischoff }
850a9f38bfSSascha Bischoff 
860a9f38bfSSascha Bischoff 
870a9f38bfSSascha Bischoff /* we don't want to assert on run execution, hence that helper */
run_vcpu(struct kvm_vcpu * vcpu)880a9f38bfSSascha Bischoff static int run_vcpu(struct kvm_vcpu *vcpu)
890a9f38bfSSascha Bischoff {
900a9f38bfSSascha Bischoff 	return __vcpu_run(vcpu) ? -errno : 0;
910a9f38bfSSascha Bischoff }
920a9f38bfSSascha Bischoff 
vm_gic_destroy(struct vm_gic * v)930a9f38bfSSascha Bischoff static void vm_gic_destroy(struct vm_gic *v)
940a9f38bfSSascha Bischoff {
950a9f38bfSSascha Bischoff 	close(v->gic_fd);
960a9f38bfSSascha Bischoff 	kvm_vm_free(v->vm);
970a9f38bfSSascha Bischoff }
980a9f38bfSSascha Bischoff 
test_vgic_v5_ppis(u32 gic_dev_type)99*0c3a8774SDavid Matlack static void test_vgic_v5_ppis(u32 gic_dev_type)
1000a9f38bfSSascha Bischoff {
1010a9f38bfSSascha Bischoff 	struct kvm_vcpu *vcpus[NR_VCPUS];
1020a9f38bfSSascha Bischoff 	struct ucall uc;
1030a9f38bfSSascha Bischoff 	u64 user_ppis[2];
1040a9f38bfSSascha Bischoff 	struct vm_gic v;
1050a9f38bfSSascha Bischoff 	int ret, i;
1060a9f38bfSSascha Bischoff 
1070a9f38bfSSascha Bischoff 	v.gic_dev_type = gic_dev_type;
1080a9f38bfSSascha Bischoff 	v.vm = __vm_create(VM_SHAPE_DEFAULT, NR_VCPUS, 0);
1090a9f38bfSSascha Bischoff 
1100a9f38bfSSascha Bischoff 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
1110a9f38bfSSascha Bischoff 
1120a9f38bfSSascha Bischoff 	for (i = 0; i < NR_VCPUS; i++)
1130a9f38bfSSascha Bischoff 		vcpus[i] = vm_vcpu_add(v.vm, i, guest_code);
1140a9f38bfSSascha Bischoff 
1150a9f38bfSSascha Bischoff 	vm_init_descriptor_tables(v.vm);
1160a9f38bfSSascha Bischoff 	vm_install_exception_handler(v.vm, VECTOR_IRQ_CURRENT, guest_irq_handler);
1170a9f38bfSSascha Bischoff 
1180a9f38bfSSascha Bischoff 	for (i = 0; i < NR_VCPUS; i++)
1190a9f38bfSSascha Bischoff 		vcpu_init_descriptor_tables(vcpus[i]);
1200a9f38bfSSascha Bischoff 
1210a9f38bfSSascha Bischoff 	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
1220a9f38bfSSascha Bischoff 			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
1230a9f38bfSSascha Bischoff 
1240a9f38bfSSascha Bischoff 	/* Read out the PPIs that user space is allowed to drive. */
1250a9f38bfSSascha Bischoff 	kvm_device_attr_get(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
1260a9f38bfSSascha Bischoff 			    KVM_DEV_ARM_VGIC_USERSPACE_PPIS, &user_ppis);
1270a9f38bfSSascha Bischoff 
1280a9f38bfSSascha Bischoff 	/* We should always be able to drive the SW_PPI. */
1290a9f38bfSSascha Bischoff 	TEST_ASSERT(user_ppis[0] & BIT(GICV5_ARCH_PPI_SW_PPI),
1300a9f38bfSSascha Bischoff 		"SW_PPI is not drivable by userspace");
1310a9f38bfSSascha Bischoff 
1320a9f38bfSSascha Bischoff 	while (1) {
1330a9f38bfSSascha Bischoff 		ret = run_vcpu(vcpus[0]);
1340a9f38bfSSascha Bischoff 
1350a9f38bfSSascha Bischoff 		switch (get_ucall(vcpus[0], &uc)) {
1360a9f38bfSSascha Bischoff 		case UCALL_SYNC:
1370a9f38bfSSascha Bischoff 			/*
1380a9f38bfSSascha Bischoff 			 * The guest is ready for the next level change. Set
1390a9f38bfSSascha Bischoff 			 * high if ready, and lower if it has been consumed.
1400a9f38bfSSascha Bischoff 			 */
1410a9f38bfSSascha Bischoff 			if (uc.args[1] == GUEST_CMD_IS_READY ||
1420a9f38bfSSascha Bischoff 			    uc.args[1] == GUEST_CMD_IRQ_DIEOI) {
1430a9f38bfSSascha Bischoff 				u64 irq;
1440a9f38bfSSascha Bischoff 				bool level = uc.args[1] == GUEST_CMD_IRQ_DIEOI ? 0 : 1;
1450a9f38bfSSascha Bischoff 
1460a9f38bfSSascha Bischoff 				irq = FIELD_PREP(KVM_ARM_IRQ_NUM_MASK, 3);
1470a9f38bfSSascha Bischoff 				irq |= KVM_ARM_IRQ_TYPE_PPI << KVM_ARM_IRQ_TYPE_SHIFT;
1480a9f38bfSSascha Bischoff 
1490a9f38bfSSascha Bischoff 				_kvm_irq_line(v.vm, irq, level);
1500a9f38bfSSascha Bischoff 			} else if (uc.args[1] == GUEST_CMD_IS_AWAKE) {
1510a9f38bfSSascha Bischoff 				pr_info("Guest skipping WFI due to pending IRQ\n");
1520a9f38bfSSascha Bischoff 			} else if (uc.args[1] == GUEST_CMD_IRQ_CDIA) {
1530a9f38bfSSascha Bischoff 				pr_info("Guest acknowledged IRQ\n");
1540a9f38bfSSascha Bischoff 			}
1550a9f38bfSSascha Bischoff 
1560a9f38bfSSascha Bischoff 			continue;
1570a9f38bfSSascha Bischoff 		case UCALL_ABORT:
1580a9f38bfSSascha Bischoff 			REPORT_GUEST_ASSERT(uc);
1590a9f38bfSSascha Bischoff 			break;
1600a9f38bfSSascha Bischoff 		case UCALL_DONE:
1610a9f38bfSSascha Bischoff 			goto done;
1620a9f38bfSSascha Bischoff 		default:
1630a9f38bfSSascha Bischoff 			TEST_FAIL("Unknown ucall %lu", uc.cmd);
1640a9f38bfSSascha Bischoff 		}
1650a9f38bfSSascha Bischoff 	}
1660a9f38bfSSascha Bischoff 
1670a9f38bfSSascha Bischoff done:
1680a9f38bfSSascha Bischoff 	TEST_ASSERT(ret == 0, "Failed to test GICv5 PPIs");
1690a9f38bfSSascha Bischoff 
1700a9f38bfSSascha Bischoff 	vm_gic_destroy(&v);
1710a9f38bfSSascha Bischoff }
1720a9f38bfSSascha Bischoff 
1730a9f38bfSSascha Bischoff /*
1740a9f38bfSSascha Bischoff  * Returns 0 if it's possible to create GIC device of a given type (V5).
1750a9f38bfSSascha Bischoff  */
test_kvm_device(u32 gic_dev_type)176*0c3a8774SDavid Matlack int test_kvm_device(u32 gic_dev_type)
1770a9f38bfSSascha Bischoff {
1780a9f38bfSSascha Bischoff 	struct kvm_vcpu *vcpus[NR_VCPUS];
1790a9f38bfSSascha Bischoff 	struct vm_gic v;
1800a9f38bfSSascha Bischoff 	int ret;
1810a9f38bfSSascha Bischoff 
1820a9f38bfSSascha Bischoff 	v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
1830a9f38bfSSascha Bischoff 
1840a9f38bfSSascha Bischoff 	/* try to create a non existing KVM device */
1850a9f38bfSSascha Bischoff 	ret = __kvm_test_create_device(v.vm, 0);
1860a9f38bfSSascha Bischoff 	TEST_ASSERT(ret && errno == ENODEV, "unsupported device");
1870a9f38bfSSascha Bischoff 
1880a9f38bfSSascha Bischoff 	/* trial mode */
1890a9f38bfSSascha Bischoff 	ret = __kvm_test_create_device(v.vm, gic_dev_type);
1900a9f38bfSSascha Bischoff 	if (ret)
1910a9f38bfSSascha Bischoff 		return ret;
1920a9f38bfSSascha Bischoff 	v.gic_fd = kvm_create_device(v.vm, gic_dev_type);
1930a9f38bfSSascha Bischoff 
1940a9f38bfSSascha Bischoff 	ret = __kvm_create_device(v.vm, gic_dev_type);
1950a9f38bfSSascha Bischoff 	TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice");
1960a9f38bfSSascha Bischoff 
1970a9f38bfSSascha Bischoff 	vm_gic_destroy(&v);
1980a9f38bfSSascha Bischoff 
1990a9f38bfSSascha Bischoff 	return 0;
2000a9f38bfSSascha Bischoff }
2010a9f38bfSSascha Bischoff 
run_tests(u32 gic_dev_type)202*0c3a8774SDavid Matlack void run_tests(u32 gic_dev_type)
2030a9f38bfSSascha Bischoff {
2040a9f38bfSSascha Bischoff 	pr_info("Test VGICv5 PPIs\n");
2050a9f38bfSSascha Bischoff 	test_vgic_v5_ppis(gic_dev_type);
2060a9f38bfSSascha Bischoff }
2070a9f38bfSSascha Bischoff 
main(int ac,char ** av)2080a9f38bfSSascha Bischoff int main(int ac, char **av)
2090a9f38bfSSascha Bischoff {
2100a9f38bfSSascha Bischoff 	int ret;
2110a9f38bfSSascha Bischoff 	int pa_bits;
2120a9f38bfSSascha Bischoff 
2130a9f38bfSSascha Bischoff 	test_disable_default_vgic();
2140a9f38bfSSascha Bischoff 
2150a9f38bfSSascha Bischoff 	pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
2160a9f38bfSSascha Bischoff 	max_phys_size = 1ULL << pa_bits;
2170a9f38bfSSascha Bischoff 
2180a9f38bfSSascha Bischoff 	ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V5);
2190a9f38bfSSascha Bischoff 	if (ret) {
2200a9f38bfSSascha Bischoff 		pr_info("No GICv5 support; Not running GIC_v5 tests.\n");
2210a9f38bfSSascha Bischoff 		exit(KSFT_SKIP);
2220a9f38bfSSascha Bischoff 	}
2230a9f38bfSSascha Bischoff 
2240a9f38bfSSascha Bischoff 	pr_info("Running VGIC_V5 tests.\n");
2250a9f38bfSSascha Bischoff 	run_tests(KVM_DEV_TYPE_ARM_VGIC_V5);
2260a9f38bfSSascha Bischoff 
2270a9f38bfSSascha Bischoff 	return 0;
2280a9f38bfSSascha Bischoff }
229