diff options
| author | Michael Roth <michael.roth@amd.com> | 2021-11-10 16:07:25 -0600 |
|---|---|---|
| committer | Joerg Roedel <jroedel@suse.de> | 2021-11-15 14:14:59 +0100 |
| commit | d35494e7aba4b3a2e7b1c9be9add9968be6d8ffd (patch) | |
| tree | 5e1670a6b037597592a4c783d28cbf7a5d47a5a4 | |
| parent | 3ef653bfccaa36cfa6191851fbbc71248ede9e7a (diff) | |
| download | linux-d35494e7aba4b3a2e7b1c9be9add9968be6d8ffd.tar.gz | |
x86/sev: add SEV-SNP feature detection/setup
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>
| -rw-r--r-- | arch/x86/include/asm/sev.h | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/sev-shared.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/sev.c | 65 | ||||
| -rw-r--r-- | arch/x86/mm/mem_encrypt_identity.c | 8 |
4 files changed, 76 insertions, 2 deletions
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index b6a97863b71fe..2c382533aeeaa 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -147,6 +147,7 @@ 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); +void snp_abort(void); /* * TODO: These are exported only temporarily while boot/compressed/sev.c is * the only user. This is to avoid unused function warnings for kernel/sev.c @@ -156,7 +157,6 @@ bool snp_init(struct boot_params *bp); * can be moved back to being statically-scoped to units that pull in * sev-shared.c via #include and these declarations can be dropped. */ -struct cc_blob_sev_info *snp_find_cc_blob_setup_data(struct boot_params *bp); void __init snp_cpuid_info_create(const struct cc_blob_sev_info *cc_info); #else static inline void sev_es_ist_enter(struct pt_regs *regs) { } @@ -176,6 +176,7 @@ static inline void snp_set_memory_shared(unsigned long vaddr, unsigned int npage 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; } +static inline void snp_abort(void) { } #endif #endif diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c index 4189d2808ff47..d91b61061b1d4 100644 --- a/arch/x86/kernel/sev-shared.c +++ b/arch/x86/kernel/sev-shared.c @@ -989,7 +989,7 @@ static struct cc_setup_data *get_cc_setup_data(struct boot_params *bp) * Search for a Confidential Computing blob passed in as a setup_data entry * via the Linux Boot Protocol. */ -struct cc_blob_sev_info * +static struct cc_blob_sev_info * snp_find_cc_blob_setup_data(struct boot_params *bp) { struct cc_setup_data *sd; diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c index 403ae5cddbe8f..b794606c7ab2c 100644 --- a/arch/x86/kernel/sev.c +++ b/arch/x86/kernel/sev.c @@ -2010,3 +2010,68 @@ fail: while (true) halt(); } + +/* + * Initial set up of SEV-SNP relies on information provided by the + * Confidential Computing blob, which can be passed to the kernel + * in the following ways, depending on how it is booted: + * + * - when booted via the boot/decompress kernel: + * - via boot_params + * + * - when booted directly by firmware/bootloader (e.g. CONFIG_PVH): + * - via a setup_data entry, as defined by the Linux Boot Protocol + * + * Scan for the blob in that order. + */ +struct cc_blob_sev_info *snp_find_cc_blob(struct boot_params *bp) +{ + struct cc_blob_sev_info *cc_info; + + /* Boot kernel would have passed the CC blob via boot_params. */ + if (bp->cc_blob_address) { + cc_info = (struct cc_blob_sev_info *) + (unsigned long)bp->cc_blob_address; + goto found_cc_info; + } + + /* + * If kernel was booted directly, without the use of the + * boot/decompression kernel, the CC blob may have been passed via + * setup_data instead. + */ + 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(1, GHCB_SNP_UNSUPPORTED); + + return cc_info; +} + +bool __init 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; + + /* + * The CC blob will be used later to access the secrets page. Cache + * it here like the boot kernel does. + */ + bp->cc_blob_address = (u32)(unsigned long)cc_info; + + return true; +} + +void __init snp_abort(void) +{ + sev_es_terminate(1, GHCB_SNP_UNSUPPORTED); +} diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c index 3f0abb4033403..2f723e106ed3b 100644 --- a/arch/x86/mm/mem_encrypt_identity.c +++ b/arch/x86/mm/mem_encrypt_identity.c @@ -44,6 +44,7 @@ #include <asm/setup.h> #include <asm/sections.h> #include <asm/cmdline.h> +#include <asm/sev.h> #include "mm_internal.h" @@ -508,8 +509,11 @@ void __init sme_enable(struct boot_params *bp) bool active_by_default; unsigned long me_mask; char buffer[16]; + bool snp; u64 msr; + snp = snp_init(bp); + /* Check for the SME/SEV support leaf */ eax = 0x80000000; ecx = 0; @@ -541,6 +545,10 @@ void __init sme_enable(struct boot_params *bp) sev_status = __rdmsr(MSR_AMD64_SEV); feature_mask = (sev_status & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT; + /* The SEV-SNP CC blob should never be present unless SEV-SNP is enabled. */ + if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED)) + snp_abort(); + /* Check if memory encryption is enabled */ if (feature_mask == AMD_SME_BIT) { /* |
