Extend the Secure AVIC (SAVIC) selftest to validate the injection of Message-Signaled Interrupts (MSIs) from the host. In SAVIC mode, the delivery of external interrupts, including MSIs, requires explicit cooperation from the guest. For an interrupt to be successfully injected by the hardware, the guest must first grant permission by setting the corresponding vector bit in the 'ALLOWED IRR' region of its private APIC backing page. If the vector is not explicitly allowed, the hardware will drop the interrupt. Add a new test case to Secure AVIC selftest that verifies this permission model for MSIs. Verify that: 1. If the host injects an MSI while the guest has not yet allowed the vector, the interrupt is correctly dropped and not received. 2. The guest then updates the ALLOWED_IRR to permit the MSI vector. When the host injects the same MSI again, the interrupt is successfully delivered and handled. This two-stage approach provides robust validation of the SAVIC MSI delivery mechanism, ensuring both the blocking and permissive paths work as expected. Signed-off-by: Neeraj Upadhyay --- tools/testing/selftests/kvm/x86/savic_test.c | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tools/testing/selftests/kvm/x86/savic_test.c b/tools/testing/selftests/kvm/x86/savic_test.c index 3efefc1e69f5..1d9861949a28 100644 --- a/tools/testing/selftests/kvm/x86/savic_test.c +++ b/tools/testing/selftests/kvm/x86/savic_test.c @@ -22,6 +22,7 @@ #define IOAPIC_NUM_LEVEL_VECTORS 2 #define RTC_GSI 8 #define RTC_GSI_IRQ 0x85 +#define MSI_VECTOR 0x40 #define FIXED_IPI_VEC 0x31 #define FIXED_LOGICAL_IPI_VEC 0x32 #define BROADCAST_ALL_IPI_VEC 0x33 @@ -40,6 +41,7 @@ enum savic_test_state { SAVIC_TEST_STATE(SAVIC_IDLE_HALT), SAVIC_TEST_STATE(SAVIC_IOAPIC), SAVIC_TEST_STATE(SAVIC_IOAPIC2), + SAVIC_TEST_STATE(SAVIC_MSI), SAVIC_TEST_STATE(SAVIC_IPI), SAVIC_TEST_STATE(SAVIC_NMI), SAVIC_TEST_STATE(SAVIC_NMI2), @@ -57,6 +59,7 @@ struct test_data_page { uint64_t ioapic_lirq1_count; uint64_t ioapic_lirq2_count; uint64_t ioapic_rtc_gsi_irq_count; + uint64_t msi_irq_count; uint64_t fixed_phys_ipi_wake_count; uint64_t fixed_phys_ipi_hlt_count; uint64_t fixed_logical_ipi_hlt_count; @@ -807,6 +810,34 @@ static void guest_nmi_handler(struct ex_regs *regs) sev_es_nmi_complete(); } +static void savic_msi_not_allowed(int id) +{ + struct test_data_page *data = get_test_data(); + + savic_allow_vector(MSI_VECTOR); + + __GUEST_ASSERT(READ_ONCE(data->msi_irq_count) == 0, + "Invalid MSI IRQ count: %ld, should be 0", + READ_ONCE(data->msi_irq_count)); +} + +static void savic_msi_allowed(int id) +{ + struct test_data_page *data = get_test_data(); + + __GUEST_ASSERT(READ_ONCE(data->msi_irq_count) == 1, + "Invalid MSI IRQ count: %ld", + READ_ONCE(data->msi_irq_count)); +} + +static void msi_intr_handler(struct ex_regs *regs) +{ + struct test_data_page *data = get_test_data(); + + WRITE_ONCE(data->msi_irq_count, data->msi_irq_count + 1); + x2apic_write_reg(APIC_EOI, 0x00); +} + static void ipi_guest_code(int id) { struct test_data_page *data; @@ -901,6 +932,9 @@ static void guest_code(int id) SAVIC_GUEST_SYNC(SAVIC_IOAPIC, savic_ioapic); SAVIC_GUEST_SYNC(SAVIC_IOAPIC2, savic_ioapic2); + SAVIC_GUEST_SYNC(SAVIC_MSI, savic_msi_not_allowed); + SAVIC_GUEST_SYNC(SAVIC_MSI, savic_msi_allowed); + SAVIC_GUEST_SYNC(SAVIC_IPI, savic_ipi); /* Disable host NMI injection in control MSR. */ @@ -953,6 +987,17 @@ static void host_send_ioapic_irq(struct kvm_vm *vm, int id) kvm_irq_line_status(vm, RTC_GSI, 0); } +static void host_send_msi(struct kvm_vm *vm) +{ + struct kvm_msi msi = { + .address_lo = 0, + .address_hi = 0, + .data = MSI_VECTOR, + }; + + __vm_ioctl(vm, KVM_SIGNAL_MSI, &msi); +} + static void host_send_nmi(int id) { vcpu_nmi(vcpus[id]); @@ -968,6 +1013,9 @@ static void host_test_savic(struct kvm_vm *vm, int id, enum savic_test_state tes case SAVIC_IOAPIC2_START: host_send_ioapic_irq(vm, id); break; + case SAVIC_MSI_START: + host_send_msi(vm); + break; case SAVIC_NMI_START: case SAVIC_NMI2_START: case SAVIC_NMI3_START: @@ -1021,6 +1069,7 @@ static void install_exception_handlers(struct kvm_vm *vm) vm_install_exception_handler(vm, BROADCAST_NOSELF_IPI_VEC, guest_broadcast_noself_ipi_handler); vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); + vm_install_exception_handler(vm, MSI_VECTOR, msi_intr_handler); } int main(int argc, char *argv[]) -- 2.34.1