]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/apic: Support LAPIC timer for Secure AVIC
authorNeeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Thu, 28 Aug 2025 11:09:26 +0000 (16:39 +0530)
committerBorislav Petkov (AMD) <bp@alien8.de>
Mon, 1 Sep 2025 10:47:07 +0000 (12:47 +0200)
Secure AVIC requires the LAPIC timer to be emulated by the hypervisor.  KVM
already supports emulating the LAPIC timer using hrtimers. In order to emulate
it, APIC_LVTT, APIC_TMICT and APIC_TDCR register values need to be propagated
to the hypervisor for arming the timer.  APIC_TMCCT register value has to be
read from the hypervisor, which is required for calibrating the APIC timer.
So, read/write all APIC timer registers from/to the hypervisor.

Co-developed-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Tianyu Lan <tiala@microsoft.com>
Link: https://lore.kernel.org/20250828110926.208866-1-Neeraj.Upadhyay@amd.com
arch/x86/coco/sev/core.c
arch/x86/include/asm/sev.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/x2apic_savic.c

index bb33fc2265dba87f20849928f3327bc0b9471204..da9fa9d7254b6184910147b3e0e6f9924fd866db 100644 (file)
@@ -1108,6 +1108,32 @@ int __init sev_es_efi_map_ghcbs_cas(pgd_t *pgd)
        return 0;
 }
 
+u64 savic_ghcb_msr_read(u32 reg)
+{
+       u64 msr = APIC_BASE_MSR + (reg >> 4);
+       struct pt_regs regs = { .cx = msr };
+       struct es_em_ctxt ctxt = { .regs = &regs };
+       struct ghcb_state state;
+       enum es_result res;
+       struct ghcb *ghcb;
+
+       guard(irqsave)();
+
+       ghcb = __sev_get_ghcb(&state);
+       vc_ghcb_invalidate(ghcb);
+
+       res = sev_es_ghcb_handle_msr(ghcb, &ctxt, false);
+       if (res != ES_OK) {
+               pr_err("Secure AVIC MSR (0x%llx) read returned error (%d)\n", msr, res);
+               /* MSR read failures are treated as fatal errors */
+               snp_abort();
+       }
+
+       __sev_put_ghcb(&state);
+
+       return regs.ax | regs.dx << 32;
+}
+
 void savic_ghcb_msr_write(u32 reg, u64 value)
 {
        u64 msr = APIC_BASE_MSR + (reg >> 4);
index fa2864eb3e20fe430dace5dd3164bbeea1ca95e5..875c7669ba95f7b7b11806307b9f3dc0c6cd4e7d 100644 (file)
@@ -534,6 +534,7 @@ int snp_svsm_vtpm_send_command(u8 *buffer);
 void __init snp_secure_tsc_prepare(void);
 void __init snp_secure_tsc_init(void);
 enum es_result savic_register_gpa(u64 gpa);
+u64 savic_ghcb_msr_read(u32 reg);
 void savic_ghcb_msr_write(u32 reg, u64 value);
 
 static __always_inline void vc_ghcb_invalidate(struct ghcb *ghcb)
@@ -609,6 +610,7 @@ static inline void __init snp_secure_tsc_prepare(void) { }
 static inline void __init snp_secure_tsc_init(void) { }
 static inline enum es_result savic_register_gpa(u64 gpa) { return ES_UNSUPPORTED; }
 static inline void savic_ghcb_msr_write(u32 reg, u64 value) { }
+static inline u64 savic_ghcb_msr_read(u32 reg) { return 0; }
 
 #endif /* CONFIG_AMD_MEM_ENCRYPT */
 
index 7874284c1ca7fdcafdaee1501efcf6caac1bcc8e..db18810576bc057cc62abf01ffb29d3af5570da3 100644 (file)
@@ -592,6 +592,8 @@ static void setup_APIC_timer(void)
                                                0xF, ~0UL);
        } else
                clockevents_register_device(levt);
+
+       apic_update_vector(smp_processor_id(), LOCAL_TIMER_VECTOR, true);
 }
 
 /*
index 47dfbf0c5ec502769b3b1bc740069dc6f98d03c2..bdefe4cd4e29255a783eb66f2ada0de2a928d1a2 100644 (file)
@@ -67,6 +67,7 @@ static u32 savic_read(u32 reg)
        case APIC_TMICT:
        case APIC_TMCCT:
        case APIC_TDCR:
+               return savic_ghcb_msr_read(reg);
        case APIC_ID:
        case APIC_LVR:
        case APIC_TASKPRI:
@@ -194,10 +195,12 @@ static void savic_write(u32 reg, u32 data)
 
        switch (reg) {
        case APIC_LVTT:
-       case APIC_LVT0:
-       case APIC_LVT1:
        case APIC_TMICT:
        case APIC_TDCR:
+               savic_ghcb_msr_write(reg, data);
+               break;
+       case APIC_LVT0:
+       case APIC_LVT1:
        case APIC_TASKPRI:
        case APIC_EOI:
        case APIC_SPIV: