Extend SAVIC test with various NMI tests: - Test NMI injection failure when AllowedNMI is not set by guest. - Test NMI injection when 2 NMIs are pending. - Test ICR based cross-VCPU NMI for fixed-phys, fixed-logical, broadcast-all and broadcast-exclself modes. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@xxxxxxx> --- .../selftests/kvm/include/x86/processor.h | 5 + tools/testing/selftests/kvm/include/x86/sev.h | 1 + tools/testing/selftests/kvm/lib/x86/savic.c | 15 +- tools/testing/selftests/kvm/lib/x86/sev.c | 22 + tools/testing/selftests/kvm/x86/savic_test.c | 388 ++++++++++++++---- 5 files changed, 351 insertions(+), 80 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index f09b18944c47..ebd30c4515e7 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -917,6 +917,11 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs) vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs); } +static inline void vcpu_nmi(struct kvm_vcpu *vcpu) +{ + vcpu_ioctl(vcpu, KVM_NMI, NULL); +} + const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid, uint32_t function, uint32_t index); const struct kvm_cpuid2 *kvm_get_supported_cpuid(void); diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/selftests/kvm/include/x86/sev.h index 81ee79f63b7f..4e8944ca8440 100644 --- a/tools/testing/selftests/kvm/include/x86/sev.h +++ b/tools/testing/selftests/kvm/include/x86/sev.h @@ -160,4 +160,5 @@ void sev_es_vc_handler(struct ex_regs *regs); void sev_es_pv_msr_rw(uint64_t msr, uint64_t *data, bool write); void sev_es_pv_mmio_rw(uint32_t *reg_gpa, uint32_t *data, bool write); void sev_es_savic_notify_gpa(uint64_t gpa); +void sev_es_nmi_complete(void); #endif /* SELFTEST_KVM_SEV_H */ diff --git a/tools/testing/selftests/kvm/lib/x86/savic.c b/tools/testing/selftests/kvm/lib/x86/savic.c index ee2d6b66d6ce..f7301ec6d45f 100644 --- a/tools/testing/selftests/kvm/lib/x86/savic.c +++ b/tools/testing/selftests/kvm/lib/x86/savic.c @@ -91,13 +91,15 @@ int savic_nr_pages_required(uint64_t page_size) */ void set_savic_control_msr(struct guest_apic_page *apic_page, bool enable, bool enable_nmi) { - uint64_t val = apic_page->gpa | BIT_ULL(MSR_AMD64_SECURE_AVIC_EN_BIT); + uint64_t val; if (!enable) { wrmsr(MSR_AMD64_SECURE_AVIC_CONTROL, 0); return; } + val = apic_page->gpa | BIT_ULL(MSR_AMD64_SECURE_AVIC_EN_BIT); + if (enable_nmi) val |= BIT_ULL(MSR_AMD64_SECURE_AVIC_ALLOWED_NMI_BIT); @@ -442,15 +444,18 @@ static void savic_handle_icr_write(uint64_t icr_data) bool logical = icr_data & APIC_DEST_LOGICAL; bool nmi = (icr_data & APIC_DM_FIXED_MASK) == APIC_DM_NMI; uint64_t self_icr_data = APIC_DEST_SELF | APIC_INT_ASSERT | vector; - - if (nmi) - self_icr_data |= APIC_DM_NMI; + struct guest_apic_page *apic_page; switch (dsh) { case APIC_DEST_ALLINC: savic_send_ipi_all_but(vector, nmi); savic_hv_write_reg(APIC_ICR, icr_data); - x2apic_write_reg(APIC_ICR, self_icr_data); + if (nmi) { + apic_page = &apic_page_pool->guest_apic_page[x2apic_read_reg(APIC_ID)]; + savic_write_reg(apic_page, SAVIC_NMI_REQ_OFFSET, 1); + } else { + x2apic_write_reg(APIC_ICR, self_icr_data); + } break; case APIC_DEST_ALLBUT: savic_send_ipi_all_but(vector, nmi); diff --git a/tools/testing/selftests/kvm/lib/x86/sev.c b/tools/testing/selftests/kvm/lib/x86/sev.c index 24a2a29a575b..446f7d7dafda 100644 --- a/tools/testing/selftests/kvm/lib/x86/sev.c +++ b/tools/testing/selftests/kvm/lib/x86/sev.c @@ -20,6 +20,7 @@ #define SVM_VMGEXIT_MMIO_READ 0x80000001 #define SVM_VMGEXIT_MMIO_WRITE 0x80000002 #define SVM_VMGEXIT_SECURE_AVIC 0x8000001a +#define SVM_VMGEXIT_NMI_COMPLETE 0x80000003 struct ghcb_entry { struct ghcb ghcb; @@ -798,3 +799,24 @@ void sev_es_savic_notify_gpa(uint64_t gpa) __GUEST_ASSERT(!ret, "Secure AVIC GPA notification failed, ret: %d", ret); ghcb_free(entry); } + +void sev_es_nmi_complete(void) +{ + struct ghcb_entry *entry; + struct ghcb *ghcb; + int ret; + + entry = ghcb_alloc(); + ghcb = &entry->ghcb; + register_ghcb_page(entry->gpa); + + ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_NMI_COMPLETE); + ghcb_set_sw_exit_info_1(ghcb, 0); + ghcb_set_sw_exit_info_2(ghcb, 0); + + do_vmg_exit(entry->gpa); + ret = ghcb->save.sw_exit_info_1 & 0xffffffff; + __GUEST_ASSERT(!ret, "NMI completion failed, ret: %d", ret); + + ghcb_free(entry); +} diff --git a/tools/testing/selftests/kvm/x86/savic_test.c b/tools/testing/selftests/kvm/x86/savic_test.c index d677b68aa6c6..277ee18a0cbd 100644 --- a/tools/testing/selftests/kvm/x86/savic_test.c +++ b/tools/testing/selftests/kvm/x86/savic_test.c @@ -13,8 +13,8 @@ #include "test_util.h" #include "savic.h" -#define NR_SAVIC_VCPUS 2 -#define NUM_ITERATIONS 2000 +#define NR_SAVIC_VCPUS 4 +#define NUM_ITERATIONS 1000 #define IDLE_HLT_INTR_VECTOR 0x30 #define IOAPIC_VECTOR_START 0x81 @@ -47,6 +47,13 @@ enum savic_test_state { SAVIC_TEST_STATE(SAVIC_IOAPIC), SAVIC_TEST_STATE(SAVIC_IOAPIC2), SAVIC_TEST_STATE(SAVIC_IPI), + SAVIC_TEST_STATE(SAVIC_NMI), + SAVIC_TEST_STATE(SAVIC_NMI2), + SAVIC_TEST_STATE(SAVIC_NMI3), + SAVIC_TEST_STATE(SAVIC_ICR_FIXED_PHYS_NMI), + SAVIC_TEST_STATE(SAVIC_ICR_FIXED_LOGICAL_NMI), + SAVIC_TEST_STATE(SAVIC_ICR_BROADCAST_NMI), + SAVIC_TEST_STATE(SAVIC_ICR_BROADCAST_NOSELF_NMI), }; /* APIC reg values written by host. */ @@ -128,18 +135,32 @@ struct test_data_page { uint64_t ioapic_lirq1_count; uint64_t ioapic_lirq2_count; uint64_t ioapic_rtc_gsi_irq_count; - uint64_t fixed_ipi_wake_count; - uint64_t fixed_ipi_hlt_count; + uint64_t fixed_phys_ipi_wake_count; + uint64_t fixed_phys_ipi_hlt_count; uint64_t fixed_logical_ipi_hlt_count; uint64_t fixed_logical_ipi_wake_count; uint64_t broadcast_ipi_hlt_count; uint64_t broadcast_ipi_wake_count; uint64_t broadcast_noself_ipi_hlt_count; uint64_t broadcast_noself_ipi_wake_count; - uint64_t fixed_ipi_count; + uint64_t fixed_phys_ipi_count; uint64_t fixed_logical_ipi_count; uint64_t broadcast_ipi_count; uint64_t broadcast_noself_ipi_count; + uint64_t *nmi_count_p; + uint64_t nmi_count; + uint64_t fixed_phys_nmi_hlt_count; + uint64_t fixed_phys_nmi_wake_count; + uint64_t fixed_phys_nmi_count; + uint64_t fixed_logical_nmi_hlt_count; + uint64_t fixed_logical_nmi_wake_count; + uint64_t fixed_logical_nmi_count; + uint64_t broadcast_nmi_hlt_count; + uint64_t broadcast_nmi_wake_count; + uint64_t broadcast_nmi_count; + uint64_t broadcast_noself_nmi_hlt_count; + uint64_t broadcast_noself_nmi_wake_count; + uint64_t broadcast_noself_nmi_count; }; static struct test_data_page *test_data[NR_SAVIC_VCPUS]; @@ -581,9 +602,14 @@ static void _ioapic_level_irq_handler(int vec) vec); } +static inline struct test_data_page *get_test_data(void) +{ + return test_data[x2apic_read_reg(APIC_ID)]; +} + static void ioapic_level_irq1_intr_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); int vec; vec = IOAPIC_VECTOR_START + IOAPIC_NUM_EDGE_VECTORS; @@ -593,7 +619,7 @@ static void ioapic_level_irq1_intr_handler(struct ex_regs *regs) static void ioapic_level_irq2_intr_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); int vec; vec = IOAPIC_VECTOR_START + IOAPIC_NUM_EDGE_VECTORS + 1; @@ -603,7 +629,7 @@ static void ioapic_level_irq2_intr_handler(struct ex_regs *regs) static void ioapic_edge_irq1_intr_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); WRITE_ONCE(data->ioapic_eirq1_count, data->ioapic_eirq1_count + 1); x2apic_write_reg(APIC_EOI, 0x00); @@ -611,7 +637,7 @@ static void ioapic_edge_irq1_intr_handler(struct ex_regs *regs) static void ioapic_edge_irq2_intr_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); WRITE_ONCE(data->ioapic_eirq2_count, data->ioapic_eirq2_count + 1); x2apic_write_reg(APIC_EOI, 0x00); @@ -619,7 +645,7 @@ static void ioapic_edge_irq2_intr_handler(struct ex_regs *regs) static void ioapic_rtc_gsi_intr_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); WRITE_ONCE(data->ioapic_rtc_gsi_irq_count, data->ioapic_rtc_gsi_irq_count + 1); x2apic_write_reg(APIC_EOI, 0x00); @@ -627,7 +653,7 @@ static void ioapic_rtc_gsi_intr_handler(struct ex_regs *regs) static void __savic_ioapic(int count) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); int vec = IOAPIC_VECTOR_START; __GUEST_ASSERT(READ_ONCE(data->ioapic_eirq1_count) == count, @@ -726,10 +752,40 @@ static void guest_setup_ioapic(int id) savic_allow_vector(vec); } -static void savic_fixed_ipi(bool logical) +static void set_fixed_counters( + struct test_data_page *data, + uint64_t **fixed_ipi_p, + uint64_t **fixed_ipi_hlt_cnt_p, + uint64_t **fixed_ipi_wake_cnt_p, + bool logical, bool nmi) +{ + if (logical) { + *fixed_ipi_p = + nmi ? &data->fixed_logical_nmi_count : + &data->fixed_logical_ipi_count; + *fixed_ipi_hlt_cnt_p = + nmi ? &data->fixed_logical_nmi_hlt_count : + &data->fixed_logical_ipi_hlt_count; + *fixed_ipi_wake_cnt_p = + nmi ? &data->fixed_logical_nmi_wake_count : + &data->fixed_logical_ipi_wake_count; + } else { + *fixed_ipi_p = + nmi ? &data->fixed_phys_nmi_count : + &data->fixed_phys_ipi_count; + *fixed_ipi_hlt_cnt_p = + nmi ? &data->fixed_phys_nmi_hlt_count : + &data->fixed_phys_ipi_hlt_count; + *fixed_ipi_wake_cnt_p = + nmi ? &data->fixed_phys_nmi_wake_count : + &data->fixed_phys_ipi_wake_count; + } +} + +static void savic_fixed_ipi(bool logical, bool nmi) { uint64_t last_wake_cnt, last_hlt_cnt; - uint64_t last_fixed_ipi_cnt; + uint64_t last_fixed_phys_ipi_cnt; uint64_t tsc_start; uint64_t *fixed_ipi_p; uint64_t *fixed_ipi_hlt_cnt_p; @@ -741,26 +797,26 @@ static void savic_fixed_ipi(bool logical) struct test_data_page *data = test_data[i]; uint64_t dst_apic_id = i; + set_fixed_counters(data, &fixed_ipi_p, + &fixed_ipi_hlt_cnt_p, &fixed_ipi_wake_cnt_p, + logical, nmi); if (logical) { - fixed_ipi_p = &data->fixed_logical_ipi_count; - fixed_ipi_hlt_cnt_p = &data->fixed_logical_ipi_hlt_count; - fixed_ipi_wake_cnt_p = &data->fixed_logical_ipi_wake_count; vec = FIXED_LOGICAL_IPI_VEC | APIC_DEST_LOGICAL; dst_apic_id = 1 << i; } else { - fixed_ipi_p = &data->fixed_ipi_count; - fixed_ipi_hlt_cnt_p = &data->fixed_ipi_hlt_count; - fixed_ipi_wake_cnt_p = &data->fixed_ipi_wake_count; vec = FIXED_IPI_VEC; dst_apic_id = i; } + if (nmi) + vec |= APIC_DM_NMI; + last_wake_cnt = READ_ONCE(*fixed_ipi_wake_cnt_p); while (!READ_ONCE(*fixed_ipi_hlt_cnt_p)) ; last_hlt_cnt = READ_ONCE(*fixed_ipi_hlt_cnt_p); - last_fixed_ipi_cnt = READ_ONCE(*fixed_ipi_p); + last_fixed_phys_ipi_cnt = READ_ONCE(*fixed_ipi_p); for (j = 0; j < NUM_ITERATIONS; j++) { tsc_start = rdtsc(); @@ -769,31 +825,73 @@ static void savic_fixed_ipi(bool logical) while (rdtsc() - tsc_start < 1000000000) { if (READ_ONCE(*fixed_ipi_wake_cnt_p) != last_wake_cnt && READ_ONCE(*fixed_ipi_hlt_cnt_p) != last_hlt_cnt && - READ_ONCE(*fixed_ipi_p) != last_fixed_ipi_cnt) + READ_ONCE(*fixed_ipi_p) != last_fixed_phys_ipi_cnt) break; } __GUEST_ASSERT(READ_ONCE(*fixed_ipi_wake_cnt_p) != last_wake_cnt && READ_ONCE(*fixed_ipi_hlt_cnt_p) != last_hlt_cnt && - READ_ONCE(*fixed_ipi_p) != last_fixed_ipi_cnt, - "wakeup_cnt: %ld last_wake_cnt: %ld hlt_count: %ld last_hlt_cnt: %ld d_ipi_count: %ld last_d_ipi_count: %ld", + READ_ONCE(*fixed_ipi_p) != last_fixed_phys_ipi_cnt, + "%s fixed-%s wake: %ld last_wake: %ld hlt: %ld last_hlt: %ld ipi: %ld last_ipi: %ld", + nmi ? "nmi" : "ipi", + logical ? "logical" : "phys", READ_ONCE(*fixed_ipi_wake_cnt_p), last_wake_cnt, READ_ONCE(*fixed_ipi_hlt_cnt_p), last_hlt_cnt, - READ_ONCE(*fixed_ipi_p), last_fixed_ipi_cnt); + READ_ONCE(*fixed_ipi_p), last_fixed_phys_ipi_cnt); last_wake_cnt = READ_ONCE(*fixed_ipi_wake_cnt_p); last_hlt_cnt = READ_ONCE(*fixed_ipi_hlt_cnt_p); - last_fixed_ipi_cnt = READ_ONCE(*fixed_ipi_p); + last_fixed_phys_ipi_cnt = READ_ONCE(*fixed_ipi_p); } } } -static void savic_send_broadcast(int dsh) +static uint64_t *get_broadcast_ipi_counter(struct test_data_page *data, + int dsh, bool nmi) +{ + if (dsh == APIC_DEST_ALLINC) + return nmi ? + &data->broadcast_nmi_count : + &data->broadcast_ipi_count; + else + return nmi ? + &data->broadcast_noself_nmi_count : + &data->broadcast_noself_ipi_count; +} + + +static uint64_t *get_broadcast_hlt_counter(struct test_data_page *data, + int dsh, bool nmi) +{ + if (dsh == APIC_DEST_ALLINC) + return nmi ? + &data->broadcast_nmi_hlt_count : + &data->broadcast_ipi_hlt_count; + else + return nmi ? + &data->broadcast_noself_nmi_hlt_count : + &data->broadcast_noself_ipi_hlt_count; +} + +static uint64_t *get_broadcast_wake_counter(struct test_data_page *data, + int dsh, bool nmi) +{ + if (dsh == APIC_DEST_ALLINC) + return nmi ? + &data->broadcast_nmi_wake_count : + &data->broadcast_ipi_wake_count; + else + return nmi ? + &data->broadcast_noself_nmi_wake_count : + &data->broadcast_noself_ipi_wake_count; +} + +static void savic_send_broadcast(int dsh, bool nmi) { uint64_t last_wake_cnt[NR_SAVIC_VCPUS], last_hlt_cnt[NR_SAVIC_VCPUS]; uint64_t last_ipi_cnt[NR_SAVIC_VCPUS]; uint64_t tsc_start; - uint64_t *broadcast_ipi_p; + uint64_t *broadcast_ipi_cnt_p; uint64_t *broadcast_ipi_hlt_cnt_p; uint64_t *broadcast_ipi_wake_cnt_p; struct test_data_page *data; @@ -808,10 +906,8 @@ static void savic_send_broadcast(int dsh) for (i = 1; i < NR_SAVIC_VCPUS; i++) { data = test_data[i]; - if (dsh == APIC_DEST_ALLINC) - broadcast_ipi_hlt_cnt_p = &data->broadcast_ipi_hlt_count; - else - broadcast_ipi_hlt_cnt_p = &data->broadcast_noself_ipi_hlt_count; + broadcast_ipi_hlt_cnt_p = get_broadcast_hlt_counter( + data, dsh, nmi); while (!READ_ONCE(*broadcast_ipi_hlt_cnt_p)) ; @@ -821,17 +917,20 @@ static void savic_send_broadcast(int dsh) for (i = 1; i < NR_SAVIC_VCPUS; i++) { data = test_data[i]; - if (dsh == APIC_DEST_ALLINC) { - last_hlt_cnt[i] = READ_ONCE(data->broadcast_ipi_hlt_count); - last_ipi_cnt[i] = READ_ONCE(data->broadcast_ipi_count); - last_wake_cnt[i] = READ_ONCE(data->broadcast_ipi_wake_count); - } else { - last_hlt_cnt[i] = READ_ONCE(data->broadcast_noself_ipi_hlt_count); - last_ipi_cnt[i] = READ_ONCE(data->broadcast_noself_ipi_count); - last_wake_cnt[i] = READ_ONCE(data->broadcast_noself_ipi_wake_count); - } + broadcast_ipi_cnt_p = get_broadcast_ipi_counter( + data, dsh, nmi); + broadcast_ipi_hlt_cnt_p = get_broadcast_hlt_counter( + data, dsh, nmi); + broadcast_ipi_wake_cnt_p = get_broadcast_wake_counter( + data, dsh, nmi); + last_ipi_cnt[i] = *broadcast_ipi_cnt_p; + last_hlt_cnt[i] = *broadcast_ipi_hlt_cnt_p; + last_wake_cnt[i] = *broadcast_ipi_wake_cnt_p; } + if (nmi) + vec |= APIC_DM_NMI; + x2apic_write_reg(APIC_ICR, APIC_INT_ASSERT | dsh | vec); tsc_start = rdtsc(); @@ -839,60 +938,59 @@ static void savic_send_broadcast(int dsh) for (i = 1; i < NR_SAVIC_VCPUS; i++) { data = test_data[i]; - if (dsh == APIC_DEST_ALLINC) { - broadcast_ipi_p = &data->broadcast_ipi_count; - broadcast_ipi_hlt_cnt_p = &data->broadcast_ipi_hlt_count; - broadcast_ipi_wake_cnt_p = &data->broadcast_ipi_wake_count; - } else { - broadcast_ipi_p = &data->broadcast_noself_ipi_count; - broadcast_ipi_hlt_cnt_p = &data->broadcast_noself_ipi_hlt_count; - broadcast_ipi_wake_cnt_p = &data->broadcast_noself_ipi_wake_count; - } + broadcast_ipi_cnt_p = get_broadcast_ipi_counter( + data, dsh, nmi); + broadcast_ipi_hlt_cnt_p = get_broadcast_hlt_counter( + data, dsh, nmi); + broadcast_ipi_wake_cnt_p = get_broadcast_wake_counter( + data, dsh, nmi); while (rdtsc() - tsc_start < 1000000000) { if (READ_ONCE(*broadcast_ipi_wake_cnt_p) != last_wake_cnt[i] && READ_ONCE(*broadcast_ipi_hlt_cnt_p) != last_hlt_cnt[i] && - READ_ONCE(*broadcast_ipi_p) != last_ipi_cnt[i]) + READ_ONCE(*broadcast_ipi_cnt_p) != last_ipi_cnt[i]) break; } __GUEST_ASSERT(READ_ONCE(*broadcast_ipi_wake_cnt_p) != last_wake_cnt[i] && READ_ONCE(*broadcast_ipi_hlt_cnt_p) != last_hlt_cnt[i] && - READ_ONCE(*broadcast_ipi_p) != last_ipi_cnt[i], - "wakeup_cnt: %ld last_wake_cnt: %ld hlt_count: %ld last_hlt_cnt: %ld b_ipi_count: %ld last_b_ipi_count: %ld", + READ_ONCE(*broadcast_ipi_cnt_p) != last_ipi_cnt[i], + "%s broadcast-%s wake: %ld last_wake: %ld hlt: %ld last_hlt: %ld ipi: %ld last_ipi: %ld", + nmi ? "nmi" : "ipi", + dsh == APIC_DEST_ALLINC ? "all" : "excl-self", READ_ONCE(*broadcast_ipi_wake_cnt_p), last_wake_cnt[i], READ_ONCE(*broadcast_ipi_hlt_cnt_p), last_hlt_cnt[i], - READ_ONCE(*broadcast_ipi_p), last_ipi_cnt[i]); + READ_ONCE(*broadcast_ipi_cnt_p), last_ipi_cnt[i]); last_wake_cnt[i] = READ_ONCE(*broadcast_ipi_wake_cnt_p); last_hlt_cnt[i] = READ_ONCE(*broadcast_ipi_hlt_cnt_p); - last_ipi_cnt[i] = READ_ONCE(*broadcast_ipi_p); + last_ipi_cnt[i] = READ_ONCE(*broadcast_ipi_cnt_p); } } } void savic_ipi(int id) { - savic_fixed_ipi(false); - savic_fixed_ipi(true); + savic_fixed_ipi(false, false); + savic_fixed_ipi(true, false); asm volatile("sti;":::"memory"); x2apic_write_reg(APIC_TASKPRI, 0); - savic_send_broadcast(APIC_DEST_ALLINC); - savic_send_broadcast(APIC_DEST_ALLBUT); + savic_send_broadcast(APIC_DEST_ALLINC, false); + savic_send_broadcast(APIC_DEST_ALLBUT, false); } -void guest_fixed_ipi_handler(struct ex_regs *regs) +void guest_fixed_phys_ipi_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); - WRITE_ONCE(data->fixed_ipi_count, data->fixed_ipi_count + 1); + WRITE_ONCE(data->fixed_phys_ipi_count, data->fixed_phys_ipi_count + 1); x2apic_write_reg(APIC_EOI, 0x00); } void guest_fixed_logical_ipi_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); WRITE_ONCE(data->fixed_logical_ipi_count, data->fixed_logical_ipi_count + 1); x2apic_write_reg(APIC_EOI, 0x00); @@ -900,7 +998,7 @@ void guest_fixed_logical_ipi_handler(struct ex_regs *regs) void guest_broadcast_ipi_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); WRITE_ONCE(data->broadcast_ipi_count, data->broadcast_ipi_count + 1); x2apic_write_reg(APIC_EOI, 0x00); @@ -908,13 +1006,65 @@ void guest_broadcast_ipi_handler(struct ex_regs *regs) void guest_broadcast_noself_ipi_handler(struct ex_regs *regs) { - struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)]; + struct test_data_page *data = get_test_data(); WRITE_ONCE(data->broadcast_noself_ipi_count, data->broadcast_noself_ipi_count + 1); x2apic_write_reg(APIC_EOI, 0x00); } -static void ipi_guest_code(int id, unsigned long secondary_entry) +static void savic_nmi(int id) +{ + struct test_data_page *data = get_test_data(); + + __GUEST_ASSERT(!data->nmi_count, "Invalid NMI count: %ld\n", data->nmi_count); + set_savic_control_msr(get_guest_apic_page(), true, true); +} + +static void savic_nmi2(int id) +{ + struct test_data_page *data = get_test_data(); + + __GUEST_ASSERT(data->nmi_count == 2, "Invalid NMI count: %ld\n", data->nmi_count); +} + +static void savic_nmi3(int id) +{ + struct test_data_page *data = get_test_data(); + + __GUEST_ASSERT(data->nmi_count == 4, "Invalid NMI count: %ld\n", data->nmi_count); +} + +static void savic_icr_fixed_phys(int id) +{ + savic_fixed_ipi(false, true); +} + +static void savic_icr_fixed_logical(int id) +{ + savic_fixed_ipi(true, true); +} + +static void savic_icr_bcast(int id) +{ + savic_send_broadcast(APIC_DEST_ALLINC, true); +} + +static void savic_icr_bcast_noself(int id) +{ + savic_send_broadcast(APIC_DEST_ALLBUT, true); +} + +static void guest_nmi_handler(struct ex_regs *regs) +{ + struct test_data_page *data = get_test_data(); + + WRITE_ONCE(*data->nmi_count_p, *data->nmi_count_p + 1); + /* Skip NMI completed notification for ICR based NMI. */ + if (data->nmi_count_p == &data->nmi_count) + sev_es_nmi_complete(); +} + +static void ipi_guest_code(int id) { struct test_data_page *data; uint64_t *ipi_count_p, *hlt_count_p, *wake_count_p; @@ -928,9 +1078,9 @@ static void ipi_guest_code(int id, unsigned long secondary_entry) uint64_t *ipi_count_types[][3] = { { - &data->fixed_ipi_hlt_count, - &data->fixed_ipi_count, - &data->fixed_ipi_wake_count + &data->fixed_phys_ipi_hlt_count, + &data->fixed_phys_ipi_count, + &data->fixed_phys_ipi_wake_count }, { &data->fixed_logical_ipi_hlt_count, @@ -947,6 +1097,26 @@ static void ipi_guest_code(int id, unsigned long secondary_entry) &data->broadcast_noself_ipi_count, &data->broadcast_noself_ipi_wake_count }, + { + &data->fixed_phys_nmi_hlt_count, + &data->fixed_phys_nmi_count, + &data->fixed_phys_nmi_wake_count + }, + { + &data->fixed_logical_nmi_hlt_count, + &data->fixed_logical_nmi_count, + &data->fixed_logical_nmi_wake_count + }, + { + &data->broadcast_nmi_hlt_count, + &data->broadcast_nmi_count, + &data->broadcast_nmi_wake_count + }, + { + &data->broadcast_noself_nmi_hlt_count, + &data->broadcast_noself_nmi_count, + &data->broadcast_noself_nmi_wake_count + }, }; for (i = 0; i < ARRAY_SIZE(ipi_count_types); i++) { @@ -955,9 +1125,11 @@ static void ipi_guest_code(int id, unsigned long secondary_entry) wake_count_p = ipi_count_types[i][2]; while (READ_ONCE(*ipi_count_p) != NUM_ITERATIONS) { - asm volatile("cli"); + if (i < 4) + asm volatile("cli"); WRITE_ONCE(*hlt_count_p, *hlt_count_p + 1); - asm volatile("sti; hlt" : : : "memory"); + if (i < 4) + asm volatile("sti; hlt" : : : "memory"); WRITE_ONCE(*wake_count_p, *wake_count_p + 1); } @@ -969,6 +1141,9 @@ static void ipi_guest_code(int id, unsigned long secondary_entry) static void guest_code(int id) { + struct test_data_page *data; + int i; + GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SNP_SECURE_AVIC); SAVIC_GUEST_SYNC(RESET, guest_savic_start); @@ -991,6 +1166,39 @@ static void guest_code(int id) SAVIC_GUEST_SYNC(SAVIC_IPI, savic_ipi); + /* Disable host NMI injection in control MSR. */ + set_savic_control_msr(get_guest_apic_page(), true, false); + + data = test_data[id]; + data->nmi_count_p = &data->nmi_count; + SAVIC_GUEST_SYNC(SAVIC_NMI, savic_nmi); + SAVIC_GUEST_SYNC(SAVIC_NMI2, savic_nmi2); + SAVIC_GUEST_SYNC(SAVIC_NMI3, savic_nmi3); + + for (i = 0; i < NR_SAVIC_VCPUS; i++) { + data = test_data[i]; + data->nmi_count_p = &data->fixed_phys_nmi_count; + } + SAVIC_GUEST_SYNC(SAVIC_ICR_FIXED_PHYS_NMI, savic_icr_fixed_phys); + + for (i = 0; i < NR_SAVIC_VCPUS; i++) { + data = test_data[i]; + data->nmi_count_p = &data->fixed_logical_nmi_count; + } + SAVIC_GUEST_SYNC(SAVIC_ICR_FIXED_LOGICAL_NMI, savic_icr_fixed_logical); + + for (i = 0; i < NR_SAVIC_VCPUS; i++) { + data = test_data[i]; + data->nmi_count_p = &data->broadcast_nmi_count; + } + SAVIC_GUEST_SYNC(SAVIC_ICR_BROADCAST_NMI, savic_icr_bcast); + + for (i = 0; i < NR_SAVIC_VCPUS; i++) { + data = test_data[i]; + data->nmi_count_p = &data->broadcast_noself_nmi_count; + } + SAVIC_GUEST_SYNC(SAVIC_ICR_BROADCAST_NOSELF_NMI, savic_icr_bcast_noself); + GUEST_DONE(); } @@ -1105,6 +1313,12 @@ static void host_send_ioapic_irq(struct kvm_vm *vm, int id) } } +static void host_send_nmi(int id) +{ + vcpu_nmi(vcpus[id]); + vcpu_nmi(vcpus[id]); +} + static void host_test_savic(struct kvm_vm *vm, int id, enum savic_test_state test_state) { switch (test_state) { @@ -1132,6 +1346,11 @@ 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_NMI_START: + case SAVIC_NMI2_START: + case SAVIC_NMI3_START: + host_send_nmi(id); + break; default: break; } @@ -1174,11 +1393,12 @@ static void install_exception_handlers(struct kvm_vm *vm) vm_install_exception_handler(vm, IOAPIC_VECTOR_START + 2, ioapic_level_irq1_intr_handler); vm_install_exception_handler(vm, IOAPIC_VECTOR_START + 3, ioapic_level_irq2_intr_handler); vm_install_exception_handler(vm, RTC_GSI_IRQ, ioapic_rtc_gsi_intr_handler); - vm_install_exception_handler(vm, FIXED_IPI_VEC, guest_fixed_ipi_handler); + vm_install_exception_handler(vm, FIXED_IPI_VEC, guest_fixed_phys_ipi_handler); vm_install_exception_handler(vm, FIXED_LOGICAL_IPI_VEC, guest_fixed_logical_ipi_handler); vm_install_exception_handler(vm, BROADCAST_ALL_IPI_VEC, guest_broadcast_ipi_handler); vm_install_exception_handler(vm, BROADCAST_NOSELF_IPI_VEC, guest_broadcast_noself_ipi_handler); + vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); } int main(int argc, char *argv[]) @@ -1239,9 +1459,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "VCPU %d ioapic level irq1 count: %ld level irq2 count: %ld\n", i, shared_state->ioapic_lirq1_count, shared_state->ioapic_lirq2_count); fprintf(stderr, "VCPU %d ioapic RTC GSI irq1 count: %ld\n", i, shared_state->ioapic_rtc_gsi_irq_count); fprintf(stderr, "vCPU %d fixed IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", - i, shared_state->fixed_ipi_wake_count, - shared_state->fixed_ipi_hlt_count, - shared_state->fixed_ipi_count); + i, shared_state->fixed_phys_ipi_wake_count, + shared_state->fixed_phys_ipi_hlt_count, + shared_state->fixed_phys_ipi_count); fprintf(stderr, "vCPU %d fixed-logical IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", i, shared_state->fixed_logical_ipi_wake_count, shared_state->fixed_logical_ipi_hlt_count, @@ -1250,10 +1470,28 @@ int main(int argc, char *argv[]) i, shared_state->broadcast_ipi_wake_count, shared_state->broadcast_ipi_hlt_count, shared_state->broadcast_ipi_count); - fprintf(stderr, "vCPU %d broadcast exluding self IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", + fprintf(stderr, "vCPU %d broadcast excluding self IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", i, shared_state->broadcast_noself_ipi_wake_count, shared_state->broadcast_noself_ipi_hlt_count, shared_state->broadcast_noself_ipi_count); + fprintf(stderr, "vCPU %d nmi count: %ld\n", + i, shared_state->nmi_count); + fprintf(stderr, "vCPU %d nmi fixed IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", + i, shared_state->fixed_phys_nmi_wake_count, + shared_state->fixed_phys_nmi_hlt_count, + shared_state->fixed_phys_nmi_count); + fprintf(stderr, "vCPU %d nmi fixed-logical IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", + i, shared_state->fixed_logical_nmi_wake_count, + shared_state->fixed_logical_nmi_hlt_count, + shared_state->fixed_logical_nmi_count); + fprintf(stderr, "vCPU %d nmi broadcast IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", + i, shared_state->broadcast_nmi_wake_count, + shared_state->broadcast_nmi_hlt_count, + shared_state->broadcast_nmi_count); + fprintf(stderr, "vCPU %d nmi broadcast excluding self IPI counts wake: %ld hlt: %ld num-IPI: %ld\n", + i, shared_state->broadcast_noself_nmi_wake_count, + shared_state->broadcast_noself_nmi_hlt_count, + shared_state->broadcast_noself_nmi_count); } kvm_vm_free(vm); -- 2.34.1