From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3306A46AA7D; Wed, 5 Aug 2026 11:04:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927856; cv=none; b=NquqtRLp5o2lHSpKP7iK58AC3TiJMe9EJwK363D8XM7I74SiBPR2tpWOA2QmCpRVERhLlzJ2neiTa00jk0sEo0BHwDc/qnBnLmzBBDSYIlC8W/9OQ74CEFEmazIfrKbT77thT88q5VIoIMu+bBxPZOwmzuOaMxv6EAnE09gzTvw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927856; c=relaxed/simple; bh=BfpEaAGkDyfbANpfPBIaZd/uzX61Ff66TSNwy44xLiA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FdqdRQx1EHWLe19ZSvM9WHxY77bqp6+v3cp+r8cKXsYStrZEzp8KcHLhWsbobel5nHFaoL8Cq7jI0i1GIn+4GPRFRt454nixbdSLxbC9ppIyzrXoytUc05q6pt42AU+OU5+PSExqRDM7mr5C6sMK6oE+VBbfk7KX+9RNLD0j/RQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=kO9BUPAv; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="kO9BUPAv" Received: from fedora.hsd1.wa.comcast.net (unknown [52.148.140.42]) by linux.microsoft.com (Postfix) with ESMTPSA id 08ADA20B716D; Wed, 5 Aug 2026 04:03:52 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 08ADA20B716D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785927833; bh=CZO/FdjjrPxcYw4qgRLhHr2fLzYDF8y1zRIOsjWT26g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kO9BUPAvWRCzrsYobVhBUcB2xm2bM2DD4VJpERjHV/eSn5VIeK8bsumdJESYK45rF WkzGQhI4i2uMD2Z9sHvJZR5OdY1VB7ejAsN9Xe+BlMjXYG3rwnQmFYBYdLfZlLRKDe s+icGXDgINZyI4YasxfUFbj3PxI8NUqUtck1jRbE= From: Sriram Nambakam To: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Subject: [RFC PATCH v1 37/42] KVM: selftests: run plane tests with a split IRQ chip Date: Wed, 5 Aug 2026 04:03:19 -0700 Message-ID: <20260805110324.25067-38-snambakam@linux.microsoft.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260805110324.25067-1-snambakam@linux.microsoft.com> References: <20260805110324.25067-1-snambakam@linux.microsoft.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 +#include #include #include #include @@ -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