x86/boot/sev: Support memory acceptance in the EFI stub under SVSM
Subsystems (3)
PATCH 1/1 x86/boot/sev: Support memory acceptance in the EFI stub under SVSM
From: Ard Biesheuvel <[email protected]>
Commit
d54d610243a4 ("x86/boot/sev: Avoid shared GHCB page for early memory acceptance")
provided a fix for SEV-SNP memory acceptance from the EFI stub when running at VMPL #0. However, that fix was insufficient for SVSM SEV-SNP guests running at VMPL >0, as those rely on a SVSM calling area, which is a shared buffer whose address is programmed into a SEV-SNP MSR, and the SEV init code that sets up this calling area executes much later during the boot.
Given that booting via the EFI stub at VMPL >0 implies that the firmware has configured this calling area already, reuse it for performing memory acceptance in the EFI stub.
---
Tom,
Please confirm that this works as you intended.
Thanks,
arch/x86/boot/compressed/mem.c | 5 +-- arch/x86/boot/compressed/sev.c | 40 ++++++++++++++++++++ arch/x86/boot/compressed/sev.h | 2 + 3 files changed, 43 insertions(+), 4 deletions(-)
arch/x86/boot/compressed/mem.c +1 -4
@@ -34,14 +34,11 @@ static bool early_is_tdx_guest(void)void arch_accept_memory (phys_addr_t start,phys_addr_t end) { -static bool sevsnp; -/* Platform-specific memory-acceptance call goes here */ if (early_is_tdx_guest ()) {if (!tdx_accept_memory (start, end))panic ("TDX: Failed to accept memory\n" ); - }else if (sevsnp || (sev_get_status () &MSR_AMD64_SEV_SNP_ENABLED )) { - sevsnp = true; + }else if (early_is_sevsnp_guest ()) {snp_accept_memory (start, end); }else {error ("Cannot accept memory: unknown platform\n" );
arch/x86/boot/compressed/sev.c +40 -0
@@ -645,3 +645,43 @@ void sev_prep_identity_maps(unsigned long top_level_pgt)sev_verify_cbit (top_level_pgt); } + +bool early_is_sevsnp_guest (void ) +{ +static bool sevsnp; + +if (sevsnp) +return true; + +if (!(sev_get_status () &MSR_AMD64_SEV_SNP_ENABLED )) +return false; + + sevsnp = true; + +if (!snp_vmpl) { +unsigned int eax, ebx, ecx, edx; + +/* +* CPUID Fn8000_001F_EAX[28] - SVSM support +*/ + eax =0x8000001f ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +if (eax &BIT (28 )) { +struct msr m; + +/* Obtain the address of the calling area to use */ +boot_rdmsr (MSR_SVSM_CAA , &m); + boot_svsm_caa = (void *)m.q; + boot_svsm_caa_pa = m.q; + +/* +* The real VMPL level cannot be discovered, but the +* memory acceptance routines make no use of that so +* any non-zero value suffices here. +*/ + snp_vmpl =U8_MAX ; + } + } +return true; +}
arch/x86/boot/compressed/sev.h +2 -0
@@ -13,12 +13,14 @@bool sev_snp_enabled (void );void snp_accept_memory (phys_addr_t start,phys_addr_t end);u64 sev_get_status (void ); +bool early_is_sevsnp_guest (void );#else static inline bool sev_snp_enabled (void ) {return false; }static inline void snp_accept_memory (phys_addr_t start,phys_addr_t end) { }static inline u64 sev_get_status (void ) {return 0 ; } +static inline bool early_is_sevsnp_guest (void ) {return false; }#endif
base-commit: b4432656b36e5cc1d50a1f2dc15357543add530e
Signature · 1 line
2.49.0.906.g1f30a19c02-goog
Quoted 13 lines · Ard Biesheuvel
From: Ard Biesheuvel <[email protected]>
Commit
d54d610243a4("x86/boot/sev: Avoid shared GHCB page for early memory acceptance")provided a fix for SEV-SNP memory acceptance from the EFI stub when running at VMPL #0. However, that fix was insufficient for SVSM SEV-SNP guests running at VMPL >0, as those rely on a SVSM calling area, which is a shared buffer whose address is programmed into a SEV-SNP MSR, and the SEV init code that sets up this calling area executes much later during the boot.
Quoted 3 lines
Given that booting via the EFI stub at VMPL >0 implies that the firmware has configured this calling area already, reuse it for performing memory acceptance in the EFI stub.
This looks to be working for SNP guest boot and kexec. SNP guest boot with an SVSM is also working, but kexec isn't. But the kexec failure of an SVSM SNP guest is unrelated to this patch, I'll send a fix for that separately.
Thanks,
Tom
Quoted 111 lines
Cc Borislav Petkov <[email protected]>Cc Ingo Molnar <[email protected]>Cc Dionna Amalie Glaze <[email protected]>Cc Kevin Loughlin <[email protected]>Cc <[email protected]>Fixes fcd042e86422 ("x86/sev: Perform PVALIDATE using the SVSM when not at VMPL0")Co-developed-by Tom Lendacky <[email protected]>Signed-off-by Tom Lendacky <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>---
Tom,Please confirm that this works as you intended.
Thanks,
arch/x86/boot/compressed/mem.c | 5 +-- arch/x86/boot/compressed/sev.c | 40 ++++++++++++++++++++ arch/x86/boot/compressed/sev.h | 2 + 3 files changed, 43 insertions(+), 4 deletions(-)arch/x86/boot/compressed/mem.c +1
-4@@ -34,14 +34,11 @@ static bool early_is_tdx_guest(void)void arch_accept_memory (phys_addr_t start,phys_addr_t end) { -static bool sevsnp; -/* Platform-specific memory-acceptance call goes here */ if (early_is_tdx_guest ()) {if (!tdx_accept_memory (start, end))panic ("TDX: Failed to accept memory\n" ); - }else if (sevsnp || (sev_get_status () &MSR_AMD64_SEV_SNP_ENABLED )) { - sevsnp = true; + }else if (early_is_sevsnp_guest ()) {snp_accept_memory (start, end); }else {error ("Cannot accept memory: unknown platform\n" );arch/x86/boot/compressed/sev.c +40
-0@@ -645,3 +645,43 @@ void sev_prep_identity_maps(unsigned long top_level_pgt)sev_verify_cbit (top_level_pgt); } + +bool early_is_sevsnp_guest (void ) +{ +static bool sevsnp; + +if (sevsnp) +return true; + +if (!(sev_get_status () &MSR_AMD64_SEV_SNP_ENABLED )) +return false; + + sevsnp = true; + +if (!snp_vmpl) { +unsigned int eax, ebx, ecx, edx; + +/* +* CPUID Fn8000_001F_EAX[28] - SVSM support +*/ + eax =0x8000001f ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +if (eax &BIT (28 )) { +struct msr m; + +/* Obtain the address of the calling area to use */ +boot_rdmsr (MSR_SVSM_CAA , &m); + boot_svsm_caa = (void *)m.q; + boot_svsm_caa_pa = m.q; + +/* +* The real VMPL level cannot be discovered, but the +* memory acceptance routines make no use of that so +* any non-zero value suffices here. +*/ + snp_vmpl =U8_MAX ; + } + } +return true; +}arch/x86/boot/compressed/sev.h +2
-0@@ -13,12 +13,14 @@bool sev_snp_enabled (void );void snp_accept_memory (phys_addr_t start,phys_addr_t end);u64 sev_get_status (void ); +bool early_is_sevsnp_guest (void );#else static inline bool sev_snp_enabled (void ) {return false; }static inline void snp_accept_memory (phys_addr_t start,phys_addr_t end) { }static inline u64 sev_get_status (void ) {return 0 ; } +static inline bool early_is_sevsnp_guest (void ) {return false; }#endif base-commit:
b4432656b36e5cc1d50a1f2dc15357543add530e
Ard Biesheuvel
maintainerQuoted 15 lines · Tom Lendacky
Quoted 13 lines · Ard Biesheuvel
From: Ard Biesheuvel <[email protected]>
Commit
d54d610243a4("x86/boot/sev: Avoid shared GHCB page for early memory acceptance")provided a fix for SEV-SNP memory acceptance from the EFI stub when running at VMPL #0. However, that fix was insufficient for SVSM SEV-SNP guests running at VMPL >0, as those rely on a SVSM calling area, which is a shared buffer whose address is programmed into a SEV-SNP MSR, and the SEV init code that sets up this calling area executes much later during the boot.
Quoted 8 lines
Quoted 3 lines
Given that booting via the EFI stub at VMPL >0 implies that the firmware has configured this calling area already, reuse it for performing memory acceptance in the EFI stub.
This looks to be working for SNP guest boot and kexec. SNP guest boot with an SVSM is also working, but kexec isn't. But the kexec failure of an SVSM SNP guest is unrelated to this patch, I'll send a fix for that separately.
Thanks for confirming.
Ingo, Boris, can we get this queued as a fix, please, and merge it back into x86/boot as was done before?
Quoted 20 lines
Thanks,
TomQuoted 17 lines
Cc Borislav Petkov <[email protected]>Cc Ingo Molnar <[email protected]>Cc Dionna Amalie Glaze <[email protected]>Cc Kevin Loughlin <[email protected]>Cc <[email protected]>Fixes fcd042e86422 ("x86/sev: Perform PVALIDATE using the SVSM when not at VMPL0")Co-developed-by Tom Lendacky <[email protected]>Signed-off-by Tom Lendacky <[email protected]>Signed-off-by Ard Biesheuvel <[email protected]>---
Tom,Please confirm that this works as you intended.
Thanks,
Quoted 25 lines · Ard Biesheuvel
Quoted 15 lines · Tom Lendacky
Quoted 13 lines · Ard Biesheuvel
From: Ard Biesheuvel <[email protected]>
Commit
d54d610243a4("x86/boot/sev: Avoid shared GHCB page for early memory acceptance")provided a fix for SEV-SNP memory acceptance from the EFI stub when running at VMPL #0. However, that fix was insufficient for SVSM SEV-SNP guests running at VMPL >0, as those rely on a SVSM calling area, which is a shared buffer whose address is programmed into a SEV-SNP MSR, and the SEV init code that sets up this calling area executes much later during the boot.
Quoted 8 lines
Quoted 3 lines
Given that booting via the EFI stub at VMPL >0 implies that the firmware has configured this calling area already, reuse it for performing memory acceptance in the EFI stub.
This looks to be working for SNP guest boot and kexec. SNP guest boot with an SVSM is also working, but kexec isn't. But the kexec failure of an SVSM SNP guest is unrelated to this patch, I'll send a fix for that separately.
Quoted 4 lines
Thanks for confirming.
Ingo, Boris, can we get this queued as a fix, please, and merge it back into x86/boot as was done before?
Just to clarify, memory acceptance trough the EFI stub from VMPL >0 SEV-SNP guests was broken last summer via fcd042e86422, and it hasn't worked since then?
Thanks,
Ingo
Ard Biesheuvel
maintainerQuoted 29 lines · Ingo Molnar
Quoted 25 lines · Ard Biesheuvel
Quoted 23 lines · Tom Lendacky
Quoted 13 lines · Ard Biesheuvel
From: Ard Biesheuvel <[email protected]>
Commit
d54d610243a4("x86/boot/sev: Avoid shared GHCB page for early memory acceptance")provided a fix for SEV-SNP memory acceptance from the EFI stub when running at VMPL #0. However, that fix was insufficient for SVSM SEV-SNP guests running at VMPL >0, as those rely on a SVSM calling area, which is a shared buffer whose address is programmed into a SEV-SNP MSR, and the SEV init code that sets up this calling area executes much later during the boot.
Quoted 3 lines
Given that booting via the EFI stub at VMPL >0 implies that the firmware has configured this calling area already, reuse it for performing memory acceptance in the EFI stub.
This looks to be working for SNP guest boot and kexec. SNP guest boot with an SVSM is also working, but kexec isn't. But the kexec failure of an SVSM SNP guest is unrelated to this patch, I'll send a fix for that separately.
Quoted 9 lines
Quoted 4 lines
Thanks for confirming.
Ingo, Boris, can we get this queued as a fix, please, and merge it back into x86/boot as was done before?
Just to clarify, memory acceptance trough the EFI stub from VMPL >0 SEV-SNP guests was broken last summer via
fcd042e86422, and it hasn't worked since then?
It never worked correctly at all for SEV-SNP, since it was enabled in d54d610243a4.
We never noticed because it appears that the SEV-SNP firmware rarely exposes EFI_UNACCEPTED regions in chunks that are not 2M aligned, and the EFI stub only accepts the misaligned bits so it can populate the unaccepted_memory table accurately, which keeps track of unaccepted memory with 2M granularity.
The following commit has been merged into the x86/urgent branch of tip:
The following commit has been merged into the x86/urgent branch of tip:
Commit-ID: 8ed12ab1319b2d8e4a529504777aacacf71371e4 Gitweb: https://git.kernel.org/tip/8ed12ab1319b2d8e4a529504777aacacf71371e4 Author: Ard Biesheuvel <[email protected]> AuthorDate: Mon, 28 Apr 2025 19:43:22 +02:00 Committer: Ingo Molnar <[email protected]> CommitterDate: Sun, 04 May 2025 08:20:27 +02:00
x86/boot/sev: Support memory acceptance in the EFI stub under SVSM
Commit:
d54d610243a4 ("x86/boot/sev: Avoid shared GHCB page for early memory acceptance")
provided a fix for SEV-SNP memory acceptance from the EFI stub when running at VMPL #0. However, that fix was insufficient for SVSM SEV-SNP guests running at VMPL >0, as those rely on a SVSM calling area, which is a shared buffer whose address is programmed into a SEV-SNP MSR, and the SEV init code that sets up this calling area executes much later during the boot.
Given that booting via the EFI stub at VMPL >0 implies that the firmware has configured this calling area already, reuse it for performing memory acceptance in the EFI stub.
--- arch/x86/boot/compressed/mem.c | 5 +---- arch/x86/boot/compressed/sev.c | 40 +++++++++++++++++++++++++++++++++- arch/x86/boot/compressed/sev.h | 2 ++- 3 files changed, 43 insertions(+), 4 deletions(-)
arch/x86/boot/compressed/mem.c +1 -4
@@ -34,14 +34,11 @@ static bool early_is_tdx_guest(void)void arch_accept_memory (phys_addr_t start,phys_addr_t end) { -static bool sevsnp; -/* Platform-specific memory-acceptance call goes here */ if (early_is_tdx_guest ()) {if (!tdx_accept_memory (start, end))panic ("TDX: Failed to accept memory\n" ); - }else if (sevsnp || (sev_get_status () &MSR_AMD64_SEV_SNP_ENABLED )) { - sevsnp = true; + }else if (early_is_sevsnp_guest ()) {snp_accept_memory (start, end); }else {error ("Cannot accept memory: unknown platform\n" );
arch/x86/boot/compressed/sev.c +40 -0
@@ -645,3 +645,43 @@ void sev_prep_identity_maps(unsigned long top_level_pgt)sev_verify_cbit (top_level_pgt); } + +bool early_is_sevsnp_guest (void ) +{ +static bool sevsnp; + +if (sevsnp) +return true; + +if (!(sev_get_status () &MSR_AMD64_SEV_SNP_ENABLED )) +return false; + + sevsnp = true; + +if (!snp_vmpl) { +unsigned int eax, ebx, ecx, edx; + +/* +* CPUID Fn8000_001F_EAX[28] - SVSM support +*/ + eax =0x8000001f ; + ecx =0 ; +native_cpuid (&eax, &ebx, &ecx, &edx); +if (eax &BIT (28 )) { +struct msr m; + +/* Obtain the address of the calling area to use */ +boot_rdmsr (MSR_SVSM_CAA , &m); + boot_svsm_caa = (void *)m.q; + boot_svsm_caa_pa = m.q; + +/* +* The real VMPL level cannot be discovered, but the +* memory acceptance routines make no use of that so +* any non-zero value suffices here. +*/ + snp_vmpl =U8_MAX ; + } + } +return true; +}
arch/x86/boot/compressed/sev.h +2 -0
@@ -13,12 +13,14 @@bool sev_snp_enabled (void );void snp_accept_memory (phys_addr_t start,phys_addr_t end);u64 sev_get_status (void ); +bool early_is_sevsnp_guest (void );#else static inline bool sev_snp_enabled (void ) {return false; }static inline void snp_accept_memory (phys_addr_t start,phys_addr_t end) { }static inline u64 sev_get_status (void ) {return 0 ; } +static inline bool early_is_sevsnp_guest (void ) {return false; }#endif