X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FPlatformPei%2FAmdSev.c;h=3991edfd1e82b1edfe4f6e1a59f6eeeaec778227;hb=ac0a286f4d747a4c6c603a7b225917293cbe1e9f;hp=4dc5340caa7a2814e8914ecfa7a3a6deb12acbd8;hpb=cf845a749a1cc25c6b63586de08ea69cd8832bc9;p=mirror_edk2.git diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c index 4dc5340caa..3991edfd1e 100644 --- a/OvmfPkg/PlatformPei/AmdSev.c +++ b/OvmfPkg/PlatformPei/AmdSev.c @@ -1,7 +1,7 @@ /**@file Initialize Secure Encrypted Virtualization (SEV) support - Copyright (c) 2017, Advanced Micro Devices. All rights reserved.
+ Copyright (c) 2017 - 2020, Advanced Micro Devices. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -10,13 +10,14 @@ // The package level header files this module uses // #include +#include #include #include #include +#include #include #include -#include -#include +#include #include #include "Platform.h" @@ -32,7 +33,17 @@ AmdSevEsInitialize ( VOID ) { - RETURN_STATUS PcdStatus; + UINT8 *GhcbBase; + PHYSICAL_ADDRESS GhcbBasePa; + UINTN GhcbPageCount; + UINT8 *GhcbBackupBase; + UINT8 *GhcbBackupPages; + UINTN GhcbBackupPageCount; + SEV_ES_PER_CPU_DATA *SevEsData; + UINTN PageCount; + RETURN_STATUS PcdStatus, DecryptStatus; + IA32_DESCRIPTOR Gdtr; + VOID *Gdt; if (!MemEncryptSevEsIsEnabled ()) { return; @@ -40,6 +51,87 @@ AmdSevEsInitialize ( PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE); ASSERT_RETURN_ERROR (PcdStatus); + + // + // Allocate GHCB and per-CPU variable pages. + // Since the pages must survive across the UEFI to OS transition + // make them reserved. + // + GhcbPageCount = mMaxCpuCount * 2; + GhcbBase = AllocateReservedPages (GhcbPageCount); + ASSERT (GhcbBase != NULL); + + GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN)GhcbBase; + + // + // Each vCPU gets two consecutive pages, the first is the GHCB and the + // second is the per-CPU variable page. Loop through the allocation and + // only clear the encryption mask for the GHCB pages. + // + for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) { + DecryptStatus = MemEncryptSevClearPageEncMask ( + 0, + GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount), + 1 + ); + ASSERT_RETURN_ERROR (DecryptStatus); + } + + ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount)); + + PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa); + ASSERT_RETURN_ERROR (PcdStatus); + PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount)); + ASSERT_RETURN_ERROR (PcdStatus); + + DEBUG (( + DEBUG_INFO, + "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n", + (UINT64)GhcbPageCount, + GhcbBase + )); + + // + // Allocate #VC recursion backup pages. The number of backup pages needed is + // one less than the maximum VC count. + // + GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1); + GhcbBackupBase = AllocatePages (GhcbBackupPageCount); + ASSERT (GhcbBackupBase != NULL); + + GhcbBackupPages = GhcbBackupBase; + for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) { + SevEsData = + (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount)); + SevEsData->GhcbBackupPages = GhcbBackupPages; + + GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1); + } + + DEBUG (( + DEBUG_INFO, + "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n", + (UINT64)GhcbBackupPageCount, + GhcbBackupBase + )); + + AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa); + + // + // The SEV support will clear the C-bit from non-RAM areas. The early GDT + // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT + // will be read as un-encrypted even though it was created before the C-bit + // was cleared (encrypted). This will result in a failure to be able to + // handle the exception. + // + AsmReadGdtr (&Gdtr); + + Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)Gdtr.Limit + 1)); + ASSERT (Gdt != NULL); + + CopyMem (Gdt, (VOID *)Gdtr.Base, Gdtr.Limit + 1); + Gdtr.Base = (UINTN)Gdt; + AsmWriteGdtr (&Gdtr); } /** @@ -53,9 +145,8 @@ AmdSevInitialize ( VOID ) { - CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx; - UINT64 EncryptionMask; - RETURN_STATUS PcdStatus; + UINT64 EncryptionMask; + RETURN_STATUS PcdStatus; // // Check if SEV is enabled @@ -64,16 +155,11 @@ AmdSevInitialize ( return; } - // - // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position) - // - AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL); - EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits); - // // Set Memory Encryption Mask PCD // - PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask); + EncryptionMask = MemEncryptSevGetEncryptionMask (); + PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask); ASSERT_RETURN_ERROR (PcdStatus); DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask)); @@ -96,9 +182,9 @@ AmdSevInitialize ( // hypervisor. // if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) { - RETURN_STATUS LocateMapStatus; - UINTN MapPagesBase; - UINTN MapPagesCount; + RETURN_STATUS LocateMapStatus; + UINTN MapPagesBase; + UINTN MapPagesCount; LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages ( &MapPagesBase,