[RFC 11/14] x86/apic: Allow NMI to be injected from hypervisor for Secure AVIC

From: Neeraj Upadhyay
Date: Fri Sep 13 2024 - 07:40:58 EST


From: Kishon Vijay Abraham I <kvijayab@xxxxxxx>

Secure AVIC requires "AllowedNmi" bit in the Secure AVIC Control MSR
to be set for NMI to be injected from hypervisor.

Set "AllowedNmi" bit in Secure AVIC Control MSR here to allow NMI
interrupts to be injected from hypervisor. While at that, also propagate
APIC_LVT0 and APIC_LVT1 register values to the hypervisor required for
injecting NMI interrupts from hypervisor.

Signed-off-by: Kishon Vijay Abraham I <kvijayab@xxxxxxx>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@xxxxxxx>
---
arch/x86/include/asm/msr-index.h | 5 +++++
arch/x86/kernel/apic/x2apic_savic.c | 10 ++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index d0583619c978..0b7454ed7b39 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -662,6 +662,11 @@
#define MSR_AMD64_SNP_SECURE_AVIC_ENABLED BIT_ULL(MSR_AMD64_SNP_SECURE_AVIC_BIT)
#define MSR_AMD64_SNP_RESV_BIT 19
#define MSR_AMD64_SNP_RESERVED_MASK GENMASK_ULL(63, MSR_AMD64_SNP_RESV_BIT)
+#define MSR_AMD64_SECURE_AVIC_CONTROL 0xc0010138
+#define MSR_AMD64_SECURE_AVIC_EN_BIT 0
+#define MSR_AMD64_SECURE_AVIC_EN BIT_ULL(MSR_AMD64_SECURE_AVIC_EN_BIT)
+#define MSR_AMD64_SECURE_AVIC_ALLOWEDNMI_BIT 1
+#define MSR_AMD64_SECURE_AVIC_ALLOWEDNMI BIT_ULL(MSR_AMD64_SECURE_AVIC_ALLOWEDNMI_BIT)

#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f

diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c
index 5502a828a795..321b3678e26f 100644
--- a/arch/x86/kernel/apic/x2apic_savic.c
+++ b/arch/x86/kernel/apic/x2apic_savic.c
@@ -38,6 +38,11 @@ enum lapic_lvt_entry {

#define APIC_LVTx(x) (APIC_LVTT + 0x10 * (x))

+static inline void savic_wr_control_msr(u64 val)
+{
+ native_wrmsr(MSR_AMD64_SECURE_AVIC_CONTROL, lower_32_bits(val), upper_32_bits(val));
+}
+
static int x2apic_savic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
return x2apic_enabled() && cc_platform_has(CC_ATTR_SNP_SECURE_AVIC);
@@ -143,12 +148,12 @@ static void x2apic_savic_write(u32 reg, u32 data)

switch (reg) {
case APIC_LVTT:
+ case APIC_LVT0:
+ case APIC_LVT1:
case APIC_TMICT:
case APIC_TDCR:
write_msr_to_hv(reg, data);
break;
- case APIC_LVT0:
- case APIC_LVT1:
/* APIC_ID is writable and configured by guest for Secure AVIC */
case APIC_ID:
case APIC_TASKPRI:
@@ -401,6 +406,7 @@ static void x2apic_savic_setup(void)
ret = sev_notify_savic_gpa(gpa);
if (ret != ES_OK)
snp_abort();
+ savic_wr_control_msr(gpa | MSR_AMD64_SECURE_AVIC_ALLOWEDNMI);
this_cpu_write(savic_setup_done, true);
}

--
2.34.1