For the most part, OVMF will clear the encryption bit for MMIO regions, but there is currently one known exception during SEC when the APIC base address is accessed via MMIO with the encryption bit set for SEV-ES/SEV-SNP guests. In the case of SEV-SNP, this requires special handling on the hypervisor side which may not be available in the future[1], so make the necessary changes in the SEC-configured page table to clear the encryption bit for 4K region containing the APIC base address.
While here, drop special handling for the APIC base address in the SEV-ES/SNP #VC handler. [1] https://lore.kernel.org/lkml/20240208002420.34mvemnzrwwsa...@amd.com/#t Suggested-by: Tom Lendacky <thomas.lenda...@amd.com> Cc: Ard Biesheuvel <a...@kernel.org> Cc: Gerd Hoffmann <kra...@redhat.com> Cc: Erdem Aktas <erdemak...@google.com> Cc: Jiewen Yao <jiewen....@intel.com> Cc: Min Xu <min.m...@intel.com> Cc: Tom Lendacky <thomas.lenda...@amd.com> Cc: Jianyong Wu <jianyong...@arm.com> Cc: Anatol Belski <anbel...@linux.microsoft.com> Signed-off-by: Michael Roth <michael.r...@amd.com> --- OvmfPkg/AmdSev/AmdSevX64.fdf | 5 +- OvmfPkg/CloudHv/CloudHvX64.fdf | 5 +- OvmfPkg/Library/CcExitLib/CcExitVcHandler.c | 12 +--- OvmfPkg/Microvm/MicrovmX64.fdf | 3 + OvmfPkg/OvmfPkg.dec | 5 ++ OvmfPkg/OvmfPkgX64.fdf | 5 +- OvmfPkg/Sec/AmdSev.c | 71 +++++++++++++++++++++ OvmfPkg/Sec/AmdSev.h | 14 ++++ OvmfPkg/Sec/SecMain.c | 1 + OvmfPkg/Sec/SecMain.inf | 2 + 10 files changed, 109 insertions(+), 14 deletions(-) diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf index d49555c6c8..595945181c 100644 --- a/OvmfPkg/AmdSev/AmdSevX64.fdf +++ b/OvmfPkg/AmdSev/AmdSevX64.fdf @@ -77,7 +77,10 @@ gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase|gUefiOvmfPkgTokenSpaceGuid.Pcd 0x010C00|0x000400 gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableSize -0x011000|0x00F000 +0x011000|0x001000 +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableSize + +0x012000|0x00E000 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize 0x020000|0x0E0000 diff --git a/OvmfPkg/CloudHv/CloudHvX64.fdf b/OvmfPkg/CloudHv/CloudHvX64.fdf index eae3ada191..3e6688b103 100644 --- a/OvmfPkg/CloudHv/CloudHvX64.fdf +++ b/OvmfPkg/CloudHv/CloudHvX64.fdf @@ -76,7 +76,10 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCp 0x00F000|0x001000 gUefiOvmfPkgTokenSpaceGuid.PcdXenPvhStartOfDayStructPtr|gUefiOvmfPkgTokenSpaceGuid.PcdXenPvhStartOfDayStructPtrSize -0x010000|0x010000 +0x010000|0x001000 +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableSize + +0x011000|0x00F000 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize 0x020000|0x0E0000 diff --git a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c index 549375dfed..da8f1e5db9 100644 --- a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c +++ b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c @@ -98,7 +98,7 @@ UnsupportedExit ( Validate that the MMIO memory access is not to encrypted memory. Examine the pagetable entry for the memory specified. MMIO should not be - performed against encrypted memory. MMIO to the APIC page is always allowed. + performed against encrypted memory. @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block @param[in] MemoryAddress Memory address to validate @@ -118,16 +118,6 @@ ValidateMmioMemory ( { MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State; GHCB_EVENT_INJECTION GpEvent; - UINTN Address; - - // - // Allow APIC accesses (which will have the encryption bit set during - // SEC and PEI phases). - // - Address = MemoryAddress & ~(SIZE_4KB - 1); - if (Address == GetLocalApicBaseAddress ()) { - return 0; - } State = MemEncryptSevGetAddressRangeState ( 0, diff --git a/OvmfPkg/Microvm/MicrovmX64.fdf b/OvmfPkg/Microvm/MicrovmX64.fdf index 825bf9f5e4..055e659a35 100644 --- a/OvmfPkg/Microvm/MicrovmX64.fdf +++ b/OvmfPkg/Microvm/MicrovmX64.fdf @@ -62,6 +62,9 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvm 0x00C000|0x001000 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize +0x00D000|0x001000 +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableSize + 0x010000|0x010000 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 2f7bded926..b23219ebd4 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -277,6 +277,11 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase|0|UINT32|0x44 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize|0|UINT32|0x45 + ## Specify the extra page table needed to mark the APIC MMIO range as unencrypted. + # The value should be a multiple of 4KB for each. + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableBase|0x0|UINT32|0x72 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableSize|0x0|UINT32|0x73 + ## The base address and size of the SEV Launch Secret Area provisioned # after remote attestation. If this is set in the .fdf, the platform # is responsible for protecting the area from DXE phase overwrites. diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index c2d3cc901e..b6e8f43566 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -97,7 +97,10 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCp 0x00F000|0x001000 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecSvsmCaaBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecSvsmCaaSize -0x010000|0x010000 +0x010000|0x001000 +gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableSize + +0x011000|0x00F000 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize 0x020000|0x0E0000 diff --git a/OvmfPkg/Sec/AmdSev.c b/OvmfPkg/Sec/AmdSev.c index 520b125132..cff2ecbb8c 100644 --- a/OvmfPkg/Sec/AmdSev.c +++ b/OvmfPkg/Sec/AmdSev.c @@ -8,11 +8,15 @@ **/ #include <Library/BaseLib.h> +#include <Library/CpuLib.h> #include <Library/DebugLib.h> +#include <Library/LocalApicLib.h> #include <Library/MemEncryptSevLib.h> #include <Library/BaseMemoryLib.h> #include <Register/Amd/Ghcb.h> #include <Register/Amd/Msr.h> +#include <IndustryStandard/PageTable.h> +#include <WorkArea.h> #include "AmdSev.h" @@ -301,3 +305,70 @@ SecValidateSystemRam ( MemEncryptSevSnpPreValidateSystemRam (Start, EFI_SIZE_TO_PAGES ((UINTN)(End - Start))); } } + +/** + Map known MMIO regions unencrypted if SEV-ES is active. + + During early booting, page table entries default to having the encryption bit + set for SEV-ES/SEV-SNP guests. In cases where there is MMIO to an address, the + encryption bit should be cleared. Clear it here for any known MMIO accesses + during SEC, which is currently just the APIC base address. + +**/ +VOID +SecMapApicBaseUnencrypted ( + VOID + ) +{ + PAGE_MAP_AND_DIRECTORY_POINTER *Level4Entry; + PAGE_MAP_AND_DIRECTORY_POINTER *Level3Entry; + PAGE_MAP_AND_DIRECTORY_POINTER *Level2Entry; + PAGE_TABLE_4K_ENTRY *Level1Entry; + SEC_SEV_ES_WORK_AREA *SevEsWorkArea; + PHYSICAL_ADDRESS Cr3; + UINT64 ApicAddress; + UINT64 PgTableMask; + UINT32 Level1Page; + UINT64 Level1Address; + UINT64 Level1Flags; + UINTN PteIndex; + + if (!SevEsIsEnabled ()) { + return; + } + + SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *)FixedPcdGet32 (PcdSevEsWorkAreaBase); + ApicAddress = (UINT64)GetLocalApicBaseAddress (); + Level1Page = FixedPcdGet32 (PcdOvmfSecApicPageTableBase); + PgTableMask = PAGING_4K_ADDRESS_MASK_64; + PgTableMask &= ~SevEsWorkArea->EncryptionMask; + + Cr3 = AsmReadCr3 (); + Level4Entry = (VOID *)(UINTN)(Cr3 & PgTableMask); + Level4Entry += (UINTN)BitFieldRead64 (ApicAddress, 39, 47); + + Level3Entry = (VOID *)(UINTN)(Level4Entry->Uint64 & PgTableMask); + Level3Entry += (UINTN)BitFieldRead64 (ApicAddress, 30, 38); + + Level2Entry = (VOID *)(UINTN)(Level3Entry->Uint64 & PgTableMask); + Level2Entry += (UINTN)BitFieldRead64 (ApicAddress, 21, 29); + + // + // Get memory address including encryption bit + // + Level1Address = Level2Entry->Uint64 & PgTableMask; + Level1Entry = (VOID *)(UINTN)Level1Page; + Level1Flags = BitFieldRead64 (Level2Entry->Uint64, 0, 11); + Level1Flags &= IA32_PG_P | IA32_PG_RW; + for (PteIndex = 0; PteIndex < 512; PteIndex++, Level1Entry++, Level1Address += SIZE_4KB) { + Level1Entry->Uint64 = Level1Address | Level1Flags; + + if (Level1Address != ApicAddress) { + Level1Entry->Uint64 |= SevEsWorkArea->EncryptionMask; + } + } + + Level2Entry->Uint64 = (UINT64)(UINTN)Level1Page | IA32_PG_P | IA32_PG_RW; + + CpuFlushTlb (); +} diff --git a/OvmfPkg/Sec/AmdSev.h b/OvmfPkg/Sec/AmdSev.h index f75877096e..c5ab0d5a0b 100644 --- a/OvmfPkg/Sec/AmdSev.h +++ b/OvmfPkg/Sec/AmdSev.h @@ -91,4 +91,18 @@ SevSnpIsEnabled ( VOID ); +/** + Map MMIO regions unencrypted if SEV-ES is active. + + During early booting, page table entries default to having the encryption bit + set for SEV-ES/SEV-SNP guests. In cases where there is MMIO to an address, the + encryption bit should be cleared. Clear it here for any known MMIO accesses + during SEC, which is currently just the APIC base address. + +**/ +VOID +SecMapApicBaseUnencrypted ( + VOID + ); + #endif diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c index a30d4ce09e..60dfa61842 100644 --- a/OvmfPkg/Sec/SecMain.c +++ b/OvmfPkg/Sec/SecMain.c @@ -938,6 +938,7 @@ SecCoreStartupWithStack ( // interrupts before initializing the Debug Agent and the debug timer is // enabled. // + SecMapApicBaseUnencrypted (); InitializeApicTimer (0, MAX_UINT32, TRUE, 5); DisableApicTimerInterrupt (); diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf index dca932a474..7b93b4e7d0 100644 --- a/OvmfPkg/Sec/SecMain.inf +++ b/OvmfPkg/Sec/SecMain.inf @@ -83,6 +83,8 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecApicPageTableSize [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire -- 2.25.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118176): https://edk2.groups.io/g/devel/message/118176 Mute This Topic: https://groups.io/mt/105698125/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-