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> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lore.kernel.org/r/20220307213356.2797205-39-brijesh.singh@amd.com
This commit is contained in:
parent
76f61e1e89
commit
b190a043c4
5 changed files with 101 additions and 27 deletions
|
@ -352,33 +352,6 @@ static struct cc_blob_sev_info *find_cc_blob_efi(struct boot_params *bp)
|
||||||
EFI_CC_BLOB_GUID);
|
EFI_CC_BLOB_GUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cc_setup_data {
|
|
||||||
struct setup_data header;
|
|
||||||
u32 cc_blob_address;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Search for a Confidential Computing blob passed in as a setup_data entry
|
|
||||||
* via the Linux Boot Protocol.
|
|
||||||
*/
|
|
||||||
static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
|
|
||||||
{
|
|
||||||
struct cc_setup_data *sd = NULL;
|
|
||||||
struct setup_data *hdr;
|
|
||||||
|
|
||||||
hdr = (struct setup_data *)bp->hdr.setup_data;
|
|
||||||
|
|
||||||
while (hdr) {
|
|
||||||
if (hdr->type == SETUP_CC_BLOB) {
|
|
||||||
sd = (struct cc_setup_data *)hdr;
|
|
||||||
return (struct cc_blob_sev_info *)(unsigned long)sd->cc_blob_address;
|
|
||||||
}
|
|
||||||
hdr = (struct setup_data *)hdr->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial set up of SNP relies on information provided by the
|
* Initial set up of SNP relies on information provided by the
|
||||||
* Confidential Computing blob, which can be passed to the boot kernel
|
* Confidential Computing blob, which can be passed to the boot kernel
|
||||||
|
|
|
@ -153,6 +153,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_memory_private(unsigned long vaddr, unsigned int npages);
|
||||||
void snp_set_wakeup_secondary_cpu(void);
|
void snp_set_wakeup_secondary_cpu(void);
|
||||||
bool snp_init(struct boot_params *bp);
|
bool snp_init(struct boot_params *bp);
|
||||||
|
void snp_abort(void);
|
||||||
#else
|
#else
|
||||||
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
|
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
|
||||||
static inline void sev_es_ist_exit(void) { }
|
static inline void sev_es_ist_exit(void) { }
|
||||||
|
@ -171,6 +172,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_memory_private(unsigned long vaddr, unsigned int npages) { }
|
||||||
static inline void snp_set_wakeup_secondary_cpu(void) { }
|
static inline void snp_set_wakeup_secondary_cpu(void) { }
|
||||||
static inline bool snp_init(struct boot_params *bp) { return false; }
|
static inline bool snp_init(struct boot_params *bp) { return false; }
|
||||||
|
static inline void snp_abort(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -937,3 +937,30 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,
|
||||||
|
|
||||||
return ES_OK;
|
return ES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cc_setup_data {
|
||||||
|
struct setup_data header;
|
||||||
|
u32 cc_blob_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for a Confidential Computing blob passed in as a setup_data entry
|
||||||
|
* via the Linux Boot Protocol.
|
||||||
|
*/
|
||||||
|
static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
|
||||||
|
{
|
||||||
|
struct cc_setup_data *sd = NULL;
|
||||||
|
struct setup_data *hdr;
|
||||||
|
|
||||||
|
hdr = (struct setup_data *)bp->hdr.setup_data;
|
||||||
|
|
||||||
|
while (hdr) {
|
||||||
|
if (hdr->type == SETUP_CC_BLOB) {
|
||||||
|
sd = (struct cc_setup_data *)hdr;
|
||||||
|
return (struct cc_blob_sev_info *)(unsigned long)sd->cc_blob_address;
|
||||||
|
}
|
||||||
|
hdr = (struct setup_data *)hdr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -1974,3 +1974,67 @@ fail:
|
||||||
while (true)
|
while (true)
|
||||||
halt();
|
halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initial set up of 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.
|
||||||
|
*/
|
||||||
|
static __init struct cc_blob_sev_info *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 = find_cc_blob_setup_data(bp);
|
||||||
|
if (!cc_info)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
found_cc_info:
|
||||||
|
if (cc_info->magic != CC_BLOB_SEV_HDR_MAGIC)
|
||||||
|
snp_abort();
|
||||||
|
|
||||||
|
return cc_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __init snp_init(struct boot_params *bp)
|
||||||
|
{
|
||||||
|
struct cc_blob_sev_info *cc_info;
|
||||||
|
|
||||||
|
if (!bp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cc_info = 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(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
#include <asm/cmdline.h>
|
#include <asm/cmdline.h>
|
||||||
#include <asm/coco.h>
|
#include <asm/coco.h>
|
||||||
|
#include <asm/sev.h>
|
||||||
|
|
||||||
#include "mm_internal.h"
|
#include "mm_internal.h"
|
||||||
|
|
||||||
|
@ -509,8 +510,11 @@ void __init sme_enable(struct boot_params *bp)
|
||||||
bool active_by_default;
|
bool active_by_default;
|
||||||
unsigned long me_mask;
|
unsigned long me_mask;
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
|
bool snp;
|
||||||
u64 msr;
|
u64 msr;
|
||||||
|
|
||||||
|
snp = snp_init(bp);
|
||||||
|
|
||||||
/* Check for the SME/SEV support leaf */
|
/* Check for the SME/SEV support leaf */
|
||||||
eax = 0x80000000;
|
eax = 0x80000000;
|
||||||
ecx = 0;
|
ecx = 0;
|
||||||
|
@ -542,6 +546,10 @@ void __init sme_enable(struct boot_params *bp)
|
||||||
sev_status = __rdmsr(MSR_AMD64_SEV);
|
sev_status = __rdmsr(MSR_AMD64_SEV);
|
||||||
feature_mask = (sev_status & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT;
|
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 */
|
/* Check if memory encryption is enabled */
|
||||||
if (feature_mask == AMD_SME_BIT) {
|
if (feature_mask == AMD_SME_BIT) {
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Reference in a new issue