All of lore.kernel.org
 help / color / mirror / Atom feed
From: Borislav Petkov <bp@alien8.de>
To: Brijesh Singh <brijesh.singh@amd.com>
Cc: x86@kernel.org, linux-kernel@vger.kernel.org,
	kvm@vger.kernel.org, linux-efi@vger.kernel.org,
	platform-driver-x86@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-mm@kvack.org, Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Joerg Roedel <jroedel@suse.de>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Ard Biesheuvel <ardb@kernel.org>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>,
	Vitaly Kuznetsov <vkuznets@redhat.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Jim Mattson <jmattson@google.com>,
	Andy Lutomirski <luto@kernel.org>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	Sergio Lopez <slp@redhat.com>, Peter Gonda <pgonda@google.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>,
	David Rientjes <rientjes@google.com>,
	Dov Murik <dovmurik@linux.ibm.com>,
	Tobin Feldman-Fitzthum <tobin@ibm.com>,
	Michael Roth <michael.roth@amd.com>,
	Vlastimil Babka <vbabka@suse.cz>,
	"Kirill A . Shutemov" <kirill@shutemov.name>,
	Andi Kleen <ak@linux.intel.com>,
	tony.luck@intel.com, marcorr@google.com,
	sathyanarayanan.kuppuswamy@linux.intel.com
Subject: Re: [PATCH Part1 v5 28/38] x86/compressed/64: enable SEV-SNP-validated CPUID in #VC handler
Date: Wed, 25 Aug 2021 21:19:18 +0200	[thread overview]
Message-ID: <YSaXtpKT+iE7dxYq@zn.tnic> (raw)
In-Reply-To: <20210820151933.22401-29-brijesh.singh@amd.com>

On Fri, Aug 20, 2021 at 10:19:23AM -0500, Brijesh Singh wrote:
> From: Michael Roth <michael.roth@amd.com>
> 
> CPUID instructions generate a #VC exception for SEV-ES/SEV-SNP guests,
> for which early handlers are currently set up to handle. In the case
> of SEV-SNP, guests can use a special location in guest memory address
> space that has been pre-populated with firmware-validated CPUID
> information to look up the relevant CPUID values rather than
> requesting them from hypervisor via a VMGEXIT.
> 
> Determine the location of the CPUID memory address in advance of any
> CPUID instructions/exceptions and, when available, use it to handle
> the CPUID lookup.
> 
> Signed-off-by: Michael Roth <michael.roth@amd.com>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  arch/x86/boot/compressed/efi.c     |   1 +
>  arch/x86/boot/compressed/head_64.S |   1 +
>  arch/x86/boot/compressed/idt_64.c  |   7 +-
>  arch/x86/boot/compressed/misc.h    |   1 +
>  arch/x86/boot/compressed/sev.c     |   3 +
>  arch/x86/include/asm/sev-common.h  |   2 +
>  arch/x86/include/asm/sev.h         |   3 +
>  arch/x86/kernel/sev-shared.c       | 374 +++++++++++++++++++++++++++++
>  arch/x86/kernel/sev.c              |   4 +
>  9 files changed, 394 insertions(+), 2 deletions(-)

Another huuge patch. I wonder if it can be split...

> diff --git a/arch/x86/boot/compressed/efi.c b/arch/x86/boot/compressed/efi.c
> index 16ff5cb9a1fb..a1529a230ea7 100644
> --- a/arch/x86/boot/compressed/efi.c
> +++ b/arch/x86/boot/compressed/efi.c
> @@ -176,3 +176,4 @@ efi_get_conf_table(struct boot_params *boot_params,
>  
>  	return 0;
>  }
> +

Applying: x86/compressed/64: Enable SEV-SNP-validated CPUID in #VC handler
.git/rebase-apply/patch:21: new blank line at EOF.
+
warning: 1 line adds whitespace errors.

That looks like a stray hunk which doesn't belong.

> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index a2347ded77ea..1c1658693fc9 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -441,6 +441,7 @@ SYM_CODE_START(startup_64)
>  .Lon_kernel_cs:
>  
>  	pushq	%rsi
> +	movq	%rsi, %rdi		/* real mode address */
>  	call	load_stage1_idt
>  	popq	%rsi
>  
> diff --git a/arch/x86/boot/compressed/idt_64.c b/arch/x86/boot/compressed/idt_64.c
> index 9b93567d663a..1f6511a6625d 100644
> --- a/arch/x86/boot/compressed/idt_64.c
> +++ b/arch/x86/boot/compressed/idt_64.c
> @@ -3,6 +3,7 @@
>  #include <asm/segment.h>
>  #include <asm/trapnr.h>
>  #include "misc.h"
> +#include <asm/sev.h>

asm/ namespaced headers should go together, before the private ones,
i.e., above the misc.h line.

>  static void set_idt_entry(int vector, void (*handler)(void))
>  {
> @@ -28,13 +29,15 @@ static void load_boot_idt(const struct desc_ptr *dtr)
>  }
>  
>  /* Setup IDT before kernel jumping to  .Lrelocated */
> -void load_stage1_idt(void)
> +void load_stage1_idt(void *rmode)
>  {
>  	boot_idt_desc.address = (unsigned long)boot_idt;
>  
>  
> -	if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))
> +	if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
> +		sev_snp_cpuid_init(rmode);
>  		set_idt_entry(X86_TRAP_VC, boot_stage1_vc);
> +	}
>  
>  	load_boot_idt(&boot_idt_desc);
>  }
> diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
> index 16b092fd7aa1..cdd328aa42c2 100644
> --- a/arch/x86/boot/compressed/misc.h
> +++ b/arch/x86/boot/compressed/misc.h
> @@ -190,6 +190,7 @@ int efi_get_conf_table(struct boot_params *boot_params,
>  		       unsigned long *conf_table_pa,
>  		       unsigned int *conf_table_len,
>  		       bool *is_efi_64);
> +

Another stray hunk.

>  #else
>  static inline int
>  efi_find_vendor_table(unsigned long conf_table_pa, unsigned int conf_table_len,
> diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
> index 6e8d97c280aa..910bf5cf010e 100644
> --- a/arch/x86/boot/compressed/sev.c
> +++ b/arch/x86/boot/compressed/sev.c
> @@ -20,6 +20,9 @@
>  #include <asm/fpu/xcr.h>
>  #include <asm/ptrace.h>
>  #include <asm/svm.h>
> +#include <asm/cpuid.h>
> +#include <linux/efi.h>
> +#include <linux/log2.h>

What are those includes for?

Polluting the decompressor namespace with kernel proper defines is a
real pain to untangle as it is. What do you need those for and can you
do it without them?

>  #include "error.h"
>  
> diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
> index 072540dfb129..5f134c172dbf 100644
> --- a/arch/x86/include/asm/sev-common.h
> +++ b/arch/x86/include/asm/sev-common.h
> @@ -148,6 +148,8 @@ struct snp_psc_desc {
>  #define GHCB_TERM_PSC			1	/* Page State Change failure */
>  #define GHCB_TERM_PVALIDATE		2	/* Pvalidate failure */
>  #define GHCB_TERM_NOT_VMPL0		3	/* SNP guest is not running at VMPL-0 */
> +#define GHCB_TERM_CPUID			4	/* CPUID-validation failure */
> +#define GHCB_TERM_CPUID_HV		5	/* CPUID failure during hypervisor fallback */
>  
>  #define GHCB_RESP_CODE(v)		((v) & GHCB_MSR_INFO_MASK)
>  
> diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
> index 534fa1c4c881..c73931548346 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
> @@ -126,6 +127,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);
> +void sev_snp_cpuid_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) { }
> @@ -141,6 +143,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 void sev_snp_cpuid_init(struct boot_params *bp) { }
>  #endif
>  
>  #endif
> diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
> index ae4556925485..651980ddbd65 100644
> --- a/arch/x86/kernel/sev-shared.c
> +++ b/arch/x86/kernel/sev-shared.c
> @@ -14,6 +14,25 @@
>  #define has_cpuflag(f)	boot_cpu_has(f)
>  #endif
>  
> +struct sev_snp_cpuid_fn {
> +	u32 eax_in;
> +	u32 ecx_in;
> +	u64 unused;
> +	u64 unused2;

What are those for? Padding? Or are they spec-ed somewhere and left for
future use?

Seeing how the struct is __packed, they probably are part of a spec
definition somewhere.

Link pls.

> +	u32 eax;
> +	u32 ebx;
> +	u32 ecx;
> +	u32 edx;
> +	u64 reserved;

Ditto.

Please prefix all those unused/reserved members with "__".

> +} __packed;
> +
> +struct sev_snp_cpuid_info {
> +	u32 count;
> +	u32 reserved1;
> +	u64 reserved2;

Ditto.

> +	struct sev_snp_cpuid_fn fn[0];
> +} __packed;
> +
>  /*
>   * Since feature negotiation related variables are set early in the boot
>   * process they must reside in the .data section so as not to be zeroed
> @@ -26,6 +45,15 @@ static u16 __ro_after_init ghcb_version;
>  /* Bitmap of SEV features supported by the hypervisor */
>  u64 __ro_after_init sev_hv_features = 0;
>  
> +/*
> + * These are also stored in .data section to avoid the need to re-parse
> + * boot_params and re-determine CPUID memory range when .bss is cleared.
> + */
> +static int sev_snp_cpuid_enabled __section(".data");

That will become part of prot_guest_has() or cc_platform_has() or
whatever its name is going to be.

> +static unsigned long sev_snp_cpuid_pa __section(".data");
> +static unsigned long sev_snp_cpuid_sz __section(".data");
> +static const struct sev_snp_cpuid_info *cpuid_info __section(".data");

All those: __ro_after_init?

Also, just like the ones above have a short comment explaining what they
are, add such comments for those too pls and perhaps what they're used
for.

> +
>  static bool __init sev_es_check_cpu_features(void)
>  {
>  	if (!has_cpuflag(X86_FEATURE_RDRAND)) {
> @@ -236,6 +264,219 @@ static int sev_cpuid_hv(u32 func, u32 subfunc, u32 *eax, u32 *ebx,
>  	return 0;
>  }
>  
> +static bool sev_snp_cpuid_active(void)
> +{
> +	return sev_snp_cpuid_enabled;
> +}

That too will become part of prot_guest_has() or cc_platform_has() or
whatever its name is going to be.

> +
> +static int sev_snp_cpuid_xsave_size(u64 xfeatures_en, u32 base_size,
> +				    u32 *xsave_size, bool compacted)

Function name needs a verb. Please audit all your patches.

> +{
> +	u64 xfeatures_found = 0;
> +	int i;
> +
> +	*xsave_size = base_size;

Set that xsave_size only...
> +
> +	for (i = 0; i < cpuid_info->count; i++) {
> +		const struct sev_snp_cpuid_fn *fn = &cpuid_info->fn[i];
> +
> +		if (!(fn->eax_in == 0xd && fn->ecx_in > 1 && fn->ecx_in < 64))
> +			continue;
> +		if (!(xfeatures_en & (1UL << fn->ecx_in)))
> +			continue;
> +		if (xfeatures_found & (1UL << fn->ecx_in))
> +			continue;
> +
> +		xfeatures_found |= (1UL << fn->ecx_in);

For all use BIT_ULL().

> +		if (compacted)
> +			*xsave_size += fn->eax;
> +		else
> +			*xsave_size = max(*xsave_size, fn->eax + fn->ebx);

... not here ...

> +	}
> +
> +	/*
> +	 * Either the guest set unsupported XCR0/XSS bits, or the corresponding
> +	 * entries in the CPUID table were not present. This is not a valid
> +	 * state to be in.
> +	 */
> +	if (xfeatures_found != (xfeatures_en & ~3ULL))
> +		return -EINVAL;

... but here when you're not going to return an error because callers
will see that value change temporarily which is not clean.

Also, you need to set it once - not during each loop iteration.

> +
> +	return 0;
> +}
> +
> +static void sev_snp_cpuid_hv(u32 func, u32 subfunc, u32 *eax, u32 *ebx,
> +			     u32 *ecx, u32 *edx)
> +{
> +	/*
> +	 * Currently MSR protocol is sufficient to handle fallback cases, but
> +	 * should that change make sure we terminate rather than grabbing random

Fix the "we"s please. Please audit all your patches.

> +	 * values. Handling can be added in future to use GHCB-page protocol for
> +	 * cases that occur late enough in boot that GHCB page is available

End comment sentences with a fullstop. Please audit all your patches.

> +	 */

Also, put that comment over the function.

> +	if (cpuid_function_is_indexed(func) && subfunc != 0)

In all your patches:

s/ != 0//g

> +		sev_es_terminate(1, GHCB_TERM_CPUID_HV);
> +
> +	if (sev_cpuid_hv(func, 0, eax, ebx, ecx, edx))
> +		sev_es_terminate(1, GHCB_TERM_CPUID_HV);
> +}
> +
> +static bool sev_snp_cpuid_find(u32 func, u32 subfunc, u32 *eax, u32 *ebx,

I guess

	find_validated_cpuid_func()

or so to denote where it picks it out from.

> +			       u32 *ecx, u32 *edx)
> +{
> +	int i;
> +	bool found = false;

The tip-tree preferred ordering of variable declarations at the
beginning of a function is reverse fir tree order::

	struct long_struct_name *descriptive_name;
	unsigned long foo, bar;
	unsigned int tmp;
	int ret;

The above is faster to parse than the reverse ordering::

	int ret;
	unsigned int tmp;
	unsigned long foo, bar;
	struct long_struct_name *descriptive_name;

And even more so than random ordering::

	unsigned long foo, bar;
	int ret;
	struct long_struct_name *descriptive_name;
	unsigned int tmp;

Audit all your patches pls.

> +
> +	for (i = 0; i < cpuid_info->count; i++) {
> +		const struct sev_snp_cpuid_fn *fn = &cpuid_info->fn[i];
> +
> +		if (fn->eax_in != func)
> +			continue;
> +
> +		if (cpuid_function_is_indexed(func) && fn->ecx_in != subfunc)
> +			continue;
> +
> +		*eax = fn->eax;
> +		*ebx = fn->ebx;
> +		*ecx = fn->ecx;
> +		*edx = fn->edx;
> +		found = true;
> +
> +		break;

That's just silly. Simply:

		return true;


> +	}
> +
> +	return found;

	return false;

here and the "found" variable can go.

> +}
> +
> +static bool sev_snp_cpuid_in_range(u32 func)
> +{
> +	int i;
> +	u32 std_range_min = 0;
> +	u32 std_range_max = 0;
> +	u32 hyp_range_min = 0x40000000;
> +	u32 hyp_range_max = 0;
> +	u32 ext_range_min = 0x80000000;
> +	u32 ext_range_max = 0;
> +
> +	for (i = 0; i < cpuid_info->count; i++) {
> +		const struct sev_snp_cpuid_fn *fn = &cpuid_info->fn[i];
> +
> +		if (fn->eax_in == std_range_min)
> +			std_range_max = fn->eax;
> +		else if (fn->eax_in == hyp_range_min)
> +			hyp_range_max = fn->eax;
> +		else if (fn->eax_in == ext_range_min)
> +			ext_range_max = fn->eax;
> +	}

So this loop which determines those ranges will run each time
sev_snp_cpuid_find() doesn't find @func among the validated CPUID leafs.

Why don't you do that determination once at init...

> +
> +	if ((func >= std_range_min && func <= std_range_max) ||
> +	    (func >= hyp_range_min && func <= hyp_range_max) ||
> +	    (func >= ext_range_min && func <= ext_range_max))

... so that this function becomes only this check?

This is unnecessary work as it is.

> +		return true;
> +
> +	return false;
> +}
> +
> +/*
> + * Returns -EOPNOTSUPP if feature not enabled. Any other return value should be
> + * treated as fatal by caller since we cannot fall back to hypervisor to fetch
> + * the values for security reasons (outside of the specific cases handled here)
> + */
> +static int sev_snp_cpuid(u32 func, u32 subfunc, u32 *eax, u32 *ebx, u32 *ecx,
> +			 u32 *edx)
> +{
> +	if (!sev_snp_cpuid_active())
> +		return -EOPNOTSUPP;
> +
> +	if (!cpuid_info)
> +		return -EIO;
> +
> +	if (!sev_snp_cpuid_find(func, subfunc, eax, ebx, ecx, edx)) {
> +		/*
> +		 * Some hypervisors will avoid keeping track of CPUID entries
> +		 * where all values are zero, since they can be handled the
> +		 * same as out-of-range values (all-zero). In our case, we want
> +		 * to be able to distinguish between out-of-range entries and
> +		 * in-range zero entries, since the CPUID table entries are
> +		 * only a template that may need to be augmented with
> +		 * additional values for things like CPU-specific information.
> +		 * So if it's not in the table, but is still in the valid
> +		 * range, proceed with the fix-ups below. Otherwise, just return
> +		 * zeros.
> +		 */
> +		*eax = *ebx = *ecx = *edx = 0;
> +		if (!sev_snp_cpuid_in_range(func))
> +			goto out;

That label is not needed.

> +	}

All that from here on looks like it should go into a separate function
called

snp_cpuid_postprocess()

where you can do a switch-case on func and have it nice, readable and
extensible there, in case more functions get added.

> +	if (func == 0x1) {
> +		u32 ebx2, edx2;
> +
> +		sev_snp_cpuid_hv(func, subfunc, NULL, &ebx2, NULL, &edx2);
> +		/* initial APIC ID */
> +		*ebx = (*ebx & 0x00FFFFFF) | (ebx2 & 0xFF000000);

For all hex masks: use GENMASK_ULL.

> +		/* APIC enabled bit */
> +		*edx = (*edx & ~BIT_ULL(9)) | (edx2 & BIT_ULL(9));
> +
> +		/* OSXSAVE enabled bit */
> +		if (native_read_cr4() & X86_CR4_OSXSAVE)
> +			*ecx |= BIT_ULL(27);
> +	} else if (func == 0x7) {
> +		/* OSPKE enabled bit */
> +		*ecx &= ~BIT_ULL(4);
> +		if (native_read_cr4() & X86_CR4_PKE)
> +			*ecx |= BIT_ULL(4);
> +	} else if (func == 0xB) {
> +		/* extended APIC ID */
> +		sev_snp_cpuid_hv(func, 0, NULL, NULL, NULL, edx);
> +	} else if (func == 0xd && (subfunc == 0x0 || subfunc == 0x1)) {
> +		bool compacted = false;
> +		u64 xcr0 = 1, xss = 0;
> +		u32 xsave_size;
> +
> +		if (native_read_cr4() & X86_CR4_OSXSAVE)
> +			xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
> +		if (subfunc == 1) {
> +			/* boot/compressed doesn't set XSS so 0 is fine there */
> +#ifndef __BOOT_COMPRESSED
> +			if (*eax & 0x8) /* XSAVES */
> +				if (boot_cpu_has(X86_FEATURE_XSAVES))

cpu_feature_enabled()

> +					rdmsrl(MSR_IA32_XSS, xss);
> +#endif
> +			/*
> +			 * The PPR and APM aren't clear on what size should be
> +			 * encoded in 0xD:0x1:EBX when compaction is not enabled
> +			 * by either XSAVEC or XSAVES since SNP-capable hardware
> +			 * has the entries fixed as 1. KVM sets it to 0 in this
> +			 * case, but to avoid this becoming an issue it's safer
> +			 * to simply treat this as unsupported or SNP guests.
> +			 */
> +			if (!(*eax & 0xA)) /* (XSAVEC|XSAVES) */

Please put side comments over the line they comment.

> +				return -EINVAL;
> +
> +			compacted = true;
> +		}
> +
> +		if (sev_snp_cpuid_xsave_size(xcr0 | xss, *ebx, &xsave_size,
> +					     compacted))

No need for that linebreak.

> +			return -EINVAL;
> +
> +		*ebx = xsave_size;
> +	} else if (func == 0x8000001E) {
> +		u32 ebx2, ecx2;
> +
> +		/* extended APIC ID */
> +		sev_snp_cpuid_hv(func, subfunc, eax, &ebx2, &ecx2, NULL);
> +		/* compute ID */
> +		*ebx = (*ebx & 0xFFFFFFF00) | (ebx2 & 0x000000FF);
> +		/* node ID */
> +		*ecx = (*ecx & 0xFFFFFFF00) | (ecx2 & 0x000000FF);
> +	}
> +
> +out:
> +	return 0;
> +}
> +
>  /*
>   * Boot VC Handler - This is the first VC handler during boot, there is no GHCB
>   * page yet, so it only supports the MSR based communication with the

Is that comment...

> @@ -244,15 +485,25 @@ static int sev_cpuid_hv(u32 func, u32 subfunc, u32 *eax, u32 *ebx,
>  void __init do_vc_no_ghcb(struct pt_regs *regs, unsigned long exit_code)
>  {
>  	unsigned int fn = lower_bits(regs->ax, 32);
> +	unsigned int subfn = lower_bits(regs->cx, 32);
>  	u32 eax, ebx, ecx, edx;
> +	int ret;
>  
>  	/* Only CPUID is supported via MSR protocol */

... and that still valid?

>  	if (exit_code != SVM_EXIT_CPUID)
>  		goto fail;
>  
> +	ret = sev_snp_cpuid(fn, subfn, &eax, &ebx, &ecx, &edx);
> +	if (ret == 0)
> +		goto out;

I think you mean here "goto cpuid_done;" or so.

> +
> +	if (ret != -EOPNOTSUPP)
> +		goto fail;
> +
>  	if (sev_cpuid_hv(fn, 0, &eax, &ebx, &ecx, &edx))
>  		goto fail;
>  
> +out:
>  	regs->ax = eax;
>  	regs->bx = ebx;
>  	regs->cx = ecx;
> @@ -552,6 +803,19 @@ static enum es_result vc_handle_cpuid(struct ghcb *ghcb,
>  	struct pt_regs *regs = ctxt->regs;
>  	u32 cr4 = native_read_cr4();
>  	enum es_result ret;
> +	u32 eax, ebx, ecx, edx;
> +	int cpuid_ret;
> +
> +	cpuid_ret = sev_snp_cpuid(regs->ax, regs->cx, &eax, &ebx, &ecx, &edx);
> +	if (cpuid_ret == 0) {
> +		regs->ax = eax;
> +		regs->bx = ebx;
> +		regs->cx = ecx;
> +		regs->dx = edx;
> +		return ES_OK;
> +	}
> +	if (cpuid_ret != -EOPNOTSUPP)
> +		return ES_VMM_ERROR;

I don't like this thing slapped inside the function. Pls put it in a separate 

vc_handle_cpuid_snp()

which is called by vc_handle_cpuid() instead.

>  
>  	ghcb_set_rax(ghcb, regs->ax);
>  	ghcb_set_rcx(ghcb, regs->cx);
> @@ -603,3 +867,113 @@ static enum es_result vc_handle_rdtsc(struct ghcb *ghcb,
>  
>  	return ES_OK;
>  }
> +
> +#ifdef BOOT_COMPRESSED
> +static struct 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 hdr;
> +		hdr = (struct setup_data *)hdr->next;
> +	}
> +
> +	return NULL;
> +}
> +
> +/*
> + * For boot/compressed kernel:
> + *
> + *   1) Search for CC blob in the following order/precedence:
> + *      - via linux boot protocol / setup_data entry
> + *      - via EFI configuration table
> + *   2) Return a pointer to the CC blob, NULL otherwise.
> + */
> +static struct cc_blob_sev_info *sev_snp_probe_cc_blob(struct boot_params *bp)

snp_find_cc_blob() simply.

> +{
> +	struct cc_blob_sev_info *cc_info = NULL;
> +	struct setup_data_cc {
> +		struct setup_data header;
> +		u32 cc_blob_address;
> +	} *sd;

Define that struct above the function and call it "cc_setup_data" like
the rest of the stuff which deals with that.

> +	unsigned long conf_table_pa;
> +	unsigned int conf_table_len;
> +	bool efi_64;
> +
> +	/* Try to get CC blob via setup_data */
> +	sd = (struct setup_data_cc *)get_cc_setup_data(bp);
> +	if (sd) {
> +		cc_info = (struct cc_blob_sev_info *)(unsigned long)sd->cc_blob_address;
> +		goto out_verify;
> +	}
> +
> +	/* CC blob isn't in setup_data, see if it's in the EFI config table */
> +	if (!efi_get_conf_table(bp, &conf_table_pa, &conf_table_len, &efi_64))
> +		(void)efi_find_vendor_table(conf_table_pa, conf_table_len,
> +					    EFI_CC_BLOB_GUID, efi_64,
> +					    (unsigned long *)&cc_info);

Yah, check that retval pls with a proper ret variable. No need to cram
it all together.

> +
> +out_verify:
> +	/* CC blob should be either valid or not present. Fail otherwise. */
> +	if (cc_info && cc_info->magic != CC_BLOB_SEV_HDR_MAGIC)
> +		sev_es_terminate(1, GHCB_SNP_UNSUPPORTED);
> +
> +	return cc_info;
> +}
> +#else
> +/*
> + * Probing for CC blob for run-time kernel will be enabled in a subsequent
> + * patch. For now we need to stub this out.
> + */
> +static struct cc_blob_sev_info *sev_snp_probe_cc_blob(struct boot_params *bp)
> +{
> +	return NULL;
> +}
> +#endif
> +
> +/*
> + * Initial set up of CPUID table when running identity-mapped.
> + *
> + * NOTE: Since SEV_SNP feature partly relies on CPUID checks that can't
> + * happen until we access CPUID page, we skip the check and hope the
> + * bootloader is providing sane values.

So I don't like the sound of that even one bit. We shouldn't hope
anything here...

> Current code relies on all CPUID
> + * page lookups originating from #VC handler, which at least provides
> + * indication that SEV-ES is enabled. Subsequent init levels will check for
> + * SEV_SNP feature once available to also take SEV MSR value into account.
> + */
> +void sev_snp_cpuid_init(struct boot_params *bp)

snp_cpuid_init()

In general, prefix all SNP-specific variables, structs, functions, etc
with "snp_" simply.

> +{
> +	struct cc_blob_sev_info *cc_info;
> +
> +	if (!bp)
> +		sev_es_terminate(1, GHCB_TERM_CPUID);
> +
> +	cc_info = sev_snp_probe_cc_blob(bp);
> +

^ Superfluous newline.

> +	if (!cc_info)
> +		return;
> +
> +	sev_snp_cpuid_pa = cc_info->cpuid_phys;
> +	sev_snp_cpuid_sz = cc_info->cpuid_len;

You can do those assignments ...

> +
> +	/*
> +	 * These should always be valid values for SNP, even if guest isn't
> +	 * actually configured to use the CPUID table.
> +	 */
> +	if (!sev_snp_cpuid_pa || sev_snp_cpuid_sz < PAGE_SIZE)
> +		sev_es_terminate(1, GHCB_TERM_CPUID);


... here, after you've verified them.

> +
> +	cpuid_info = (const struct sev_snp_cpuid_info *)sev_snp_cpuid_pa;
> +
> +	/*
> +	 * We should be able to trust the 'count' value in the CPUID table
> +	 * area, but ensure it agrees with CC blob value to be safe.
> +	 */
> +	if (sev_snp_cpuid_sz < (sizeof(struct sev_snp_cpuid_info) +
> +				sizeof(struct sev_snp_cpuid_fn) *
> +				cpuid_info->count))

Yah, this is the type of paranoia I'm talking about!

> +		sev_es_terminate(1, GHCB_TERM_CPUID);
> +
> +	sev_snp_cpuid_enabled = 1;
> +}
> diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
> index ddf8ced4a879..d7b6f7420551 100644
> --- a/arch/x86/kernel/sev.c
> +++ b/arch/x86/kernel/sev.c
> @@ -19,6 +19,8 @@
>  #include <linux/kernel.h>
>  #include <linux/mm.h>
>  #include <linux/cpumask.h>
> +#include <linux/log2.h>
> +#include <linux/efi.h>
>  
>  #include <asm/cpu_entry_area.h>
>  #include <asm/stacktrace.h>
> @@ -32,6 +34,8 @@
>  #include <asm/smp.h>
>  #include <asm/cpu.h>
>  #include <asm/apic.h>
> +#include <asm/efi.h>
> +#include <asm/cpuid.h>
>  
>  #include "sev-internal.h"

What are those includes for?

Looks like a leftover...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

  reply	other threads:[~2021-08-25 19:18 UTC|newest]

Thread overview: 126+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-20 15:18 [PATCH Part1 v5 00/38] Add AMD Secure Nested Paging (SEV-SNP) Guest Support Brijesh Singh
2021-08-20 15:18 ` [PATCH Part1 v5 01/38] x86/mm: Add sev_feature_enabled() helper Brijesh Singh
2021-08-20 15:18 ` [PATCH Part1 v5 02/38] x86/sev: Shorten GHCB terminate macro names Brijesh Singh
2021-08-20 15:18 ` [PATCH Part1 v5 03/38] x86/sev: Get rid of excessive use of defines Brijesh Singh
2021-08-20 15:18 ` [PATCH Part1 v5 04/38] x86/head64: Carve out the guest encryption postprocessing into a helper Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 05/38] x86/sev: Define the Linux specific guest termination reasons Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 06/38] x86/sev: Save the negotiated GHCB version Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 07/38] x86/sev: Add support for hypervisor feature VMGEXIT Brijesh Singh
2021-08-23  9:47   ` Borislav Petkov
2021-08-23 18:25     ` Brijesh Singh
2021-08-23 18:34       ` Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 08/38] x86/sev: Check SEV-SNP features support Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 09/38] x86/sev: Add a helper for the PVALIDATE instruction Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 10/38] x86/sev: Check the vmpl level Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 11/38] x86/compressed: Add helper for validating pages in the decompression stage Brijesh Singh
2021-08-23 14:16   ` Borislav Petkov
2021-08-23 18:55     ` Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 12/38] x86/compressed: Register GHCB memory when SEV-SNP is active Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 13/38] x86/sev: " Brijesh Singh
2021-08-23 17:35   ` Borislav Petkov
2021-08-23 18:56     ` Brijesh Singh
2021-08-23 19:45       ` [PATCH] x86/sev: Remove do_early_exception() forward declarations Borislav Petkov
2021-08-23 20:06         ` Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 14/38] x86/sev: Add helper for validating pages in early enc attribute changes Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 15/38] x86/kernel: Make the bss.decrypted section shared in RMP table Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 16/38] x86/kernel: Validate rom memory before accessing when SEV-SNP is active Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 17/38] x86/mm: Add support to validate memory when changing C-bit Brijesh Singh
2021-08-25 11:06   ` Borislav Petkov
2021-08-25 13:54     ` Brijesh Singh
2021-08-25 14:00       ` Borislav Petkov
2021-08-27 17:09   ` Borislav Petkov
2021-08-20 15:19 ` [PATCH Part1 v5 18/38] KVM: SVM: Define sev_features and vmpl field in the VMSA Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 19/38] KVM: SVM: Create a separate mapping for the SEV-ES save area Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 20/38] KVM: SVM: Create a separate mapping for the GHCB " Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 21/38] KVM: SVM: Update the SEV-ES save area mapping Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 22/38] x86/sev: Use SEV-SNP AP creation to start secondary CPUs Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 23/38] x86/head/64: set up a startup %gs for stack protector Brijesh Singh
2021-08-25 14:29   ` Borislav Petkov
2021-08-25 15:18     ` Michael Roth
2021-08-25 16:29       ` Borislav Petkov
2021-08-27 13:38         ` Michael Roth
2021-08-31  8:03           ` Borislav Petkov
2021-08-31 23:30             ` Michael Roth
2021-08-25 15:07   ` Joerg Roedel
2021-08-25 17:07     ` Michael Roth
2021-08-20 15:19 ` [PATCH Part1 v5 24/38] x86/sev: move MSR-based VMGEXITs for CPUID to helper Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 25/38] KVM: x86: move lookup of indexed CPUID leafs " Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 26/38] x86/compressed/acpi: move EFI config table access to common code Brijesh Singh
2021-08-25 15:18   ` Borislav Petkov
2021-08-25 17:14     ` Michael Roth
2021-08-20 15:19 ` [PATCH Part1 v5 27/38] x86/boot: Add Confidential Computing type to setup_data Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 28/38] x86/compressed/64: enable SEV-SNP-validated CPUID in #VC handler Brijesh Singh
2021-08-25 19:19   ` Borislav Petkov [this message]
2021-08-27 16:46     ` Michael Roth
2021-08-31 10:04       ` Borislav Petkov
2021-09-01  1:03         ` Michael Roth
2021-09-02 10:53           ` Borislav Petkov
2021-08-20 15:19 ` [PATCH Part1 v5 29/38] x86/boot: add a pointer to Confidential Computing blob in bootparams Brijesh Singh
2021-08-27 13:51   ` Borislav Petkov
2021-08-27 18:48     ` Michael Roth
2021-08-20 15:19 ` [PATCH Part1 v5 30/38] x86/compressed/64: store Confidential Computing blob address " Brijesh Singh
2021-08-27 14:15   ` Borislav Petkov
2021-08-27 19:09     ` Michael Roth
2021-08-31 10:26       ` Borislav Petkov
2021-08-20 15:19 ` [PATCH Part1 v5 31/38] x86/compressed/64: add identity mapping for Confidential Computing blob Brijesh Singh
2021-08-27 14:43   ` Borislav Petkov
2021-08-20 15:19 ` [PATCH Part1 v5 32/38] x86/sev: enable SEV-SNP-validated CPUID in #VC handlers Brijesh Singh
2021-08-27 15:18   ` Borislav Petkov
2021-08-27 15:47     ` Brijesh Singh
2021-08-27 16:56       ` Borislav Petkov
2021-08-27 18:39       ` Michael Roth
2021-08-27 18:32     ` Michael Roth
2021-08-30 16:03       ` Michael Roth
2021-08-31 16:22       ` Borislav Petkov
2021-09-01  1:16         ` Michael Roth
2021-09-02 11:05           ` Borislav Petkov
2021-08-20 15:19 ` [PATCH Part1 v5 33/38] x86/sev: Provide support for SNP guest request NAEs Brijesh Singh
2021-08-27 17:44   ` Borislav Petkov
2021-08-27 18:07     ` Brijesh Singh
2021-08-27 18:13       ` Borislav Petkov
2021-08-27 18:27         ` Brijesh Singh
2021-08-27 18:38           ` Borislav Petkov
2021-08-27 19:57       ` Tom Lendacky
2021-08-27 20:17         ` Borislav Petkov
2021-08-27 20:31           ` Tom Lendacky
2021-08-20 15:19 ` [PATCH Part1 v5 34/38] x86/sev: Add snp_msg_seqno() helper Brijesh Singh
2021-08-27 18:41   ` Borislav Petkov
2021-08-30 15:07     ` Brijesh Singh
2021-09-02 11:26       ` Borislav Petkov
2021-09-02 15:27         ` Brijesh Singh
2021-08-31 20:46   ` Dov Murik
2021-08-31 21:13     ` Brijesh Singh
2021-09-09 14:54   ` Peter Gonda
2021-09-09 14:54     ` Peter Gonda
2021-09-09 15:26     ` Brijesh Singh
2021-09-09 15:43       ` Peter Gonda
2021-09-09 15:43         ` Peter Gonda
2021-09-09 16:17         ` Brijesh Singh
2021-09-09 16:21           ` Peter Gonda
2021-09-09 16:21             ` Peter Gonda
2021-09-09 19:26             ` Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 35/38] x86/sev: Register SNP guest request platform device Brijesh Singh
2021-08-31 11:37   ` Dov Murik
2021-08-31 16:03     ` Brijesh Singh
2021-09-02 16:40   ` Borislav Petkov
2021-09-02 19:58     ` Brijesh Singh
2021-09-03  8:15       ` Dov Murik
2021-09-03 12:08         ` Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 36/38] virt: Add SEV-SNP guest driver Brijesh Singh
2021-09-06 17:38   ` Borislav Petkov
2021-09-07 13:35     ` Brijesh Singh
2021-09-08 13:44       ` Borislav Petkov
2021-08-20 15:19 ` [PATCH Part1 v5 37/38] virt: sevguest: Add support to derive key Brijesh Singh
2021-08-31 18:59   ` Dov Murik
2021-08-31 21:04     ` Brijesh Singh
2021-09-01  5:33       ` Dov Murik
2021-09-08 14:00   ` Borislav Petkov
2021-09-08 21:44     ` Brijesh Singh
2021-08-20 15:19 ` [PATCH Part1 v5 38/38] virt: sevguest: Add support to get extended report Brijesh Singh
2021-08-31 20:22   ` Dov Murik
2021-08-31 21:11     ` Brijesh Singh
2021-09-01  8:32       ` Dov Murik
2021-09-08 17:53   ` Borislav Petkov
2021-09-15 11:46     ` Brijesh Singh
2021-09-15 10:02   ` Dr. David Alan Gilbert
2021-09-15 11:53     ` Brijesh Singh

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YSaXtpKT+iE7dxYq@zn.tnic \
    --to=bp@alien8.de \
    --cc=ak@linux.intel.com \
    --cc=ardb@kernel.org \
    --cc=brijesh.singh@amd.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=dovmurik@linux.ibm.com \
    --cc=hpa@zytor.com \
    --cc=jmattson@google.com \
    --cc=jroedel@suse.de \
    --cc=kirill@shutemov.name \
    --cc=kvm@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=luto@kernel.org \
    --cc=marcorr@google.com \
    --cc=michael.roth@amd.com \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=pgonda@google.com \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=rientjes@google.com \
    --cc=sathyanarayanan.kuppuswamy@linux.intel.com \
    --cc=seanjc@google.com \
    --cc=slp@redhat.com \
    --cc=srinivas.pandruvada@linux.intel.com \
    --cc=tglx@linutronix.de \
    --cc=thomas.lendacky@amd.com \
    --cc=tobin@ibm.com \
    --cc=tony.luck@intel.com \
    --cc=vbabka@suse.cz \
    --cc=vkuznets@redhat.com \
    --cc=wanpengli@tencent.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.