lkml.org 
[lkml]   [2022]   [Jan]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v9 15/43] x86/sev: Register GHCB memory when SEV-SNP is active
    Date
    The SEV-SNP guest is required by the GHCB spec to register the GHCB's
    Guest Physical Address (GPA). This is because the hypervisor may prefer
    that a guest use a consistent and/or specific GPA for the GHCB associated
    with a vCPU. For more information, see the GHCB specification section
    "GHCB GPA Registration".

    Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
    ---
    arch/x86/include/asm/sev.h | 2 +
    arch/x86/kernel/cpu/common.c | 4 +
    arch/x86/kernel/head64.c | 4 +-
    arch/x86/kernel/sev-shared.c | 2 +-
    arch/x86/kernel/sev.c | 145 ++++++++++++++++++++---------------
    5 files changed, 94 insertions(+), 63 deletions(-)

    diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
    index e37451849165..48df02713ee0 100644
    --- a/arch/x86/include/asm/sev.h
    +++ b/arch/x86/include/asm/sev.h
    @@ -122,6 +122,7 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)

    return rc;
    }
    +void setup_ghcb(void);
    #else
    static inline void sev_es_ist_enter(struct pt_regs *regs) { }
    static inline void sev_es_ist_exit(void) { }
    @@ -130,6 +131,7 @@ static inline void sev_es_nmi_complete(void) { }
    static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
    static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
    static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; }
    +static inline void setup_ghcb(void) { }
    #endif

    #endif
    diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
    index 7b8382c11788..d3c319f2ffd2 100644
    --- a/arch/x86/kernel/cpu/common.c
    +++ b/arch/x86/kernel/cpu/common.c
    @@ -59,6 +59,7 @@
    #include <asm/cpu_device_id.h>
    #include <asm/uv/uv.h>
    #include <asm/sigframe.h>
    +#include <asm/sev.h>

    #include "cpu.h"

    @@ -1988,6 +1989,9 @@ void cpu_init_exception_handling(void)

    load_TR_desc();

    + /* GHCB need to be setup to handle #VC. */
    + setup_ghcb();
    +
    /* Finally load the IDT */
    load_current_idt();
    }
    diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
    index 66363f51a3ad..8075e91cff2b 100644
    --- a/arch/x86/kernel/head64.c
    +++ b/arch/x86/kernel/head64.c
    @@ -597,8 +597,10 @@ static void startup_64_load_idt(unsigned long physbase)
    void early_setup_idt(void)
    {
    /* VMM Communication Exception */
    - if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))
    + if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
    + setup_ghcb();
    set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb);
    + }

    bringup_idt_descr.address = (unsigned long)bringup_idt_table;
    native_load_idt(&bringup_idt_descr);
    diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
    index e9ff13cd90b0..3aaef1a18ffe 100644
    --- a/arch/x86/kernel/sev-shared.c
    +++ b/arch/x86/kernel/sev-shared.c
    @@ -68,7 +68,7 @@ static u64 get_hv_features(void)
    return GHCB_MSR_HV_FT_RESP_VAL(val);
    }

    -static void __maybe_unused snp_register_ghcb_early(unsigned long paddr)
    +static void snp_register_ghcb_early(unsigned long paddr)
    {
    unsigned long pfn = paddr >> PAGE_SHIFT;
    u64 val;
    diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
    index 24df739c9c05..b86b48b66a44 100644
    --- a/arch/x86/kernel/sev.c
    +++ b/arch/x86/kernel/sev.c
    @@ -41,7 +41,7 @@ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);
    * Needs to be in the .data section because we need it NULL before bss is
    * cleared
    */
    -static struct ghcb __initdata *boot_ghcb;
    +static struct ghcb *boot_ghcb __section(".data");

    /* Bitmap of SEV features supported by the hypervisor */
    static u64 sev_hv_features __ro_after_init;
    @@ -161,55 +161,6 @@ void noinstr __sev_es_ist_exit(void)
    this_cpu_write(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC], *(unsigned long *)ist);
    }

    -/*
    - * Nothing shall interrupt this code path while holding the per-CPU
    - * GHCB. The backup GHCB is only for NMIs interrupting this path.
    - *
    - * Callers must disable local interrupts around it.
    - */
    -static noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
    -{
    - struct sev_es_runtime_data *data;
    - struct ghcb *ghcb;
    -
    - WARN_ON(!irqs_disabled());
    -
    - data = this_cpu_read(runtime_data);
    - ghcb = &data->ghcb_page;
    -
    - if (unlikely(data->ghcb_active)) {
    - /* GHCB is already in use - save its contents */
    -
    - if (unlikely(data->backup_ghcb_active)) {
    - /*
    - * Backup-GHCB is also already in use. There is no way
    - * to continue here so just kill the machine. To make
    - * panic() work, mark GHCBs inactive so that messages
    - * can be printed out.
    - */
    - data->ghcb_active = false;
    - data->backup_ghcb_active = false;
    -
    - instrumentation_begin();
    - panic("Unable to handle #VC exception! GHCB and Backup GHCB are already in use");
    - instrumentation_end();
    - }
    -
    - /* Mark backup_ghcb active before writing to it */
    - data->backup_ghcb_active = true;
    -
    - state->ghcb = &data->backup_ghcb;
    -
    - /* Backup GHCB content */
    - *state->ghcb = *ghcb;
    - } else {
    - state->ghcb = NULL;
    - data->ghcb_active = true;
    - }
    -
    - return ghcb;
    -}
    -
    static inline u64 sev_es_rd_ghcb_msr(void)
    {
    return __rdmsr(MSR_AMD64_SEV_ES_GHCB);
    @@ -483,6 +434,55 @@ static enum es_result vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt
    /* Include code shared with pre-decompression boot stage */
    #include "sev-shared.c"

    +/*
    + * Nothing shall interrupt this code path while holding the per-CPU
    + * GHCB. The backup GHCB is only for NMIs interrupting this path.
    + *
    + * Callers must disable local interrupts around it.
    + */
    +static noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
    +{
    + struct sev_es_runtime_data *data;
    + struct ghcb *ghcb;
    +
    + WARN_ON(!irqs_disabled());
    +
    + data = this_cpu_read(runtime_data);
    + ghcb = &data->ghcb_page;
    +
    + if (unlikely(data->ghcb_active)) {
    + /* GHCB is already in use - save its contents */
    +
    + if (unlikely(data->backup_ghcb_active)) {
    + /*
    + * Backup-GHCB is also already in use. There is no way
    + * to continue here so just kill the machine. To make
    + * panic() work, mark GHCBs inactive so that messages
    + * can be printed out.
    + */
    + data->ghcb_active = false;
    + data->backup_ghcb_active = false;
    +
    + instrumentation_begin();
    + panic("Unable to handle #VC exception! GHCB and Backup GHCB are already in use");
    + instrumentation_end();
    + }
    +
    + /* Mark backup_ghcb active before writing to it */
    + data->backup_ghcb_active = true;
    +
    + state->ghcb = &data->backup_ghcb;
    +
    + /* Backup GHCB content */
    + *state->ghcb = *ghcb;
    + } else {
    + state->ghcb = NULL;
    + data->ghcb_active = true;
    + }
    +
    + return ghcb;
    +}
    +
    static noinstr void __sev_put_ghcb(struct ghcb_state *state)
    {
    struct sev_es_runtime_data *data;
    @@ -647,15 +647,40 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
    return ret;
    }

    -/*
    - * This function runs on the first #VC exception after the kernel
    - * switched to virtual addresses.
    - */
    -static bool __init sev_es_setup_ghcb(void)
    +static void snp_register_per_cpu_ghcb(void)
    +{
    + struct sev_es_runtime_data *data;
    + struct ghcb *ghcb;
    +
    + data = this_cpu_read(runtime_data);
    + ghcb = &data->ghcb_page;
    +
    + snp_register_ghcb_early(__pa(ghcb));
    +}
    +
    +void setup_ghcb(void)
    {
    + if (!cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT))
    + return;
    +
    /* First make sure the hypervisor talks a supported protocol. */
    if (!sev_es_negotiate_protocol())
    - return false;
    + sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
    +
    + /*
    + * Check whether the runtime #VC exception handler is active.
    + * The runtime exception handler uses the per-CPU GHCB page, and
    + * the GHCB page would be setup by sev_es_init_vc_handling().
    + *
    + * If SEV-SNP is active, then register the per-CPU GHCB page so
    + * that runtime exception handler can use it.
    + */
    + if (initial_vc_handler == (unsigned long)kernel_exc_vmm_communication) {
    + if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
    + snp_register_per_cpu_ghcb();
    +
    + return;
    + }

    /*
    * Clear the boot_ghcb. The first exception comes in before the bss
    @@ -666,7 +691,9 @@ static bool __init sev_es_setup_ghcb(void)
    /* Alright - Make the boot-ghcb public */
    boot_ghcb = &boot_ghcb_page;

    - return true;
    + /* SEV-SNP guest requires that GHCB GPA must be registered. */
    + if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
    + snp_register_ghcb_early(__pa(&boot_ghcb_page));
    }

    #ifdef CONFIG_HOTPLUG_CPU
    @@ -1398,10 +1425,6 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)
    struct es_em_ctxt ctxt;
    enum es_result result;

    - /* Do initial setup or terminate the guest */
    - if (unlikely(boot_ghcb == NULL && !sev_es_setup_ghcb()))
    - sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
    -
    vc_ghcb_invalidate(boot_ghcb);

    result = vc_init_em_ctxt(&ctxt, regs, exit_code);
    --
    2.25.1
    \
     
     \ /
      Last update: 2022-01-28 18:19    [W:4.180 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site