[PATCH v5 49/49] KVM: selftests: Add VGICv5 sparse vCPU IDs test

Sascha Bischoff <[email protected]>
Newsgroups org.kernel.vger.kvm,dev.linux.lists.kvmarm,org.infradead.lists.linux-arm-kernel
Message-ID <[email protected]>
GICv5 uses the userspace-provided vCPU ID as the VPE ID. This must
work when vCPU IDs are sparse and differ from the dense internal vCPU
index.

Add a test that creates vCPUs with IDs 17 and 3, verifies that a vCPU
with ID 512 is rejected after a GICv5 has been created, and runs both
vCPUs to check that ICC_IAFFIDR_EL1 reports the correct VPE IDs on
each.

Signed-off-by: Sascha Bischoff <[email protected]>
---
 tools/testing/selftests/kvm/arm64/vgic_v5.c | 70 +++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/tools/testing/selftests/kvm/arm64/vgic_v5.c b/tools/testing/selftests/kvm/arm64/vgic_v5.c
index 47e147bc14b87..3eef2d2da595f 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_v5.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_v5.c
@@ -14,6 +14,10 @@
 
 #define NR_VCPUS		1
 #define VGIC_V5_LPI_NR_VCPUS	2
+#define VGIC_V5_SPARSE_NR_VCPUS	2
+#define VGIC_V5_SPARSE_VCPU0_ID	17
+#define VGIC_V5_SPARSE_VCPU1_ID	3
+#define VGIC_V5_SPARSE_TOO_BIG_ID	512
 #define VGIC_V5_LPI_MEMSLOT	1
 #define VGIC_V5_NR_PRIVATE_IRQS	64
 #define VGIC_V5_DEFAULT_NR_SPIS	32
@@ -297,6 +301,13 @@ static void guest_code(void)
 		cpu_relax();
 }
 
+static void guest_iaffid_code(void)
+{
+	GUEST_SYNC(FIELD_GET(ICC_IAFFIDR_EL1_IAFFID,
+				     read_sysreg_s(SYS_ICC_IAFFIDR_EL1)));
+	GUEST_DONE();
+}
+
 static void guest_spi_irq_handler(struct ex_regs *regs)
 {
 	bool valid;
@@ -1508,6 +1519,62 @@ static void test_vgic_v5_cpu_sysreg_attrs(void)
 	vm_gic_destroy(&v);
 }
 
+static void test_vgic_v5_sparse_vcpu_ids(void)
+{
+	struct kvm_vcpu *vcpus[VGIC_V5_SPARSE_NR_VCPUS];
+	const u32 vcpu_ids[VGIC_V5_SPARSE_NR_VCPUS] = {
+		VGIC_V5_SPARSE_VCPU0_ID,
+		VGIC_V5_SPARSE_VCPU1_ID,
+	};
+	int ret, i;
+	struct ucall uc;
+	struct vm_gic v;
+	u64 attr;
+
+	v.gic_dev_type = KVM_DEV_TYPE_ARM_VGIC_V5;
+	v.vm = __vm_create(VM_SHAPE_DEFAULT, VGIC_V5_SPARSE_NR_VCPUS, 0);
+	v.gic_fd = kvm_create_device(v.vm, v.gic_dev_type);
+
+	/*
+	 * A GICv5 VM cannot create a vCPU outside the VPE ID range. We've
+	 * already created a GICv5, so it should reject VCPU creation.
+	 */
+	ret = __vm_ioctl(v.vm, KVM_CREATE_VCPU,
+			 (void *)(unsigned long)VGIC_V5_SPARSE_TOO_BIG_ID);
+	TEST_ASSERT(ret < 0 && errno == EINVAL,
+		    "GICv5 accepted vCPU ID %u", VGIC_V5_SPARSE_TOO_BIG_ID);
+
+	/* Now, create two vCPUs with legal, albeit sparse, IDs */
+	for (i = 0; i < ARRAY_SIZE(vcpus); i++) {
+		vcpus[i] = vm_vcpu_add(v.vm, vcpu_ids[i], guest_iaffid_code);
+		TEST_ASSERT(vcpus[i], "Failed to create vCPU %u", vcpu_ids[i]);
+	}
+
+	attr = GICV5_IRS_CONFIG_BASE_GPA;
+	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
+			    KVM_VGIC_V5_ADDR_TYPE_IRS, &attr);
+	vgic_v5_map_irs(v.vm);
+	kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
+
+	/* Check both are runnable, and read back their correct IAFFIDs */
+	for (i = 0; i < ARRAY_SIZE(vcpus); i++) {
+		/* IAFFID is the VPE ID and must match the userspace vCPU ID. */
+		ret = run_vcpu(vcpus[i]);
+		TEST_ASSERT(!ret, "Failed to run GICv5 vCPU %u", vcpu_ids[i]);
+		TEST_ASSERT(get_ucall(vcpus[i], &uc) == UCALL_SYNC &&
+			    uc.args[1] == vcpu_ids[i],
+			    "GICv5 vCPU %u IAFFID mismatch", vcpu_ids[i]);
+
+		ret = run_vcpu(vcpus[i]);
+		TEST_ASSERT(!ret, "Failed to complete GICv5 vCPU %u", vcpu_ids[i]);
+		TEST_ASSERT(get_ucall(vcpus[i], NULL) == UCALL_DONE,
+			    "GICv5 vCPU %u did not complete", vcpu_ids[i]);
+	}
+
+	vm_gic_destroy(&v);
+}
+
 static void test_vgic_v5_ppis(u32 gic_dev_type)
 {
 	struct kvm_vcpu *vcpus[NR_VCPUS];
@@ -1952,6 +2019,9 @@ void run_tests(u32 gic_dev_type)
 	pr_info("Test VGICv5 CPU sysreg attrs\n");
 	test_vgic_v5_cpu_sysreg_attrs();
 
+	pr_info("Test VGICv5 sparse vCPU IDs\n");
+	test_vgic_v5_sparse_vcpu_ids();
+
 	pr_info("Test VGICv5 PPIs\n");
 	test_vgic_v5_ppis(gic_dev_type);
 
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.