@@ -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+
370378void 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. */
0 commit comments