lkml.org 
[lkml]   [2023]   [Oct]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH kernel v3] x86/compressed/64: reduce #VC nesting for intercepted CPUID for SEV-SNP guest
    Date
    For certain intercepts an SNP guest uses the GHCB protocol to talk to
    the hypervisor from the #VC handler. The protocol requires a shared page so
    there is one per vCPU. In case NMI arrives in a middle of #VC or the NMI
    handler triggers a #VC, there is another "backup" GHCB page which stores
    the content of the first one while SVM_VMGEXIT_NMI_COMPLETE is sent.
    The vc_raw_handle_exception() handler manages main and backup GHCB pages
    via __sev_get_ghcb/__sev_put_ghcb.

    This works fine for #VC and occasional NMIs but not so fine when the #VC
    handler causes intercept + another #VC. If NMI arrives during
    the second #VC, there are no more pages for SVM_VMGEXIT_NMI_COMPLETE.
    The problem place is the #VC CPUID handler which reads an MSR which
    triggers another #VC and if "perf" was running, panic happens:

    Kernel panic - not syncing: Unable to handle #VC exception! GHCB and Backup GHCB are already in use

    Add a helper similar to native_read_msr_safe() for making a direct hypercall
    in the SEV-ES environment. Use the new helper instead of the raw "rdmsr" to
    avoid the extra #VC event.

    Fixes: ee0bfa08a345 ("x86/compressed/64: Add support for SEV-SNP CPUID table in #VC handlers")
    Signed-off-by: Alexey Kardashevskiy <aik@amd.com>
    ---

    Based on:
    https://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git/log/?h=tip-x86-urgent
    which top at the time was:
    62d5e970d022 "x86/sev: Change npages to unsigned long in snp_accept_memory()"

    ---
    Changes:
    v3:
    * made it a function, mimic native_read_msr_safe() which 1) returns value 2) returns an error
    * removed debug backtraces the commit log as these were added for debugging and never
    appear with actual kernels


    v2:
    * de-uglify by defining rdmsr_safe_GHCB()
    ---
    arch/x86/kernel/sev-shared.c | 27 +++++++++++++++++---
    1 file changed, 23 insertions(+), 4 deletions(-)

    diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
    index dcf325b7b022..494d92a71986 100644
    --- a/arch/x86/kernel/sev-shared.c
    +++ b/arch/x86/kernel/sev-shared.c
    @@ -241,6 +241,25 @@ static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
    return verify_exception_info(ghcb, ctxt);
    }

    +
    +/* Paravirt SEV-ES rdmsr which avoids extra #VC event */
    +static unsigned long long ghcb_prot_read_msr(unsigned int msr, struct ghcb *ghcb,
    + struct es_em_ctxt *ctxt, int *err)
    +{
    + unsigned long long ret = 0;
    +
    + ghcb_set_rcx(ghcb, msr);
    +
    + *err = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MSR, 0, 0);
    + if (*err == ES_OK)
    + ret = (ghcb->save.rdx << 32) | ghcb->save.rax;
    +
    + /* Invalidate qwords for likely another following GHCB call */
    + vc_ghcb_invalidate(ghcb);
    +
    + return ret;
    +}
    +
    static int __sev_cpuid_hv(u32 fn, int reg_idx, u32 *reg)
    {
    u64 val;
    @@ -477,11 +496,11 @@ static int snp_cpuid_postprocess(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
    if (leaf->subfn == 1) {
    /* Get XSS value if XSAVES is enabled. */
    if (leaf->eax & BIT(3)) {
    - unsigned long lo, hi;
    + int err = 0;

    - asm volatile("rdmsr" : "=a" (lo), "=d" (hi)
    - : "c" (MSR_IA32_XSS));
    - xss = (hi << 32) | lo;
    + xss = ghcb_prot_read_msr(MSR_IA32_XSS, ghcb, ctxt, &err);
    + if (err != ES_OK)
    + return -EINVAL;
    }

    /*
    --
    2.41.0
    \
     
     \ /
      Last update: 2023-10-03 09:35    [W:6.080 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site