From: Kishon Vijay Abraham I <kvijayab@xxxxxxx> Secure AVIC requires LAPIC timer to be emulated by hypervisor. KVM already supports emulating LAPIC timer using hrtimers. In order to emulate LAPIC timer, 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. In addition, configure APIC_ALLOWED_IRR for the hypervisor to inject timer interrupt using LOCAL_TIMER_VECTOR. Signed-off-by: Kishon Vijay Abraham I <kvijayab@xxxxxxx> Co-developed-by: Neeraj Upadhyay <Neeraj.Upadhyay@xxxxxxx> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@xxxxxxx> --- Changes since v1: - Move savic_ghcb_msr_read() definition here. - Call update_vector() callback only when it is initialized. arch/x86/coco/sev/core.c | 27 +++++++++++++++++++++++++++ arch/x86/include/asm/sev.h | 2 ++ arch/x86/kernel/apic/apic.c | 4 ++++ arch/x86/kernel/apic/x2apic_savic.c | 7 +++++-- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index 4291cdeb5895..e4c20023e554 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -1505,6 +1505,33 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt) return __vc_handle_msr(ghcb, ctxt, ctxt->insn.opcode.bytes[1] == 0x30); } +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 = ®s }; + struct ghcb_state state; + unsigned long flags; + enum es_result ret; + struct ghcb *ghcb; + + local_irq_save(flags); + ghcb = __sev_get_ghcb(&state); + vc_ghcb_invalidate(ghcb); + + ret = __vc_handle_msr(ghcb, &ctxt, false); + if (ret != ES_OK) { + pr_err("Secure AVIC msr (0x%llx) read returned error (%d)\n", msr, ret); + /* MSR read failures are treated as fatal errors */ + snp_abort(); + } + + __sev_put_ghcb(&state); + local_irq_restore(flags); + + return regs.ax | regs.dx << 32; +} + void savic_ghcb_msr_write(u32 reg, u64 value) { u64 msr = APIC_BASE_MSR + (reg >> 4); diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index 1beeb0daf9e6..043fe8115ec7 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -484,6 +484,7 @@ int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req void __init snp_secure_tsc_prepare(void); void __init snp_secure_tsc_init(void); enum es_result savic_register_gpa(u64 apic_id, u64 gpa); +u64 savic_ghcb_msr_read(u32 reg); void savic_ghcb_msr_write(u32 reg, u64 value); #else /* !CONFIG_AMD_MEM_ENCRYPT */ @@ -530,6 +531,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 apic_id, u64 gpa) { return ES_UNSUPPORTED; } +static inline u64 savic_ghcb_msr_read(u32 reg) { return 0; } static void savic_ghcb_msr_write(u32 reg, u64 value) { } #endif /* CONFIG_AMD_MEM_ENCRYPT */ diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 1c0b5f14435e..23a566a82084 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -591,6 +591,10 @@ static void setup_APIC_timer(void) 0xF, ~0UL); } else clockevents_register_device(levt); + + if (apic->update_vector) + apic->update_vector(smp_processor_id(), LOCAL_TIMER_VECTOR, + true); } /* diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c index 7e3843154997..af46e1b57017 100644 --- a/arch/x86/kernel/apic/x2apic_savic.c +++ b/arch/x86/kernel/apic/x2apic_savic.c @@ -71,6 +71,7 @@ static u32 x2apic_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: @@ -123,10 +124,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: + savic_ghcb_msr_write(reg, data); + break; + case APIC_LVT0: + case APIC_LVT1: case APIC_TASKPRI: case APIC_EOI: case APIC_SPIV: -- 2.34.1