[RFC PATCH v1 37/42] KVM: selftests: run plane tests with a split IRQ chip

Sriram Nambakam <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Wire the plane selftests to actually exercise planes instead of skipping:

- Add vm_create_barebones_irqchip() and create the test VMs with a split
  IRQ chip, which planes require, and query KVM_CAP_PLANES on the VM fd
  (system scope always returns 1).
- Switch plane vCPU creation to KVM_CREATE_VCPU with the vCPU id, matching
  the current plane ABI, and drop the removed KVM_CREATE_VCPU_PLANE,
  KVM_CAP_PLANES_FPU and req_exit_planes paths from the tests and docs.
- Rename x86/plane_test.c to x86/plane_x86_test.c.
---
 tools/testing/selftests/kvm/Makefile.kvm      |   2 +-
 .../testing/selftests/kvm/include/kvm_util.h  |  12 ++
 tools/testing/selftests/kvm/lib/kvm_util.c    |   8 +-
 tools/testing/selftests/kvm/plane_test.c      |  20 ++--
 .../x86/{plane_test.c => plane_x86_test.c}    | 109 +++---------------
 5 files changed, 45 insertions(+), 106 deletions(-)
 rename tools/testing/selftests/kvm/x86/{plane_test.c => plane_x86_test.c} (58%)

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 80933e942ecf..750350e187c8 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -102,7 +102,7 @@ TEST_GEN_PROGS_x86 += x86/nested_tdp_fault_test
 TEST_GEN_PROGS_x86 += x86/nested_tsc_adjust_test
 TEST_GEN_PROGS_x86 += x86/nested_tsc_scaling_test
 TEST_GEN_PROGS_x86 += x86/nested_vmsave_vmload_test
-TEST_GEN_PROGS_x86 += x86/plane_test
+TEST_GEN_PROGS_x86 += x86/plane_x86_test
 TEST_GEN_PROGS_x86 += x86/platform_info_test
 TEST_GEN_PROGS_x86 += x86/pmu_counters_test
 TEST_GEN_PROGS_x86 += x86/pmu_event_filter_test
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 2ea2960f1e2d..c4726fc7b065 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1070,6 +1070,18 @@ static inline struct kvm_vm *vm_create_barebones(void)
 	return ____vm_create(VM_SHAPE_DEFAULT);
 }
 
+static inline struct kvm_vm *vm_create_barebones_irqchip(bool split)
+{
+	struct kvm_vm *vm = vm_create_barebones();
+
+	if (split)
+		vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24);
+	else
+		vm_create_irqchip(vm);
+
+	return vm;
+}
+
 static inline struct kvm_vm *vm_create_barebones_type(unsigned long type)
 {
 	const struct vm_shape shape = {
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 43a23634b4f4..ce53230b23d0 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -790,10 +790,8 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
 void kvm_vm_release(struct kvm_vm *vmp)
 {
 	struct kvm_vcpu *vcpu, *tmp_vcpu;
-	struct kvm_plane_vcpu *plane_vcpu, *tmp_plane_vcpu;
-	struct kvm_plane *plane, *tmp_plane;
 
-	list_for_each_entry_safe(vcpu, tmp, &vmp->vcpus, list)
+	list_for_each_entry_safe(vcpu, tmp_vcpu, &vmp->vcpus, list)
 		vm_vcpu_rm(vmp, vcpu);
 
 	kvm_free_fd(vmp->fd);
@@ -1366,8 +1364,8 @@ struct kvm_plane_vcpu *__vm_plane_vcpu_add(struct kvm_vcpu *vcpu, struct kvm_pla
 	plane_vcpu = calloc(1, sizeof(*plane_vcpu));
 	TEST_ASSERT(plane_vcpu != NULL, "Insufficient Memory");
 
-	plane_vcpu->fd = __plane_ioctl(plane, KVM_CREATE_VCPU_PLANE, (void *)(unsigned long)vcpu->fd);
-	TEST_ASSERT_VM_VCPU_IOCTL(plane_vcpu->fd >= 0, KVM_CREATE_VCPU_PLANE, plane_vcpu->fd, plane->vm);
+	plane_vcpu->fd = __plane_ioctl(plane, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu->id);
+	TEST_ASSERT_VM_VCPU_IOCTL(plane_vcpu->fd >= 0, KVM_CREATE_VCPU, plane_vcpu->fd, plane->vm);
 	plane_vcpu->id = vcpu->id;
 	plane_vcpu->plane0 = vcpu;
 
diff --git a/tools/testing/selftests/kvm/plane_test.c b/tools/testing/selftests/kvm/plane_test.c
index 9cf3ab76b3cd..fd09d1f78ebe 100644
--- a/tools/testing/selftests/kvm/plane_test.c
+++ b/tools/testing/selftests/kvm/plane_test.c
@@ -21,7 +21,8 @@ void test_create_plane_errors(int max_planes)
 	struct kvm_vcpu *vcpu;
 	int planefd, plane_vcpufd;
 
-	vm = vm_create_barebones();
+	/* Planes require an in-kernel (split) IRQ chip. */
+	vm = vm_create_barebones_irqchip(true);
 	vcpu = __vm_vcpu_add(vm, 0);
 
 	planefd = __vm_ioctl(vm, KVM_CREATE_PLANE, (void *)(unsigned long)0);
@@ -34,9 +35,9 @@ void test_create_plane_errors(int max_planes)
 		    "Creating plane %d, expecting EINVAL. ret: %d, errno: %d",
 		    max_planes, planefd, errno);
 
-	plane_vcpufd = __vm_ioctl(vm, KVM_CREATE_VCPU_PLANE, (void *)(unsigned long)vcpu->fd);
-	TEST_ASSERT(plane_vcpufd == -1 && errno == ENOTTY,
-		    "Creating vCPU for plane 0, expecting ENOTTY. ret: %d, errno: %d",
+	plane_vcpufd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu->id);
+	TEST_ASSERT(plane_vcpufd == -1 && errno == EEXIST,
+		    "Creating existing vCPU for plane 0, expecting EEXIST. ret: %d, errno: %d",
 		    plane_vcpufd, errno);
 
 	kvm_vm_free(vm);
@@ -50,7 +51,7 @@ void test_create_plane(void)
 	struct kvm_plane *plane;
 	int r;
 
-	vm = vm_create_barebones();
+	vm = vm_create_barebones_irqchip(true);
 	vcpu = __vm_vcpu_add(vm, 0);
 
 	plane = vm_plane_add(vm, 1);
@@ -70,7 +71,7 @@ void test_create_plane(void)
 
 	__vm_plane_vcpu_add(vcpu, plane);
 
-	r = __plane_ioctl(plane, KVM_CREATE_VCPU_PLANE, (void *)(unsigned long)vcpu->fd);
+	r = __plane_ioctl(plane, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu->id);
 	TEST_ASSERT(r == -1 && errno == EEXIST,
 		    "Creating vCPU again for plane 1. ret: %d, errno: %d",
 		    r, errno);
@@ -86,7 +87,10 @@ void test_create_plane(void)
 
 int main(int argc, char *argv[])
 {
-	int cap_planes = kvm_check_cap(KVM_CAP_PLANES);
+	struct kvm_vm *vm = vm_create_barebones_irqchip(true);
+	int cap_planes = vm_check_cap(vm, KVM_CAP_PLANES);
+
+	kvm_vm_free(vm);
 	TEST_REQUIRE(cap_planes);
 
 	ksft_print_header();
@@ -98,6 +102,8 @@ int main(int argc, char *argv[])
 
 	if (cap_planes > 1)
 		test_create_plane();
+	else
+		ksft_test_result_skip("plane creation requires KVM_CAP_PLANES > 1\n");
 
 	ksft_finished();
 }
diff --git a/tools/testing/selftests/kvm/x86/plane_test.c b/tools/testing/selftests/kvm/x86/plane_x86_test.c
similarity index 58%
rename from tools/testing/selftests/kvm/x86/plane_test.c
rename to tools/testing/selftests/kvm/x86/plane_x86_test.c
index 0fdd8a066723..8f0919371383 100644
--- a/tools/testing/selftests/kvm/x86/plane_test.c
+++ b/tools/testing/selftests/kvm/x86/plane_x86_test.c
@@ -5,6 +5,7 @@
  * Test for x86-specific VM plane functionality
  */
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,7 +27,7 @@ static void test_plane_regs(void)
 
 	struct kvm_regs regs0, regs1;
 
-	vm = vm_create_barebones();
+	vm = vm_create_barebones_irqchip(true);
 	vcpu = __vm_vcpu_add(vm, 0);
 	plane = vm_plane_add(vm, 1);
 	plane_vcpu = __vm_plane_vcpu_add(vcpu, plane);
@@ -62,8 +63,7 @@ static void test_plane_fpu_nonshared(void)
 
 	struct kvm_xsave xsave0, xsave1;
 
-	vm = vm_create_barebones();
-	TEST_ASSERT_EQ(vm_check_cap(vm, KVM_CAP_PLANES_FPU), false);
+	vm = vm_create_barebones_irqchip(true);
 
 	vcpu = __vm_vcpu_add(vm, 0);
 	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
@@ -93,79 +93,15 @@ static void test_plane_fpu_nonshared(void)
 	ksft_test_result_pass("get/set FPU not shared across planes\n");
 }
 
-static void test_plane_fpu_shared(void)
-{
-	struct kvm_vm *vm;
-	struct kvm_vcpu *vcpu;
-	struct kvm_plane *plane;
-	struct kvm_plane_vcpu *plane_vcpu;
-
-	struct kvm_xsave xsave0, xsave1;
-
-	vm = vm_create_barebones();
-	vm_enable_cap(vm, KVM_CAP_PLANES_FPU, 1ul);
-	TEST_ASSERT_EQ(vm_check_cap(vm, KVM_CAP_PLANES_FPU), true);
-
-	vcpu = __vm_vcpu_add(vm, 0);
-	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
-	vcpu_set_cpuid(vcpu);
-
-	plane = vm_plane_add(vm, 1);
-	plane_vcpu = __vm_plane_vcpu_add(vcpu, plane);
-
-	vcpu_ioctl(vcpu, KVM_GET_XSAVE, &xsave0);
-
-	xsave0.region[XSTATE_BV_OFFSET] |= XFEATURE_MASK_FP | XFEATURE_MASK_SSE;
-	xsave0.region[XMM_OFFSET] = 0x12345678;
-	vcpu_ioctl(vcpu, KVM_SET_XSAVE, &xsave0);
-	plane_vcpu_ioctl(plane_vcpu, KVM_GET_XSAVE, &xsave1);
-	TEST_ASSERT_EQ(xsave1.region[XMM_OFFSET], 0x12345678);
-
-	xsave1.region[XSTATE_BV_OFFSET] |= XFEATURE_MASK_FP | XFEATURE_MASK_SSE;
-	xsave1.region[XMM_OFFSET] = 0x87654321;
-	plane_vcpu_ioctl(plane_vcpu, KVM_SET_XSAVE, &xsave1);
-	vcpu_ioctl(vcpu, KVM_GET_XSAVE, &xsave0);
-	TEST_ASSERT_EQ(xsave0.region[XMM_OFFSET], 0x87654321);
-
-	ksft_test_result_pass("get/set FPU shared across planes\n");
-
-	if (!this_cpu_has(X86_FEATURE_PKU)) {
-		ksft_test_result_skip("get/set PKRU with shared FPU\n");
-		goto exit;
-	}
-
-	xsave0.region[XSTATE_BV_OFFSET] = XFEATURE_MASK_PKRU;
-	xsave0.region[PKRU_OFFSET] = 0xffffffff;
-	vcpu_ioctl(vcpu, KVM_SET_XSAVE, &xsave0);
-	plane_vcpu_ioctl(plane_vcpu, KVM_GET_XSAVE, &xsave0);
-
-	xsave0.region[XSTATE_BV_OFFSET] = XFEATURE_MASK_PKRU;
-	xsave0.region[PKRU_OFFSET] = 0xaaaaaaaa;
-	vcpu_ioctl(vcpu, KVM_SET_XSAVE, &xsave0);
-	plane_vcpu_ioctl(plane_vcpu, KVM_GET_XSAVE, &xsave1);
-	assert(xsave1.region[PKRU_OFFSET] == 0xffffffff);
-
-	xsave1.region[XSTATE_BV_OFFSET] = XFEATURE_MASK_PKRU;
-	xsave1.region[PKRU_OFFSET] = 0x55555555;
-	plane_vcpu_ioctl(plane_vcpu, KVM_SET_XSAVE, &xsave1);
-	vcpu_ioctl(vcpu, KVM_GET_XSAVE, &xsave0);
-	assert(xsave0.region[PKRU_OFFSET] == 0xaaaaaaaa);
-
-	ksft_test_result_pass("get/set PKRU with shared FPU\n");
-
-exit:
-	kvm_vm_free(vm);
-}
-
 #define APIC_SPIV		0xF0
 #define APIC_IRR		0x200
 
 #define MYVEC			192
 
-#define MAKE_MSI(cpu, vector) ((struct kvm_msi){		\
-	.address_lo = APIC_DEFAULT_GPA + (((cpu) & 0xff) << 8),	\
-	.address_hi = (cpu) & ~0xff,				\
-	.data = (vector),					\
+#define MAKE_MSI(cpu, vector) ((struct kvm_msi){			\
+	.address_lo = APIC_DEFAULT_GPA + (((cpu) & 0xff) << 8),		\
+	.address_hi = (cpu) & ~0xff,					\
+	.data = (vector),						\
 })
 
 static bool has_irr(struct kvm_lapic_state *apic, int vector)
@@ -194,7 +130,7 @@ static void test_plane_msi(void)
 	struct kvm_msi msi = MAKE_MSI(0, MYVEC);
 	struct kvm_lapic_state lapic0, lapic1;
 
-	vm = __vm_create(VM_SHAPE_DEFAULT, 1, 0);
+	vm = vm_create_barebones_irqchip(true);
 
 	vcpu = __vm_vcpu_add(vm, 0);
 	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
@@ -215,6 +151,7 @@ static void test_plane_msi(void)
 	do_enable_lapic(&lapic1);
 	plane_vcpu_ioctl(plane_vcpu, KVM_SET_LAPIC, &lapic1);
 
+	/* Deliver to plane 1 (via the plane fd); it must land only in plane 1. */
 	r = __plane_ioctl(plane, KVM_SIGNAL_MSI, &msi);
 	TEST_ASSERT(r == 1,
 		   "Delivering interrupt to plane 1. ret: %d, errno: %d", r, errno);
@@ -224,46 +161,32 @@ static void test_plane_msi(void)
 	plane_vcpu_ioctl(plane_vcpu, KVM_GET_LAPIC, &lapic1);
 	TEST_ASSERT(has_irr(&lapic1, MYVEC), "Vector set in plane 1");
 
-	/* req_exit_planes always has priority */
-	vcpu->run->req_exit_planes = (1 << 1);
-	vcpu_run(vcpu);
-	TEST_ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_PLANE_EVENT);
-	TEST_ASSERT_EQ(vcpu->run->plane_event.cause, KVM_PLANE_EVENT_INTERRUPT);
-	TEST_ASSERT_EQ(vcpu->run->plane_event.pending_event_planes, (1 << 1));
-	TEST_ASSERT_EQ(vcpu->run->plane_event.target, (1 << 1));
-
+	/* Deliver to plane 0 (via the vm fd); it must land in plane 0. */
 	r = __vm_ioctl(vm, KVM_SIGNAL_MSI, &msi);
 	TEST_ASSERT(r == 1,
 		   "Delivering interrupt to plane 0. ret: %d, errno: %d", r, errno);
 	vcpu_ioctl(vcpu, KVM_GET_LAPIC, &lapic0);
 	TEST_ASSERT(has_irr(&lapic0, MYVEC), "Vector set in plane 0");
 
-	/* req_exit_planes ignores current plane; current plane is cleared */
-	vcpu->run->plane = 1;
-	vcpu->run->req_exit_planes = (1 << 0) | (1 << 1);
-	vcpu_run(vcpu);
-	TEST_ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_PLANE_EVENT);
-	TEST_ASSERT_EQ(vcpu->run->plane_event.cause, KVM_PLANE_EVENT_INTERRUPT);
-	TEST_ASSERT_EQ(vcpu->run->plane_event.pending_event_planes, (1 << 0));
-	TEST_ASSERT_EQ(vcpu->run->plane_event.target, (1 << 0));
-
 	kvm_vm_free(vm);
-	ksft_test_result_pass("signal MSI for planes\n");
+	ksft_test_result_pass("signal MSI routed per plane\n");
 }
 
 int main(int argc, char *argv[])
 {
-	int cap_planes = kvm_check_cap(KVM_CAP_PLANES);
+	struct kvm_vm *vm = vm_create_barebones_irqchip(true);
+	int cap_planes = vm_check_cap(vm, KVM_CAP_PLANES);
+
+	kvm_vm_free(vm);
 	TEST_REQUIRE(cap_planes && cap_planes > 1);
 
 	ksft_print_header();
-	ksft_set_plan(5);
+	ksft_set_plan(3);
 
 	pr_info("# KVM_CAP_PLANES: %d\n", cap_planes);
 
 	test_plane_regs();
 	test_plane_fpu_nonshared();
-	test_plane_fpu_shared();
 	test_plane_msi();
 
 	ksft_finished();
-- 
2.55.0
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.