Skip to content

Commit 31c77a5

Browse files
ardbiesheuvelbp3tk0v
authored andcommitted
x86/efistub: Perform SNP feature test while running in the firmware
Before refactoring the EFI stub boot flow to avoid the legacy bare metal decompressor, duplicate the SNP feature check in the EFI stub before handing over to the kernel proper. The SNP feature check can be performed while running under the EFI boot services, which means it can force the boot to fail gracefully and return an error to the bootloader if the loaded kernel does not implement support for all the features that the hypervisor enabled. Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bc5ddce commit 31c77a5

File tree

3 files changed

+87
-46
lines changed

3 files changed

+87
-46
lines changed

arch/x86/boot/compressed/sev.c

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -367,20 +367,25 @@ static void enforce_vmpl0(void)
367367
*/
368368
#define SNP_FEATURES_PRESENT (0)
369369

370+
u64 snp_get_unsupported_features(u64 status)
371+
{
372+
if (!(status & MSR_AMD64_SEV_SNP_ENABLED))
373+
return 0;
374+
375+
return status & SNP_FEATURES_IMPL_REQ & ~SNP_FEATURES_PRESENT;
376+
}
377+
370378
void snp_check_features(void)
371379
{
372380
u64 unsupported;
373381

374-
if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
375-
return;
376-
377382
/*
378383
* Terminate the boot if hypervisor has enabled any feature lacking
379384
* guest side implementation. Pass on the unsupported features mask through
380385
* EXIT_INFO_2 of the GHCB protocol so that those features can be reported
381386
* as part of the guest boot failure.
382387
*/
383-
unsupported = sev_status & SNP_FEATURES_IMPL_REQ & ~SNP_FEATURES_PRESENT;
388+
unsupported = snp_get_unsupported_features(sev_status);
384389
if (unsupported) {
385390
if (ghcb_version < 2 || (!boot_ghcb && !early_setup_ghcb()))
386391
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
@@ -390,35 +395,22 @@ void snp_check_features(void)
390395
}
391396
}
392397

393-
void sev_enable(struct boot_params *bp)
398+
/*
399+
* sev_check_cpu_support - Check for SEV support in the CPU capabilities
400+
*
401+
* Returns < 0 if SEV is not supported, otherwise the position of the
402+
* encryption bit in the page table descriptors.
403+
*/
404+
static int sev_check_cpu_support(void)
394405
{
395406
unsigned int eax, ebx, ecx, edx;
396-
struct msr m;
397-
bool snp;
398-
399-
/*
400-
* bp->cc_blob_address should only be set by boot/compressed kernel.
401-
* Initialize it to 0 to ensure that uninitialized values from
402-
* buggy bootloaders aren't propagated.
403-
*/
404-
if (bp)
405-
bp->cc_blob_address = 0;
406-
407-
/*
408-
* Do an initial SEV capability check before snp_init() which
409-
* loads the CPUID page and the same checks afterwards are done
410-
* without the hypervisor and are trustworthy.
411-
*
412-
* If the HV fakes SEV support, the guest will crash'n'burn
413-
* which is good enough.
414-
*/
415407

416408
/* Check for the SME/SEV support leaf */
417409
eax = 0x80000000;
418410
ecx = 0;
419411
native_cpuid(&eax, &ebx, &ecx, &edx);
420412
if (eax < 0x8000001f)
421-
return;
413+
return -ENODEV;
422414

423415
/*
424416
* Check for the SME/SEV feature:
@@ -433,6 +425,35 @@ void sev_enable(struct boot_params *bp)
433425
native_cpuid(&eax, &ebx, &ecx, &edx);
434426
/* Check whether SEV is supported */
435427
if (!(eax & BIT(1)))
428+
return -ENODEV;
429+
430+
return ebx & 0x3f;
431+
}
432+
433+
void sev_enable(struct boot_params *bp)
434+
{
435+
struct msr m;
436+
int bitpos;
437+
bool snp;
438+
439+
/*
440+
* bp->cc_blob_address should only be set by boot/compressed kernel.
441+
* Initialize it to 0 to ensure that uninitialized values from
442+
* buggy bootloaders aren't propagated.
443+
*/
444+
if (bp)
445+
bp->cc_blob_address = 0;
446+
447+
/*
448+
* Do an initial SEV capability check before snp_init() which
449+
* loads the CPUID page and the same checks afterwards are done
450+
* without the hypervisor and are trustworthy.
451+
*
452+
* If the HV fakes SEV support, the guest will crash'n'burn
453+
* which is good enough.
454+
*/
455+
456+
if (sev_check_cpu_support() < 0)
436457
return;
437458

438459
/*
@@ -443,26 +464,8 @@ void sev_enable(struct boot_params *bp)
443464

444465
/* Now repeat the checks with the SNP CPUID table. */
445466

446-
/* Recheck the SME/SEV support leaf */
447-
eax = 0x80000000;
448-
ecx = 0;
449-
native_cpuid(&eax, &ebx, &ecx, &edx);
450-
if (eax < 0x8000001f)
451-
return;
452-
453-
/*
454-
* Recheck for the SME/SEV feature:
455-
* CPUID Fn8000_001F[EAX]
456-
* - Bit 0 - Secure Memory Encryption support
457-
* - Bit 1 - Secure Encrypted Virtualization support
458-
* CPUID Fn8000_001F[EBX]
459-
* - Bits 5:0 - Pagetable bit position used to indicate encryption
460-
*/
461-
eax = 0x8000001f;
462-
ecx = 0;
463-
native_cpuid(&eax, &ebx, &ecx, &edx);
464-
/* Check whether SEV is supported */
465-
if (!(eax & BIT(1))) {
467+
bitpos = sev_check_cpu_support();
468+
if (bitpos < 0) {
466469
if (snp)
467470
error("SEV-SNP support indicated by CC blob, but not CPUID.");
468471
return;
@@ -494,7 +497,24 @@ void sev_enable(struct boot_params *bp)
494497
if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
495498
error("SEV-SNP supported indicated by CC blob, but not SEV status MSR.");
496499

497-
sme_me_mask = BIT_ULL(ebx & 0x3f);
500+
sme_me_mask = BIT_ULL(bitpos);
501+
}
502+
503+
/*
504+
* sev_get_status - Retrieve the SEV status mask
505+
*
506+
* Returns 0 if the CPU is not SEV capable, otherwise the value of the
507+
* AMD64_SEV MSR.
508+
*/
509+
u64 sev_get_status(void)
510+
{
511+
struct msr m;
512+
513+
if (sev_check_cpu_support() < 0)
514+
return 0;
515+
516+
boot_rdmsr(MSR_AMD64_SEV, &m);
517+
return m.q;
498518
}
499519

500520
/* Search for Confidential Computing blob in the EFI config table. */

arch/x86/include/asm/sev.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ bool snp_init(struct boot_params *bp);
210210
void __init __noreturn snp_abort(void);
211211
int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio);
212212
void snp_accept_memory(phys_addr_t start, phys_addr_t end);
213+
u64 snp_get_unsupported_features(u64 status);
214+
u64 sev_get_status(void);
213215
#else
214216
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
215217
static inline void sev_es_ist_exit(void) { }
@@ -235,6 +237,8 @@ static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *in
235237
}
236238

237239
static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
240+
static inline u64 snp_get_unsupported_features(u64 status) { return 0; }
241+
static inline u64 sev_get_status(void) { return 0; }
238242
#endif
239243

240244
#endif

drivers/firmware/efi/libstub/x86-stub.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <asm/setup.h>
1616
#include <asm/desc.h>
1717
#include <asm/boot.h>
18+
#include <asm/sev.h>
1819

1920
#include "efistub.h"
2021
#include "x86-stub.h"
@@ -790,6 +791,19 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
790791
return EFI_SUCCESS;
791792
}
792793

794+
static bool have_unsupported_snp_features(void)
795+
{
796+
u64 unsupported;
797+
798+
unsupported = snp_get_unsupported_features(sev_get_status());
799+
if (unsupported) {
800+
efi_err("Unsupported SEV-SNP features detected: 0x%llx\n",
801+
unsupported);
802+
return true;
803+
}
804+
return false;
805+
}
806+
793807
static void __noreturn enter_kernel(unsigned long kernel_addr,
794808
struct boot_params *boot_params)
795809
{
@@ -820,6 +834,9 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
820834
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
821835
efi_exit(handle, EFI_INVALID_PARAMETER);
822836

837+
if (have_unsupported_snp_features())
838+
efi_exit(handle, EFI_UNSUPPORTED);
839+
823840
if (IS_ENABLED(CONFIG_EFI_DXE_MEM_ATTRIBUTES)) {
824841
efi_dxe_table = get_efi_config_table(EFI_DXE_SERVICES_TABLE_GUID);
825842
if (efi_dxe_table &&

0 commit comments

Comments
 (0)