x86/sev: Use firmware-validated CPUID for SEV-SNP guests
SEV-SNP guests will be provided the location of special 'secrets' and 'CPUID' pages via the Confidential Computing blob. This blob is provided to the run-time kernel either through a boot_params field that was initialized by the boot/compressed kernel, or via a setup_data structure as defined by the Linux Boot Protocol. Locate the Confidential Computing blob from these sources and, if found, use the provided CPUID page/table address to create a copy that the run-time kernel will use when servicing CPUID instructions via a #VC handler. 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-40-brijesh.singh@amd.com
This commit is contained in:
parent
b190a043c4
commit
30612045e6
@ -381,43 +381,6 @@ found_cc_info:
|
||||
return cc_info;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the kernel's copy of the SNP CPUID table, and set up the
|
||||
* pointer that will be used to access it.
|
||||
*
|
||||
* Maintaining a direct mapping of the 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.
|
||||
*/
|
||||
static void setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
|
||||
{
|
||||
const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table;
|
||||
int i;
|
||||
|
||||
if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len < PAGE_SIZE)
|
||||
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID);
|
||||
|
||||
cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys;
|
||||
if (!cpuid_table_fw->count || cpuid_table_fw->count > SNP_CPUID_COUNT_MAX)
|
||||
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID);
|
||||
|
||||
cpuid_table = snp_cpuid_get_table();
|
||||
memcpy((void *)cpuid_table, cpuid_table_fw, sizeof(*cpuid_table));
|
||||
|
||||
/* Initialize CPUID ranges for range-checking. */
|
||||
for (i = 0; i < cpuid_table->count; i++) {
|
||||
const struct snp_cpuid_fn *fn = &cpuid_table->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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks
|
||||
* will verify the SNP CPUID/MSR bits.
|
||||
|
@ -964,3 +964,40 @@ static struct cc_blob_sev_info *find_cc_blob_setup_data(struct boot_params *bp)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the kernel's copy of the SNP CPUID table, and set up the
|
||||
* pointer that will be used to access it.
|
||||
*
|
||||
* Maintaining a direct mapping of the 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.
|
||||
*/
|
||||
static void __init setup_cpuid_table(const struct cc_blob_sev_info *cc_info)
|
||||
{
|
||||
const struct snp_cpuid_table *cpuid_table_fw, *cpuid_table;
|
||||
int i;
|
||||
|
||||
if (!cc_info || !cc_info->cpuid_phys || cc_info->cpuid_len < PAGE_SIZE)
|
||||
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID);
|
||||
|
||||
cpuid_table_fw = (const struct snp_cpuid_table *)cc_info->cpuid_phys;
|
||||
if (!cpuid_table_fw->count || cpuid_table_fw->count > SNP_CPUID_COUNT_MAX)
|
||||
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_CPUID);
|
||||
|
||||
cpuid_table = snp_cpuid_get_table();
|
||||
memcpy((void *)cpuid_table, cpuid_table_fw, sizeof(*cpuid_table));
|
||||
|
||||
/* Initialize CPUID ranges for range-checking. */
|
||||
for (i = 0; i < cpuid_table->count; i++) {
|
||||
const struct snp_cpuid_fn *fn = &cpuid_table->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;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/cpuid.h>
|
||||
#include <asm/cmdline.h>
|
||||
|
||||
#define DR7_RESET_VALUE 0x400
|
||||
|
||||
@ -2025,6 +2026,8 @@ bool __init snp_init(struct boot_params *bp)
|
||||
if (!cc_info)
|
||||
return false;
|
||||
|
||||
setup_cpuid_table(cc_info);
|
||||
|
||||
/*
|
||||
* The CC blob will be used later to access the secrets page. Cache
|
||||
* it here like the boot kernel does.
|
||||
@ -2038,3 +2041,24 @@ void __init snp_abort(void)
|
||||
{
|
||||
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is useful from an auditing/testing perspective to provide an easy way
|
||||
* for the guest owner to know that the CPUID table has been initialized as
|
||||
* expected, but that initialization happens too early in boot to print any
|
||||
* sort of indicator, and there's not really any other good place to do it,
|
||||
* so do it here.
|
||||
*/
|
||||
static int __init report_cpuid_table(void)
|
||||
{
|
||||
const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
|
||||
|
||||
if (!cpuid_table->count)
|
||||
return 0;
|
||||
|
||||
pr_info("Using SNP CPUID table, %d entries present.\n",
|
||||
cpuid_table->count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(report_cpuid_table);
|
||||
|
Loading…
Reference in New Issue
Block a user