* [PATCH v2 1/4] x86/efistub: Obtain SEV CC blob address from the stub
2025-04-16 16:57 [PATCH v2 0/4] efi: Don't initalize SEV-SNP from the EFI stub Ard Biesheuvel
@ 2025-04-16 16:57 ` Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 2/4] x86/boot: Drop redundant RMPADJUST in SEV SVSM presence check Ard Biesheuvel
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2025-04-16 16:57 UTC (permalink / raw)
To: linux-efi
Cc: x86, linux-kernel, mingo, Ard Biesheuvel, Tom Lendacky,
Borislav Petkov, Dionna Amalie Glaze, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
The x86 EFI stub no longer boots via the traditional decompressor but
jumps straight to the core kernel, avoiding all the page fault handling
and other complexity that is entirely unnecessary when booting via EFI.
The SEV startup code expects the address of the CC blob configuration
table in boot_params, so store it there when booting with SEV-SNP
enabled. This removes a dependency on the later call to sev_enable()
(which is going to be removed), and permits the EFI stub to fail
gracefully inside the guest rather than terminate it entirely.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/libstub/x86-stub.c | 21 +++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index cafc90d4caaf..d9ae1a230d39 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -681,17 +681,28 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
return EFI_SUCCESS;
}
-static bool have_unsupported_snp_features(void)
+static bool check_snp_features(struct boot_params *bp)
{
+ u64 status = sev_get_status();
u64 unsupported;
- unsupported = snp_get_unsupported_features(sev_get_status());
+ unsupported = snp_get_unsupported_features(status);
if (unsupported) {
efi_err("Unsupported SEV-SNP features detected: 0x%llx\n",
unsupported);
- return true;
+ return false;
}
- return false;
+
+ if (status & MSR_AMD64_SEV_SNP_ENABLED) {
+ void *tbl = get_efi_config_table(EFI_CC_BLOB_GUID);
+
+ if (!tbl) {
+ efi_err("SEV-SNP is enabled but CC blob not found\n");
+ return false;
+ }
+ bp->cc_blob_address = (u32)(unsigned long)tbl;
+ }
+ return true;
}
static void efi_get_seed(void *seed, int size)
@@ -829,7 +840,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
hdr = &boot_params->hdr;
- if (have_unsupported_snp_features())
+ if (!check_snp_features(boot_params))
efi_exit(handle, EFI_UNSUPPORTED);
if (IS_ENABLED(CONFIG_EFI_DXE_MEM_ATTRIBUTES)) {
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 2/4] x86/boot: Drop redundant RMPADJUST in SEV SVSM presence check
2025-04-16 16:57 [PATCH v2 0/4] efi: Don't initalize SEV-SNP from the EFI stub Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 1/4] x86/efistub: Obtain SEV CC blob address from the stub Ard Biesheuvel
@ 2025-04-16 16:57 ` Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 3/4] x86/sev: Unify SEV-SNP hypervisor feature check Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 4/4] x86/efistub: Don't bother enabling SEV in the EFI stub Ard Biesheuvel
3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2025-04-16 16:57 UTC (permalink / raw)
To: linux-efi
Cc: x86, linux-kernel, mingo, Ard Biesheuvel, Tom Lendacky,
Borislav Petkov, Dionna Amalie Glaze, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
snp_vmpl will be assigned a non-zero value when executing at a VMPL
other than 0, and this is inferred from a call to RMPADJUST, which only
works when running at VMPL0.
This means that testing snp_vmpl is sufficient, and there is no need to
perform the same check again.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/compressed/sev.c | 20 +++-----------------
1 file changed, 3 insertions(+), 17 deletions(-)
diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index 6eadd790f4e5..26ba997c45fa 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -617,30 +617,16 @@ void sev_enable(struct boot_params *bp)
*/
if (sev_status & MSR_AMD64_SEV_SNP_ENABLED) {
u64 hv_features;
- int ret;
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 or with an SVSM.
- *
- * Use RMPADJUST (see the rmpadjust() function for a description of
- * what the instruction does) to update the VMPL1 permissions of a
- * page. If the guest is running at VMPL0, this will succeed. If the
- * guest is running at any other VMPL, this will fail. Linux SNP guests
- * only ever run at a single VMPL level so permission mask changes of a
- * lesser-privileged VMPL are a don't-care.
+ * Running at VMPL0 is required unless an SVSM is present and
+ * the hypervisor supports the required SVSM GHCB events.
*/
- 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 (ret &&
- !(snp_vmpl && (hv_features & GHCB_HV_FT_SNP_MULTI_VMPL)))
+ if (snp_vmpl > 0 && !(hv_features & GHCB_HV_FT_SNP_MULTI_VMPL))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
}
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 3/4] x86/sev: Unify SEV-SNP hypervisor feature check
2025-04-16 16:57 [PATCH v2 0/4] efi: Don't initalize SEV-SNP from the EFI stub Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 1/4] x86/efistub: Obtain SEV CC blob address from the stub Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 2/4] x86/boot: Drop redundant RMPADJUST in SEV SVSM presence check Ard Biesheuvel
@ 2025-04-16 16:57 ` Ard Biesheuvel
2025-04-16 16:57 ` [PATCH v2 4/4] x86/efistub: Don't bother enabling SEV in the EFI stub Ard Biesheuvel
3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2025-04-16 16:57 UTC (permalink / raw)
To: linux-efi
Cc: x86, linux-kernel, mingo, Ard Biesheuvel, Tom Lendacky,
Borislav Petkov, Dionna Amalie Glaze, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
The decompressor and the core kernel both check the hypervisor feature
mask exposed by the hypervisor, but test it in slightly different ways.
This disparity seems unintentional, and simply a result of the fact that
the decompressor and the core kernel evolve differently over time when
it comes to setting up the SEV-SNP execution context.
So move the HV feature check into a helper function and call that
instead. For the core kernel, move the check to an earlier boot stage,
right after the point where it is established that the guest is
executing in SEV-SNP mode.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/compressed/sev.c | 19 +----------
arch/x86/boot/startup/sme.c | 2 ++
arch/x86/coco/sev/core.c | 11 -------
arch/x86/coco/sev/shared.c | 33 +++++++++++++++-----
arch/x86/include/asm/sev-internal.h | 3 +-
arch/x86/include/asm/sev.h | 2 ++
6 files changed, 32 insertions(+), 38 deletions(-)
diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index 26ba997c45fa..aeee011a6486 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -611,24 +611,7 @@ void sev_enable(struct boot_params *bp)
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_PROT_UNSUPPORTED);
}
- /*
- * SNP is supported in v2 of the GHCB spec which mandates support for HV
- * features.
- */
- if (sev_status & MSR_AMD64_SEV_SNP_ENABLED) {
- u64 hv_features;
-
- hv_features = get_hv_features();
- if (!(hv_features & GHCB_HV_FT_SNP))
- sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
-
- /*
- * Running at VMPL0 is required unless an SVSM is present and
- * the hypervisor supports the required SVSM GHCB events.
- */
- if (snp_vmpl > 0 && !(hv_features & GHCB_HV_FT_SNP_MULTI_VMPL))
- sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
- }
+ snp_check_hv_features();
if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
error("SEV-SNP supported indicated by CC blob, but not SEV status MSR.");
diff --git a/arch/x86/boot/startup/sme.c b/arch/x86/boot/startup/sme.c
index 5738b31c8e60..11caa343790d 100644
--- a/arch/x86/boot/startup/sme.c
+++ b/arch/x86/boot/startup/sme.c
@@ -533,6 +533,8 @@ void __head sme_enable(struct boot_params *bp)
if (snp_en ^ !!(msr & MSR_AMD64_SEV_SNP_ENABLED))
snp_abort();
+ sev_hv_features = snp_check_hv_features();
+
/* Check if memory encryption is enabled */
if (feature_mask == AMD_SME_BIT) {
if (!(bp->hdr.xloadflags & XLF_MEM_ENCRYPTION))
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index aeb7731862c0..4618ab64c767 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -1582,17 +1582,6 @@ void __init sev_es_init_vc_handling(void)
if (!sev_es_check_cpu_features())
panic("SEV-ES CPU Features missing");
- /*
- * SNP is supported in v2 of the GHCB spec which mandates support for HV
- * features.
- */
- if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) {
- sev_hv_features = get_hv_features();
-
- if (!(sev_hv_features & GHCB_HV_FT_SNP))
- sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
- }
-
/* Initialize per-cpu GHCB pages */
for_each_possible_cpu(cpu) {
alloc_runtime_data(cpu);
diff --git a/arch/x86/coco/sev/shared.c b/arch/x86/coco/sev/shared.c
index a7c94020e384..514e2d42700b 100644
--- a/arch/x86/coco/sev/shared.c
+++ b/arch/x86/coco/sev/shared.c
@@ -99,16 +99,10 @@ sev_es_terminate(unsigned int set, unsigned int reason)
asm volatile("hlt\n" : : : "memory");
}
-/*
- * The hypervisor features are available from GHCB version 2 onward.
- */
-u64 get_hv_features(void)
+static u64 __head get_hv_features(void)
{
u64 val;
- if (ghcb_version < 2)
- return 0;
-
sev_es_wr_ghcb_msr(GHCB_MSR_HV_FT_REQ);
VMGEXIT();
@@ -119,6 +113,31 @@ u64 get_hv_features(void)
return GHCB_MSR_HV_FT_RESP_VAL(val);
}
+u64 __head snp_check_hv_features(void)
+{
+ /*
+ * SNP is supported in v2 of the GHCB spec which mandates support for HV
+ * features.
+ */
+ if (RIP_REL_REF(sev_status) & MSR_AMD64_SEV_SNP_ENABLED) {
+ u64 hv_features;
+
+ hv_features = get_hv_features();
+ if (!(hv_features & GHCB_HV_FT_SNP))
+ sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
+
+ /*
+ * Running at VMPL0 is required unless an SVSM is present and
+ * the hypervisor supports the required SVSM GHCB events.
+ */
+ if (snp_vmpl > 0 && !(hv_features & GHCB_HV_FT_SNP_MULTI_VMPL))
+ sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
+
+ return hv_features;
+ }
+ return 0;
+}
+
void snp_register_ghcb_early(unsigned long paddr)
{
unsigned long pfn = paddr >> PAGE_SHIFT;
diff --git a/arch/x86/include/asm/sev-internal.h b/arch/x86/include/asm/sev-internal.h
index 73cb774c3639..81abef86b1d0 100644
--- a/arch/x86/include/asm/sev-internal.h
+++ b/arch/x86/include/asm/sev-internal.h
@@ -4,7 +4,6 @@
extern struct ghcb boot_ghcb_page;
extern struct ghcb *boot_ghcb;
-extern u64 sev_hv_features;
/* #VC handler runtime per-CPU data */
struct sev_es_runtime_data {
@@ -117,6 +116,6 @@ enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
void snp_register_ghcb_early(unsigned long paddr);
bool sev_es_negotiate_protocol(void);
bool sev_es_check_cpu_features(void);
-u64 get_hv_features(void);
+void check_hv_features(void);
const struct snp_cpuid_table *snp_cpuid_get_table(void);
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index a8661dfc9a9a..8637a65973ef 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -418,6 +418,7 @@ struct svsm_call {
#ifdef CONFIG_AMD_MEM_ENCRYPT
extern u8 snp_vmpl;
+extern u64 sev_hv_features;
extern void __sev_es_ist_enter(struct pt_regs *regs);
extern void __sev_es_ist_exit(void);
@@ -494,6 +495,7 @@ void snp_set_memory_private(unsigned long vaddr, unsigned long npages);
void snp_set_wakeup_secondary_cpu(void);
bool snp_init(struct boot_params *bp);
void __noreturn snp_abort(void);
+u64 snp_check_hv_features(void);
void snp_dmi_setup(void);
int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call, struct svsm_attest_call *input);
void snp_accept_memory(phys_addr_t start, phys_addr_t end);
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 4/4] x86/efistub: Don't bother enabling SEV in the EFI stub
2025-04-16 16:57 [PATCH v2 0/4] efi: Don't initalize SEV-SNP from the EFI stub Ard Biesheuvel
` (2 preceding siblings ...)
2025-04-16 16:57 ` [PATCH v2 3/4] x86/sev: Unify SEV-SNP hypervisor feature check Ard Biesheuvel
@ 2025-04-16 16:57 ` Ard Biesheuvel
3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2025-04-16 16:57 UTC (permalink / raw)
To: linux-efi
Cc: x86, linux-kernel, mingo, Ard Biesheuvel, Tom Lendacky,
Borislav Petkov, Dionna Amalie Glaze, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
One of the last things the EFI stub does before handing over to the core
kernel when booting as a SEV guest is enabling SEV, even though this is
mostly redundant: one of the first things the core kernel does is
calling sme_enable(), after setting up the early GDT and IDT but before
even setting up the kernel page tables.
So let's just drop this call to sev_enable(), and rely on the core
kernel to initiaize SEV correctly.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/include/asm/sev.h | 2 --
drivers/firmware/efi/libstub/x86-stub.c | 6 ------
2 files changed, 8 deletions(-)
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 8637a65973ef..d762cc0fd47e 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -443,7 +443,6 @@ static __always_inline void sev_es_nmi_complete(void)
__sev_es_nmi_complete();
}
extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
-extern void sev_enable(struct boot_params *bp);
/*
* RMPADJUST modifies the RMP permissions of a page of a lesser-
@@ -531,7 +530,6 @@ static inline void sev_es_ist_exit(void) { }
static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; }
static inline void sev_es_nmi_complete(void) { }
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
-static inline void sev_enable(struct boot_params *bp) { }
static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; }
static inline void setup_ghcb(void) { }
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index d9ae1a230d39..6b4f5ac91e7f 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -936,12 +936,6 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
goto fail;
}
- /*
- * Call the SEV init code while still running with the firmware's
- * GDT/IDT, so #VC exceptions will be handled by EFI.
- */
- sev_enable(boot_params);
-
efi_5level_switch();
enter_kernel(kernel_entry, boot_params);
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 5+ messages in thread