Message ID | 20220128171804.569796-34-brijesh.singh@amd.com |
---|---|
State | New |
Headers | show |
Series | Add AMD Secure Nested Paging (SEV-SNP) Guest Support | expand |
On Fri, Jan 28, 2022 at 11:17:54AM -0600, Brijesh Singh wrote: > +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; > +} Merge that function into its only caller. ... > +static struct cc_blob_sev_info *snp_find_cc_blob(struct boot_params *bp) static function, no need for the "snp_" prefix. Please audit all your patches for that and remove that prefix from all static functions. > +{ > + 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. > + */ Put that comment over the function name. Thx.
On Sun, Feb 06, 2022 at 05:41:26PM +0100, Borislav Petkov wrote: > On Fri, Jan 28, 2022 at 11:17:54AM -0600, Brijesh Singh wrote: > > +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; > > +} > > Merge that function into its only caller. > > ... > > > +static struct cc_blob_sev_info *snp_find_cc_blob(struct boot_params *bp) > > static function, no need for the "snp_" prefix. Please audit all your > patches for that and remove that prefix from all static functions. > I'm a little unsure how to handle some of these others cases: We have this which is defined in sev-shared.c and used "externally" by kernel/sev.c or boot/compressed/sev.c: snp_setup_cpuid_table() I'm assuming that would be considered 'non-static' since it would need to be exported if sev-shared.c was compiled separately instead of directly #include'd. And then there's also these which are static helpers that are only used within sev-shared.c: snp_cpuid_info_get_ptr() snp_cpuid_calc_xsave_size() snp_cpuid_get_validated_func() snp_cpuid_check_range() snp_cpuid_hv() snp_cpuid_postprocess() snp_cpuid() but in those cases it seems useful to keep them grouped under the snp_cpuid_* prefix since they become ambiguous otherwise, and just using cpuid_* as a prefix (or suffix/etc) makes it unclear that they are only used for SNP and not for general CPUID handling. Should we leave those as-is?
On Tue, Feb 08, 2022 at 07:50:09AM -0600, Michael Roth wrote: > I'm assuming that would be considered 'non-static' since it would need > to be exported if sev-shared.c was compiled separately instead of > directly #include'd. No, that one can lose the prefix too. We'll cross that bridge when we get to it. > And then there's also these which are static helpers that are only used > within sev-shared.c: > > snp_cpuid_info_get_ptr() So looking at that one - and it felt weird reading that code because it said "cpuid_info" but that's not an "info" - that should be: struct snp_cpuid_table { u32 count; u32 __reserved1; u64 __reserved2; struct snp_cpuid_fn fn[SNP_CPUID_COUNT_MAX]; } __packed; just call it what it is - a SNP CPUID *table*. And then you can have const struct snp_cpuid_table *cpuid_tbl = snp_cpuid_get_table(); and that makes it crystal clear what this does. > snp_cpuid_calc_xsave_size() > snp_cpuid_get_validated_func() > > snp_cpuid_check_range() You can merge that small function into its only call site and put a comment above the code: /* Check function is within the supported CPUID leafs ranges */ > snp_cpuid_hv() > snp_cpuid_postprocess() > snp_cpuid() > > but in those cases it seems useful to keep them grouped under the > snp_cpuid_* prefix since they become ambiguous otherwise, and > just using cpuid_* as a prefix (or suffix/etc) makes it unclear > that they are only used for SNP and not for general CPUID handling. > Should we leave those as-is? Yap, the rest make sense to denote to what functionality they belong to. Thx.
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