From: Jim Mattson <jmattson@google.com>
To: seanjc@google.com, kvm@vger.kernel.org, pbonzini@redhat.com
Cc: "Marc Orr (Google)" <marc.orr@gmail.com>,
Oliver Upton <oliver.upton@linux.dev>,
Jim Mattson <jmattson@google.com>
Subject: [kvm-unit-tests PATCH 2/5] nVMX: test nested "virtual-interrupt delivery"
Date: Mon, 11 Dec 2023 10:55:49 -0800 [thread overview]
Message-ID: <20231211185552.3856862-3-jmattson@google.com> (raw)
In-Reply-To: <20231211185552.3856862-1-jmattson@google.com>
From: "Marc Orr (Google)" <marc.orr@gmail.com>
Add test coverage for recognizing and delivering virtual interrupts via
VMX's "virtual-interrupt delivery" feature, in the following two scenarios:
1. There's a pending interrupt at VM-entry.
2. There's a pending interrupt during TPR virtualization.
Signed-off-by: Marc Orr (Google) <marc.orr@gmail.com>
Co-developed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Co-developed-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Jim Mattson <jmattson@google.com>
---
lib/x86/apic.h | 5 ++
x86/unittests.cfg | 2 +-
x86/vmx_tests.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 171 insertions(+), 1 deletion(-)
diff --git a/lib/x86/apic.h b/lib/x86/apic.h
index c389d40e169a..8df889b2d1e4 100644
--- a/lib/x86/apic.h
+++ b/lib/x86/apic.h
@@ -81,6 +81,11 @@ static inline bool apic_lvt_entry_supported(int idx)
return GET_APIC_MAXLVT(apic_read(APIC_LVR)) >= idx;
}
+static inline u8 task_priority_class(u8 vector)
+{
+ return vector >> 4;
+}
+
enum x2apic_reg_semantics {
X2APIC_INVALID = 0,
X2APIC_READABLE = BIT(0),
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 3fe59449b650..dd086d9e2bf4 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -361,7 +361,7 @@ timeout = 10
[vmx_apicv_test]
file = vmx.flat
-extra_params = -cpu max,+vmx -append "apic_reg_virt_test virt_x2apic_mode_test"
+extra_params = -cpu max,+vmx -append "apic_reg_virt_test virt_x2apic_mode_test vmx_basic_vid_test"
arch = x86_64
groups = vmx
timeout = 10
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index e5ed79b7da4a..0fb7e1466c50 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -10711,6 +10711,170 @@ static void vmx_exception_test(void)
test_set_guest_finished();
}
+enum Vid_op {
+ VID_OP_SET_ISR,
+ VID_OP_NOP,
+ VID_OP_SET_CR8,
+ VID_OP_TERMINATE,
+};
+
+struct vmx_basic_vid_test_guest_args {
+ enum Vid_op op;
+ u8 nr;
+ bool isr_fired;
+} vmx_basic_vid_test_guest_args;
+
+static void vmx_vid_test_isr(isr_regs_t *regs)
+{
+ volatile struct vmx_basic_vid_test_guest_args *args =
+ &vmx_basic_vid_test_guest_args;
+
+ args->isr_fired = true;
+ barrier();
+ eoi();
+}
+
+static void vmx_basic_vid_test_guest(void)
+{
+ volatile struct vmx_basic_vid_test_guest_args *args =
+ &vmx_basic_vid_test_guest_args;
+
+ sti_nop();
+ for (;;) {
+ enum Vid_op op = args->op;
+ u8 nr = args->nr;
+
+ switch (op) {
+ case VID_OP_TERMINATE:
+ return;
+ case VID_OP_SET_ISR:
+ handle_irq(nr, vmx_vid_test_isr);
+ break;
+ case VID_OP_SET_CR8:
+ write_cr8(nr);
+ break;
+ default:
+ break;
+ }
+
+ vmcall();
+ }
+}
+
+/*
+ * Test virtual interrupt delivery (VID) at VM-entry or TPR virtualization
+ *
+ * Args:
+ * nr: vector under test
+ * tpr: task priority under test
+ * tpr_virt: If true, then test VID during TPR virtualization. Otherwise,
+ * test VID during VM-entry.
+ */
+static void test_basic_vid(u8 nr, u8 tpr, bool tpr_virt)
+{
+ volatile struct vmx_basic_vid_test_guest_args *args =
+ &vmx_basic_vid_test_guest_args;
+ bool isr_fired_want =
+ task_priority_class(nr) > task_priority_class(tpr);
+ u16 rvi_want = isr_fired_want ? 0 : nr;
+ u16 int_status;
+
+ /*
+ * From the SDM:
+ * IF "interrupt-window exiting" is 0 AND
+ * RVI[7:4] > VPPR[7:4] (see Section 29.1.1 for definition of VPPR)
+ * THEN recognize a pending virtual interrupt;
+ * ELSE
+ * do not recognize a pending virtual interrupt;
+ * FI;
+ *
+ * Thus, VPPR dictates whether a virtual interrupt is recognized.
+ * However, PPR virtualization, which occurs before virtual interrupt
+ * delivery, sets VPPR to VTPR, when SVI is 0.
+ */
+ vmcs_write(GUEST_INT_STATUS, nr);
+ args->isr_fired = false;
+ if (tpr_virt) {
+ args->op = VID_OP_SET_CR8;
+ args->nr = task_priority_class(tpr);
+ set_vtpr(0xff);
+ } else {
+ args->op = VID_OP_NOP;
+ set_vtpr(tpr);
+ }
+
+ enter_guest();
+ skip_exit_vmcall();
+ TEST_ASSERT_EQ(args->isr_fired, isr_fired_want);
+ int_status = vmcs_read(GUEST_INT_STATUS);
+ TEST_ASSERT_EQ(int_status, rvi_want);
+}
+
+/*
+ * Test recognizing and delivering virtual interrupts via "Virtual-interrupt
+ * delivery" for two scenarios:
+ * 1. When there is a pending interrupt at VM-entry.
+ * 2. When there is a pending interrupt during TPR virtualization.
+ */
+static void vmx_basic_vid_test(void)
+{
+ volatile struct vmx_basic_vid_test_guest_args *args =
+ &vmx_basic_vid_test_guest_args;
+ u8 nr_class;
+ u16 nr;
+
+ if (!cpu_has_apicv()) {
+ report_skip("%s : Not all required APICv bits supported", __func__);
+ return;
+ }
+
+ enable_vid();
+ test_set_guest(vmx_basic_vid_test_guest);
+
+ /*
+ * kvm-unit-tests uses vector 32 for IPIs, so don't install a test ISR
+ * for that vector.
+ */
+ for (nr = 0x21; nr < 0x100; nr++) {
+ vmcs_write(GUEST_INT_STATUS, 0);
+ args->op = VID_OP_SET_ISR;
+ args->nr = nr;
+ args->isr_fired = false;
+ enter_guest();
+ skip_exit_vmcall();
+ TEST_ASSERT(!args->isr_fired);
+ }
+ report(true, "Set ISR for vectors 33-255.");
+
+ for (nr_class = 2; nr_class < 16; nr_class++) {
+ u8 nr_sub_class;
+
+ for (nr_sub_class = 0; nr_sub_class < 16; nr_sub_class++) {
+ u16 tpr;
+
+ nr = (nr_class << 4) | nr_sub_class;
+
+ /*
+ * Don't test the reserved IPI vector, as the test ISR
+ * was not installed.
+ */
+ if (nr == 0x20)
+ continue;
+
+ for (tpr = 0; tpr < 256; tpr++) {
+ test_basic_vid(nr, tpr, /*tpr_virt=*/false);
+ test_basic_vid(nr, tpr, /*tpr_virt=*/true);
+ }
+ report(true, "TPR 0-255 for vector 0x%x.", nr);
+ }
+ }
+
+ /* Terminate the guest */
+ args->op = VID_OP_TERMINATE;
+ enter_guest();
+ assert_exit_reason(VMX_VMCALL);
+}
+
#define TEST(name) { #name, .v2 = name }
/* name/init/guest_main/exit_handler/syscall_handler/guest_regs */
@@ -10765,6 +10929,7 @@ struct vmx_test vmx_tests[] = {
TEST(vmx_hlt_with_rvi_test),
TEST(apic_reg_virt_test),
TEST(virt_x2apic_mode_test),
+ TEST(vmx_basic_vid_test),
/* APIC pass-through tests */
TEST(vmx_apic_passthrough_test),
TEST(vmx_apic_passthrough_thread_test),
--
2.43.0.472.g3155946c3a-goog
next prev parent reply other threads:[~2023-12-11 18:56 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-11 18:55 [kvm-unit-tests PATCH 0/5] nVMX: Simple posted interrupts test Jim Mattson
2023-12-11 18:55 ` [kvm-unit-tests PATCH 1/5] nVMX: Enable x2APIC mode for virtual-interrupt delivery tests Jim Mattson
2023-12-11 18:55 ` Jim Mattson [this message]
2023-12-11 18:55 ` [kvm-unit-tests PATCH 3/5] nVMX: test nested EOI virtualization Jim Mattson
2023-12-11 18:55 ` [kvm-unit-tests PATCH 4/5] nVMX: add self-IPI tests to vmx_basic_vid_test Jim Mattson
2023-12-11 18:55 ` [kvm-unit-tests PATCH 5/5] nVMX: add test for posted interrupts Jim Mattson
2024-06-05 23:20 ` [kvm-unit-tests PATCH 0/5] nVMX: Simple posted interrupts test Sean Christopherson
2024-10-09 6:48 ` Like Xu
2024-10-14 8:56 ` Chao Gao
2024-10-16 15:59 ` Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231211185552.3856862-3-jmattson@google.com \
--to=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=marc.orr@gmail.com \
--cc=oliver.upton@linux.dev \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox