2024-04-24 16:03:38

by Tom Lendacky

[permalink] [raw]
Subject: [PATCH v4 15/15] x86/sev: Allow non-VMPL0 execution when an SVSM is present

To allow execution at a level other than VMPL0, an SVSM must be present.
Allow the SEV-SNP guest to continue booting if an SVSM is detected and
the hypervisor supports the SVSM feature as indicated in the GHCB
hypervisor features bitmap.

Signed-off-by: Tom Lendacky <[email protected]>
---
arch/x86/boot/compressed/sev.c | 12 +++++++++---
arch/x86/include/asm/sev-common.h | 1 +
arch/x86/kernel/sev.c | 20 +++++++++++++++++---
3 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index 32a1e98ffaa9..fb1e60165cd1 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -610,11 +610,13 @@ void sev_enable(struct boot_params *bp)
* features.
*/
if (sev_status & MSR_AMD64_SEV_SNP_ENABLED) {
- if (!(get_hv_features() & GHCB_HV_FT_SNP))
+ u64 hv_features = get_hv_features();
+
+ if (!(hv_features & GHCB_HV_FT_SNP))
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);

/*
- * Enforce running at VMPL0.
+ * Enforce running at VMPL0 or with an SVSM.
*
* RMPADJUST modifies RMP permissions of a lesser-privileged (numerically
* higher) privilege level. Here, clear the VMPL1 permission mask of the
@@ -624,8 +626,12 @@ void sev_enable(struct boot_params *bp)
* modifies permission bits, it is still ok to do so currently because Linux
* SNP guests running at VMPL0 only run at VMPL0, so VMPL1 or higher
* permission mask changes are a don't-care.
+ *
+ * Running at VMPL0 is not required if an SVSM is present and the hypervisor
+ * supports the required SVSM GHCB events.
*/
- if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1))
+ if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1) &&
+ !(vmpl && (hv_features & GHCB_HV_FT_SNP_MULTI_VMPL)))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
}

diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
index 4cc716660d4b..7a9d09458989 100644
--- a/arch/x86/include/asm/sev-common.h
+++ b/arch/x86/include/asm/sev-common.h
@@ -118,6 +118,7 @@ enum psc_op {

#define GHCB_HV_FT_SNP BIT_ULL(0)
#define GHCB_HV_FT_SNP_AP_CREATION BIT_ULL(1)
+#define GHCB_HV_FT_SNP_MULTI_VMPL BIT_ULL(5)

/*
* SNP Page State Change NAE event
diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index 5e71c94b952c..50754cc45161 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -2356,22 +2356,36 @@ static void dump_cpuid_table(void)
* 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)
+static void __init report_cpuid_table(void)
{
const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();

if (!cpuid_table->count)
- return 0;
+ return;

pr_info("Using SNP CPUID table, %d entries present.\n",
cpuid_table->count);

if (sev_cfg.debug)
dump_cpuid_table();
+}
+
+static void __init report_vmpl_level(void)
+{
+ if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+ return;
+
+ pr_info("SNP running at VMPL%u.\n", vmpl);
+}
+
+static int __init report_snp_info(void)
+{
+ report_vmpl_level();
+ report_cpuid_table();

return 0;
}
-arch_initcall(report_cpuid_table);
+arch_initcall(report_snp_info);

static int __init init_sev_config(char *str)
{
--
2.43.2



2024-05-03 11:37:32

by Joerg Roedel

[permalink] [raw]
Subject: Re: [svsm-devel] [PATCH v4 15/15] x86/sev: Allow non-VMPL0 execution when an SVSM is present

On Wed, Apr 24, 2024 at 10:58:11AM -0500, Tom Lendacky wrote:
> +static void __init report_vmpl_level(void)
> +{
> + if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
> + return;
> +
> + pr_info("SNP running at VMPL%u.\n", vmpl);

Nit: Can this be formated more like "SNP running at VMPL-%u"? That makes
it easier to parse for me when looking into dmesg :)

Regards,

Joerg

2024-05-03 16:04:56

by Borislav Petkov

[permalink] [raw]
Subject: Re: [svsm-devel] [PATCH v4 15/15] x86/sev: Allow non-VMPL0 execution when an SVSM is present

On Fri, May 03, 2024 at 01:37:20PM +0200, Jörg Rödel wrote:
> Nit: Can this be formated more like "SNP running at VMPL-%u"? That makes
> it easier to parse for me when looking into dmesg :)

Hmm, except that all documentation is without a "-"... The APM talks
about VMPL%d everywhere...

--
Regards/Gruss,
Boris.

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

2024-05-06 07:44:17

by Jörg Rödel

[permalink] [raw]
Subject: Re: [svsm-devel] [PATCH v4 15/15] x86/sev: Allow non-VMPL0 execution when an SVSM is present

On Fri, May 03, 2024 at 06:04:19PM +0200, Borislav Petkov wrote:
> On Fri, May 03, 2024 at 01:37:20PM +0200, J?rg R?del wrote:
> > Nit: Can this be formated more like "SNP running at VMPL-%u"? That makes
> > it easier to parse for me when looking into dmesg :)
>
> Hmm, except that all documentation is without a "-"... The APM talks
> about VMPL%d everywhere...

No strict opinion, I just wanted to point out that there are more
readable ways of printing the VMPL level than what is used in the APM.

Regards,

--
J?rg R?del
[email protected]

SUSE Software Solutions Germany GmbH
Frankenstra?e 146
90461 N?rnberg
Germany
https://www.suse.com/

Gesch?ftsf?hrer: Ivo Totev, Andrew McDonald, Werner Knoblich
(HRB 36809, AG N?rnberg)

2024-05-31 14:54:57

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v4 15/15] x86/sev: Allow non-VMPL0 execution when an SVSM is present

On Wed, Apr 24, 2024 at 10:58:11AM -0500, Tom Lendacky wrote:
> @@ -624,8 +626,12 @@ void sev_enable(struct boot_params *bp)
> * modifies permission bits, it is still ok to do so currently because Linux
> * SNP guests running at VMPL0 only run at VMPL0, so VMPL1 or higher
> * permission mask changes are a don't-care.
> + *
> + * Running at VMPL0 is not required if an SVSM is present and the hypervisor
> + * supports the required SVSM GHCB events.
> */
> - if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1))
> + if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1) &&
> + !(vmpl && (hv_features & GHCB_HV_FT_SNP_MULTI_VMPL)))
> sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
> }

Let's make that more readable:

diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index fb1e60165cd1..157f749faba0 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -610,8 +610,10 @@ void sev_enable(struct boot_params *bp)
* features.
*/
if (sev_status & MSR_AMD64_SEV_SNP_ENABLED) {
- u64 hv_features = get_hv_features();
+ u64 hv_features;
+ int rmpadj_ret;

+ hv_features = get_hv_features();
if (!(hv_features & GHCB_HV_FT_SNP))
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);

@@ -626,11 +628,15 @@ void sev_enable(struct boot_params *bp)
* modifies permission bits, it is still ok to do so currently because Linux
* SNP guests running at VMPL0 only run at VMPL0, so VMPL1 or higher
* permission mask changes are a don't-care.
- *
+ */
+ rmpadj_ret = rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1);
+
+ /*
* Running at VMPL0 is not required if an SVSM is present and the hypervisor
* supports the required SVSM GHCB events.
*/
- if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1) &&
+
+ if (rmpadj_ret &&
!(vmpl && (hv_features & GHCB_HV_FT_SNP_MULTI_VMPL)))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
}

> -static int __init report_cpuid_table(void)
> +static void __init report_cpuid_table(void)
> {
> const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
>
> if (!cpuid_table->count)
> - return 0;
> + return;
>
> pr_info("Using SNP CPUID table, %d entries present.\n",
> cpuid_table->count);
>
> if (sev_cfg.debug)
> dump_cpuid_table();
> +}
> +
> +static void __init report_vmpl_level(void)
> +{
> + if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
> + return;
> +
> + pr_info("SNP running at VMPL%u.\n", vmpl);
> +}
> +
> +static int __init report_snp_info(void)
> +{
> + report_vmpl_level();
> + report_cpuid_table();
>
> return 0;
> }
> -arch_initcall(report_cpuid_table);
> +arch_initcall(report_snp_info);

Zap one more silly helper:

diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index 7955c024d5d7..ff5a32b0b21c 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -2356,32 +2356,23 @@ static void dump_cpuid_table(void)
* sort of indicator, and there's not really any other good place to do it,
* so do it here.
*/
-static void __init report_cpuid_table(void)
+static int __init report_snp_info(void)
{
const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();

if (!cpuid_table->count)
- return;
+ return 0;

pr_info("Using SNP CPUID table, %d entries present.\n",
cpuid_table->count);

if (sev_cfg.debug)
dump_cpuid_table();
-}

-static void __init report_vmpl_level(void)
-{
if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
- return;
+ return 0;

pr_info("SNP running at VMPL%u.\n", vmpl);
-}
-
-static int __init report_snp_info(void)
-{
- report_vmpl_level();
- report_cpuid_table();

return 0;
}

--
Regards/Gruss,
Boris.

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

2024-05-31 19:29:21

by Tom Lendacky

[permalink] [raw]
Subject: Re: [PATCH v4 15/15] x86/sev: Allow non-VMPL0 execution when an SVSM is present

On 5/31/24 09:54, Borislav Petkov wrote:
> On Wed, Apr 24, 2024 at 10:58:11AM -0500, Tom Lendacky wrote:
>> @@ -624,8 +626,12 @@ void sev_enable(struct boot_params *bp)
>> * modifies permission bits, it is still ok to do so currently because Linux
>> * SNP guests running at VMPL0 only run at VMPL0, so VMPL1 or higher
>> * permission mask changes are a don't-care.
>> + *
>> + * Running at VMPL0 is not required if an SVSM is present and the hypervisor
>> + * supports the required SVSM GHCB events.
>> */
>> - if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1))
>> + if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1) &&
>> + !(vmpl && (hv_features & GHCB_HV_FT_SNP_MULTI_VMPL)))
>> sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
>> }
>
> Let's make that more readable:

Will do.

>
> diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
> index fb1e60165cd1..157f749faba0 100644
> --- a/arch/x86/boot/compressed/sev.c
> +++ b/arch/x86/boot/compressed/sev.c
> @@ -610,8 +610,10 @@ void sev_enable(struct boot_params *bp)
> * features.
> */
> if (sev_status & MSR_AMD64_SEV_SNP_ENABLED) {
> - u64 hv_features = get_hv_features();
> + u64 hv_features;
> + int rmpadj_ret;

But I'll probably just call this 'ret'.

>
> + hv_features = get_hv_features();
> if (!(hv_features & GHCB_HV_FT_SNP))
> sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
>
> @@ -626,11 +628,15 @@ void sev_enable(struct boot_params *bp)
> * modifies permission bits, it is still ok to do so currently because Linux
> * SNP guests running at VMPL0 only run at VMPL0, so VMPL1 or higher
> * permission mask changes are a don't-care.
> - *
> + */
> + rmpadj_ret = rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1);
> +
> + /*
> * Running at VMPL0 is not required if an SVSM is present and the hypervisor
> * supports the required SVSM GHCB events.
> */
> - if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1) &&
> +
> + if (rmpadj_ret &&
> !(vmpl && (hv_features & GHCB_HV_FT_SNP_MULTI_VMPL)))
> sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
> }
>
>> -static int __init report_cpuid_table(void)
>> +static void __init report_cpuid_table(void)
>> {
>> const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
>>
>> if (!cpuid_table->count)
>> - return 0;
>> + return;
>>
>> pr_info("Using SNP CPUID table, %d entries present.\n",
>> cpuid_table->count);
>>
>> if (sev_cfg.debug)
>> dump_cpuid_table();
>> +}
>> +
>> +static void __init report_vmpl_level(void)
>> +{
>> + if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
>> + return;
>> +
>> + pr_info("SNP running at VMPL%u.\n", vmpl);
>> +}
>> +
>> +static int __init report_snp_info(void)
>> +{
>> + report_vmpl_level();
>> + report_cpuid_table();
>>
>> return 0;
>> }
>> -arch_initcall(report_cpuid_table);
>> +arch_initcall(report_snp_info);
>
> Zap one more silly helper:
>
> diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
> index 7955c024d5d7..ff5a32b0b21c 100644
> --- a/arch/x86/kernel/sev.c
> +++ b/arch/x86/kernel/sev.c
> @@ -2356,32 +2356,23 @@ static void dump_cpuid_table(void)
> * sort of indicator, and there's not really any other good place to do it,
> * so do it here.
> */
> -static void __init report_cpuid_table(void)
> +static int __init report_snp_info(void)
> {
> const struct snp_cpuid_table *cpuid_table = snp_cpuid_get_table();
>
> if (!cpuid_table->count)
> - return;
> + return 0;

Well you can't return in this case, just not report/dump the CPUID info.
So I'll remove the helpers and adjust accordingly.

Thanks,
Tom

>
> pr_info("Using SNP CPUID table, %d entries present.\n",
> cpuid_table->count);
>
> if (sev_cfg.debug)
> dump_cpuid_table();
> -}
>
> -static void __init report_vmpl_level(void)
> -{
> if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
> - return;
> + return 0;
>
> pr_info("SNP running at VMPL%u.\n", vmpl);
> -}
> -
> -static int __init report_snp_info(void)
> -{
> - report_vmpl_level();
> - report_cpuid_table();
>
> return 0;
> }
>