diff mbox series

[v11,39/45] x86/sev: Use firmware-validated CPUID for SEV-SNP guests

Message ID 20220224165625.2175020-40-brijesh.singh@amd.com
State New
Headers show
Series Add AMD Secure Nested Paging (SEV-SNP) Guest Support | expand

Commit Message

Brijesh Singh Feb. 24, 2022, 4:56 p.m. UTC
From: Michael Roth <michael.roth@amd.com>

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 bootparams 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.

Also add an "sev_debug" kernel command-line parameter that will be used
(initially) to dump the CPUID table for debugging/analysis.

Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../admin-guide/kernel-parameters.txt         |  4 ++
 arch/x86/boot/compressed/sev.c                | 37 ---------------
 arch/x86/kernel/sev-shared.c                  | 37 +++++++++++++++
 arch/x86/kernel/sev.c                         | 45 +++++++++++++++++++
 4 files changed, 86 insertions(+), 37 deletions(-)

Comments

Borislav Petkov March 3, 2022, 11:51 a.m. UTC | #1
On Thu, Feb 24, 2022 at 10:56:19AM -0600, Brijesh Singh wrote:
> Also add an "sev_debug" kernel command-line parameter that will be used
> (initially) to dump the CPUID table for debugging/analysis.

No, not "sev_debug" - "sev=debug".

I'm pretty sure there will be need for other SEV-specific cmdline
options so this thing should be a set, i.e.,
	"sev=(option1,option2?,option3?,...)"

etc.

See mcheck_enable() and the comment above it for an example.
Michael Roth March 4, 2022, 12:31 a.m. UTC | #2
On Thu, Mar 03, 2022 at 12:51:20PM +0100, Borislav Petkov wrote:
> On Thu, Feb 24, 2022 at 10:56:19AM -0600, Brijesh Singh wrote:
> > Also add an "sev_debug" kernel command-line parameter that will be used
> > (initially) to dump the CPUID table for debugging/analysis.
> 
> No, not "sev_debug" - "sev=debug".
> 
> I'm pretty sure there will be need for other SEV-specific cmdline
> options so this thing should be a set, i.e.,
> 	"sev=(option1,option2?,option3?,...)"
> 
> etc.
> 
> See mcheck_enable() and the comment above it for an example.

If I do it the mce_check() way it ends up looking something like the
below, is that what you add in mind?

In that case it seems to expect "mce=option1 mce=option2" etc. I could
open-code a parser to handle multiple options like sev=option1,option2
etc., but wanted to check with you first.

Also, should I go ahead and introduce struct sev_options now, or
just use a regular bool until more options are added later?

Thanks!

struct sev_options {
       bool debug;
};

static struct sev_options sev_cmdline_opts;

...

static int __init process_sev_options(char *str)
{
       if ((*str) == '=')
               str++;

       if (!strcmp(str, "debug")) {
               sev_cmdline_opts.debug = true;
       } else {
               pr_info("SEV command-line option '%s' was not ecognized\n", str);
               return 1;
       }

       return 0;
}
__setup("sev", process_sev_options);

static int __init report_cpuid_table(void)
{
    ...
    if (sev_cmdline_opts.debug)
        dump_cpuid_table();
}
arch_initcall(report_cpuid_table)

> 
> -- 
> Regards/Gruss,
>     Boris.
> 
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpeople.kernel.org%2Ftglx%2Fnotes-about-netiquette&amp;data=04%7C01%7CMichael.Roth%40amd.com%7C98ed7057691e4faf205e08d9fd0c2768%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637819050942268665%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=SxTMowEey9CFaqlUHfWKVuEqThTEGktHAO3JgQIttRE%3D&amp;reserved=0
Borislav Petkov March 4, 2022, 7:43 a.m. UTC | #3
On Thu, Mar 03, 2022 at 06:31:57PM -0600, Michael Roth wrote:
> In that case it seems to expect "mce=option1 mce=option2" etc. I could
> open-code a parser to handle multiple options like sev=option1,option2
> etc., but wanted to check with you first.

Yap, that would make most sense - you want to be able to enable a couple
of options without excessive typing.

> Also, should I go ahead and introduce struct sev_options now, or
> just use a regular bool until more options are added later?

struct sev_config {
	__u64 debug	: 1,
	     __reserved : 63;
}

just like struct mca_config.

Thx.
diff mbox series

Patch

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index f5a27f067db9..990125cc701c 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5229,6 +5229,10 @@ 
 
 	serialnumber	[BUGS=X86-32]
 
+	sev_debug	[X86-64]
+			Enable verbose debug messages related to AMD Secure
+			Encrypted Virtualization.
+
 	shapers=	[NET]
 			Maximal number of shapers.
 
diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index 2911137bf37f..79a59027f3d8 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -381,43 +381,6 @@  static struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
 	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.
diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
index a7a1c0fb298e..2b4270d5559e 100644
--- a/arch/x86/kernel/sev-shared.c
+++ b/arch/x86/kernel/sev-shared.c
@@ -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;
+	}
+}
diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index a79ddacf0478..7bef422b428f 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -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
 
@@ -2035,6 +2036,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.
@@ -2048,3 +2051,45 @@  void __init snp_abort(void)
 {
 	sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
 }
+
+static void dump_cpuid_table(void)
+{
+	const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
+	int i = 0;
+
+	pr_info("count=%d reserved=0x%x reserved2=0x%llx\n",
+		cpuid_table->count, cpuid_table->__reserved1, cpuid_table->__reserved2);
+
+	for (i = 0; i < SNP_CPUID_COUNT_MAX; i++) {
+		const struct snp_cpuid_fn *fn = &cpuid_table->fn[i];
+
+		pr_info("index=%3d fn=0x%08x subfn=0x%08x: eax=0x%08x ebx=0x%08x ecx=0x%08x edx=0x%08x xcr0_in=0x%016llx xss_in=0x%016llx reserved=0x%016llx\n",
+			i, fn->eax_in, fn->ecx_in, fn->eax, fn->ebx, fn->ecx,
+			fn->edx, fn->xcr0_in, fn->xss_in, fn->__reserved);
+	}
+}
+
+/*
+ * 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);
+
+	if (cmdline_find_option_bool(boot_command_line, "sev_debug"))
+		dump_cpuid_table();
+
+	return 0;
+}
+
+arch_initcall(report_cpuid_table);