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 33/43] x86/compressed: Add SEV-SNP feature detection/setup
    Date
    From: Michael Roth <michael.roth@amd.com>

    Initial/preliminary detection of SEV-SNP is done via the Confidential
    Computing blob. Check for it prior to the normal SEV/SME feature
    initialization, and add some sanity checks to confirm it agrees with
    SEV-SNP CPUID/MSR bits.

    Signed-off-by: Michael Roth <michael.roth@amd.com>
    Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
    ---
    arch/x86/boot/compressed/sev.c | 118 ++++++++++++++++++++++++++++++++-
    arch/x86/include/asm/sev.h | 3 +
    2 files changed, 120 insertions(+), 1 deletion(-)

    diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
    index 1b80c1d0ea1f..04cabff015ba 100644
    --- a/arch/x86/boot/compressed/sev.c
    +++ b/arch/x86/boot/compressed/sev.c
    @@ -286,6 +286,13 @@ static void enforce_vmpl0(void)
    void sev_enable(struct boot_params *bp)
    {
    unsigned int eax, ebx, ecx, edx;
    + bool snp;
    +
    + /*
    + * Setup/preliminary detection of SEV-SNP. This will be sanity-checked
    + * against CPUID/MSR values later.
    + */
    + snp = snp_init(bp);

    /* Check for the SME/SEV support leaf */
    eax = 0x80000000;
    @@ -306,8 +313,11 @@ void sev_enable(struct boot_params *bp)
    ecx = 0;
    native_cpuid(&eax, &ebx, &ecx, &edx);
    /* Check whether SEV is supported */
    - if (!(eax & BIT(1)))
    + if (!(eax & BIT(1))) {
    + if (snp)
    + error("SEV-SNP support indicated by CC blob, but not CPUID.");
    return;
    + }

    /* Set the SME mask if this is an SEV guest. */
    sev_status = rd_sev_status_msr();
    @@ -332,5 +342,111 @@ void sev_enable(struct boot_params *bp)
    enforce_vmpl0();
    }

    + if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
    + error("SEV-SNP supported indicated by CC blob, but not SEV status MSR.");
    +
    sme_me_mask = BIT_ULL(ebx & 0x3f);
    }
    +
    +/* Search for Confidential Computing blob in the EFI config table. */
    +static struct cc_blob_sev_info *snp_find_cc_blob_efi(struct boot_params *bp)
    +{
    + unsigned long cfg_table_pa;
    + unsigned int cfg_table_len;
    + int ret;
    +
    + ret = efi_get_conf_table(bp, &cfg_table_pa, &cfg_table_len);
    + if (ret)
    + return NULL;
    +
    + return (struct cc_blob_sev_info *)efi_find_vendor_table(bp, cfg_table_pa,
    + cfg_table_len,
    + EFI_CC_BLOB_GUID);
    +}
    +
    +struct cc_setup_data {
    + struct setup_data header;
    + u32 cc_blob_address;
    +};
    +
    +static struct cc_setup_data *get_cc_setup_data(struct boot_params *bp)
    +{
    + struct setup_data *hdr = (struct setup_data *)bp->hdr.setup_data;
    +
    + while (hdr) {
    + if (hdr->type == SETUP_CC_BLOB)
    + return (struct cc_setup_data *)hdr;
    + hdr = (struct setup_data *)hdr->next;
    + }
    +
    + return NULL;
    +}
    +
    +/*
    + * Search for a Confidential Computing blob passed in as a setup_data entry
    + * via the Linux Boot Protocol.
    + */
    +static struct cc_blob_sev_info *snp_find_cc_blob_setup_data(struct boot_params *bp)
    +{
    + struct cc_setup_data *sd;
    +
    + sd = get_cc_setup_data(bp);
    + if (!sd)
    + return NULL;
    +
    + return (struct cc_blob_sev_info *)(unsigned long)sd->cc_blob_address;
    +}
    +
    +/*
    + * Initial set up of SEV-SNP relies on information provided by the
    + * Confidential Computing blob, which can be passed to the boot kernel
    + * by firmware/bootloader in the following ways:
    + *
    + * - via an entry in the EFI config table
    + * - via a setup_data structure, as defined by the Linux Boot Protocol
    + *
    + * Scan for the blob in that order.
    + */
    +static struct cc_blob_sev_info *snp_find_cc_blob(struct boot_params *bp)
    +{
    + struct cc_blob_sev_info *cc_info;
    +
    + cc_info = snp_find_cc_blob_efi(bp);
    + if (cc_info)
    + goto found_cc_info;
    +
    + cc_info = snp_find_cc_blob_setup_data(bp);
    + if (!cc_info)
    + return NULL;
    +
    +found_cc_info:
    + if (cc_info->magic != CC_BLOB_SEV_HDR_MAGIC)
    + sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
    +
    + return cc_info;
    +}
    +
    +bool snp_init(struct boot_params *bp)
    +{
    + struct cc_blob_sev_info *cc_info;
    +
    + if (!bp)
    + return false;
    +
    + cc_info = snp_find_cc_blob(bp);
    + if (!cc_info)
    + return false;
    +
    + /*
    + * Pass run-time kernel a pointer to CC info via boot_params so EFI
    + * config table doesn't need to be searched again during early startup
    + * phase.
    + */
    + bp->cc_blob_address = (u32)(unsigned long)cc_info;
    +
    + /*
    + * Indicate SEV-SNP based on presence of SEV-SNP-specific CC blob.
    + * Subsequent checks will verify SEV-SNP CPUID/MSR bits.
    + */
    + return true;
    +}
    diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
    index 1a7e21bb6eea..4e3909042001 100644
    --- a/arch/x86/include/asm/sev.h
    +++ b/arch/x86/include/asm/sev.h
    @@ -11,6 +11,7 @@
    #include <linux/types.h>
    #include <asm/insn.h>
    #include <asm/sev-common.h>
    +#include <asm/bootparam.h>

    #define GHCB_PROTOCOL_MIN 1ULL
    #define GHCB_PROTOCOL_MAX 2ULL
    @@ -151,6 +152,7 @@ void __init snp_prep_memory(unsigned long paddr, unsigned int sz, enum psc_op op
    void snp_set_memory_shared(unsigned long vaddr, unsigned int npages);
    void snp_set_memory_private(unsigned long vaddr, unsigned int npages);
    void snp_set_wakeup_secondary_cpu(void);
    +bool snp_init(struct boot_params *bp);
    #else
    static inline void sev_es_ist_enter(struct pt_regs *regs) { }
    static inline void sev_es_ist_exit(void) { }
    @@ -168,6 +170,7 @@ static inline void __init snp_prep_memory(unsigned long paddr, unsigned int sz,
    static inline void snp_set_memory_shared(unsigned long vaddr, unsigned int npages) { }
    static inline void snp_set_memory_private(unsigned long vaddr, unsigned int npages) { }
    static inline void snp_set_wakeup_secondary_cpu(void) { }
    +static inline bool snp_init(struct boot_params *bp) { return false; }
    #endif

    #endif
    --
    2.25.1
    \
     
     \ /
      Last update: 2022-01-28 18:20    [W:4.279 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site