@@ -411,6 +411,19 @@ bool snp_init(struct boot_params *bp)
if (!cc_info)
return false;
+ /*
+ * If SEV-SNP-specific Confidential Computing blob is present, then
+ * firmware/bootloader have indicated SEV-SNP support. Verifying this
+ * involves CPUID checks which will be more reliable if the SEV-SNP
+ * CPUID table is used. See comments for snp_cpuid_info_create() for
+ * more details.
+ */
+ snp_cpuid_info_create(cc_info);
+
+ /* SEV-SNP CPUID table should be set up now. */
+ if (!snp_cpuid_active())
+ sev_es_terminate(1, GHCB_TERM_CPUID);
+
/*
* 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
@@ -157,6 +157,7 @@ bool snp_init(struct boot_params *bp);
* 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) { }
static inline void sev_es_ist_exit(void) { }
@@ -65,6 +65,11 @@ static u64 sev_hv_features __ro_after_init;
static struct snp_cpuid_info cpuid_info_copy __ro_after_init;
static bool snp_cpuid_initialized __ro_after_init;
+/* Copy of the SNP firmware's CPUID page. */
+static struct snp_cpuid_info cpuid_info_copy __ro_after_init;
+
+static bool snp_cpuid_initialized __ro_after_init;
+
/*
* These will be initialized based on CPUID table so that non-present
* all-zero leaves (for sparse tables) can be differentiated from
@@ -413,6 +418,23 @@ snp_cpuid_find_validated_func(u32 func, u32 subfunc, u32 *eax, u32 *ebx,
return false;
}
+static void __init snp_cpuid_set_ranges(void)
+{
+ const struct snp_cpuid_info *cpuid_info = snp_cpuid_info_get_ptr();
+ int i;
+
+ for (i = 0; i < cpuid_info->count; i++) {
+ const struct snp_cpuid_fn *fn = &cpuid_info->fn[i];
+
+ if (fn->eax_in == 0x0)
+ cpuid_std_range_max = fn->eax;
+ else if (fn->eax_in == 0x40000000)
+ cpuid_hyp_range_max = fn->eax;
+ else if (fn->eax_in == 0x80000000)
+ cpuid_ext_range_max = fn->eax;
+ }
+}
+
static bool snp_cpuid_check_range(u32 func)
{
if (func <= cpuid_std_range_max ||
@@ -978,3 +1000,29 @@ snp_find_cc_blob_setup_data(struct boot_params *bp)
return (struct cc_blob_sev_info *)(unsigned long)sd->cc_blob_address;
}
+
+/*
+ * Initialize the kernel's copy of the SEV-SNP CPUID table, and set up the
+ * pointer that will be used to access it.
+ *
+ * Maintaining a direct mapping of the SEV-SNP CPUID table used by firmware
+ * would be possible as an alternative, but the approach is brittle since the
+ * mapping needs to be updated in sync with all the changes to virtual memory
+ * layout and related mapping facilities throughout the boot process.
+ */
+void __init snp_cpuid_info_create(const struct cc_blob_sev_info *cc_info)
+{
+ const struct snp_cpuid_info *cpuid_info_fw, *cpuid_info;
+
+ if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len < PAGE_SIZE)
+ sev_es_terminate(1, GHCB_TERM_CPUID);
+
+ cpuid_info_fw = (const struct snp_cpuid_info *)cc_info->cpuid_phys;
+ if (!cpuid_info_fw->count || cpuid_info_fw->count > SNP_CPUID_COUNT_MAX)
+ sev_es_terminate(1, GHCB_TERM_CPUID);
+
+ cpuid_info = snp_cpuid_info_get_ptr();
+ memcpy((void *)cpuid_info, cpuid_info_fw, sizeof(*cpuid_info));
+ snp_cpuid_initialized = true;
+ snp_cpuid_set_ranges();
+}