mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 17:11:33 +00:00
x86/compressed: 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-35-brijesh.singh@amd.com
This commit is contained in:
parent
8c9c509baf
commit
c01fce9cef
@ -274,6 +274,13 @@ void sev_enable(struct boot_params *bp)
|
||||
{
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
struct msr m;
|
||||
bool snp;
|
||||
|
||||
/*
|
||||
* Setup/preliminary detection of SNP. This will be sanity-checked
|
||||
* against CPUID/MSR values later.
|
||||
*/
|
||||
snp = snp_init(bp);
|
||||
|
||||
/* Check for the SME/SEV support leaf */
|
||||
eax = 0x80000000;
|
||||
@ -294,8 +301,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. */
|
||||
boot_rdmsr(MSR_AMD64_SEV, &m);
|
||||
@ -320,5 +330,105 @@ 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 *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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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 *find_cc_blob(struct boot_params *bp)
|
||||
{
|
||||
struct cc_blob_sev_info *cc_info;
|
||||
|
||||
cc_info = find_cc_blob_efi(bp);
|
||||
if (cc_info)
|
||||
goto found_cc_info;
|
||||
|
||||
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)
|
||||
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
|
||||
|
||||
return cc_info;
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks
|
||||
* will verify the SNP CPUID/MSR bits.
|
||||
*/
|
||||
bool 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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user