/**@file\r
Initialize Secure Encrypted Virtualization (SEV) support\r
\r
- Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>\r
+ Copyright (c) 2017 - 2020, Advanced Micro Devices. All rights reserved.<BR>\r
\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
// The package level header files this module uses\r
//\r
#include <IndustryStandard/Q35MchIch9.h>\r
+#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/HobLib.h>\r
#include <Library/MemEncryptSevLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
#include <Library/PcdLib.h>\r
#include <PiPei.h>\r
-#include <Register/Amd/Cpuid.h>\r
-#include <Register/Cpuid.h>\r
+#include <Register/Amd/Msr.h>\r
#include <Register/Intel/SmramSaveStateMap.h>\r
\r
#include "Platform.h"\r
VOID\r
)\r
{\r
- RETURN_STATUS PcdStatus;\r
+ UINT8 *GhcbBase;\r
+ PHYSICAL_ADDRESS GhcbBasePa;\r
+ UINTN GhcbPageCount;\r
+ UINT8 *GhcbBackupBase;\r
+ UINT8 *GhcbBackupPages;\r
+ UINTN GhcbBackupPageCount;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+ UINTN PageCount;\r
+ RETURN_STATUS PcdStatus, DecryptStatus;\r
+ IA32_DESCRIPTOR Gdtr;\r
+ VOID *Gdt;\r
\r
if (!MemEncryptSevEsIsEnabled ()) {\r
return;\r
\r
PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);\r
ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+ //\r
+ // Allocate GHCB and per-CPU variable pages.\r
+ // Since the pages must survive across the UEFI to OS transition\r
+ // make them reserved.\r
+ //\r
+ GhcbPageCount = mMaxCpuCount * 2;\r
+ GhcbBase = AllocateReservedPages (GhcbPageCount);\r
+ ASSERT (GhcbBase != NULL);\r
+\r
+ GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN)GhcbBase;\r
+\r
+ //\r
+ // Each vCPU gets two consecutive pages, the first is the GHCB and the\r
+ // second is the per-CPU variable page. Loop through the allocation and\r
+ // only clear the encryption mask for the GHCB pages.\r
+ //\r
+ for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {\r
+ DecryptStatus = MemEncryptSevClearPageEncMask (\r
+ 0,\r
+ GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),\r
+ 1\r
+ );\r
+ ASSERT_RETURN_ERROR (DecryptStatus);\r
+ }\r
+\r
+ ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));\r
+\r
+ PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+ PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",\r
+ (UINT64)GhcbPageCount,\r
+ GhcbBase\r
+ ));\r
+\r
+ //\r
+ // Allocate #VC recursion backup pages. The number of backup pages needed is\r
+ // one less than the maximum VC count.\r
+ //\r
+ GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1);\r
+ GhcbBackupBase = AllocatePages (GhcbBackupPageCount);\r
+ ASSERT (GhcbBackupBase != NULL);\r
+\r
+ GhcbBackupPages = GhcbBackupBase;\r
+ for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) {\r
+ SevEsData =\r
+ (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount));\r
+ SevEsData->GhcbBackupPages = GhcbBackupPages;\r
+\r
+ GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1);\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",\r
+ (UINT64)GhcbBackupPageCount,\r
+ GhcbBackupBase\r
+ ));\r
+\r
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);\r
+\r
+ //\r
+ // The SEV support will clear the C-bit from non-RAM areas. The early GDT\r
+ // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT\r
+ // will be read as un-encrypted even though it was created before the C-bit\r
+ // was cleared (encrypted). This will result in a failure to be able to\r
+ // handle the exception.\r
+ //\r
+ AsmReadGdtr (&Gdtr);\r
+\r
+ Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)Gdtr.Limit + 1));\r
+ ASSERT (Gdt != NULL);\r
+\r
+ CopyMem (Gdt, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
+ Gdtr.Base = (UINTN)Gdt;\r
+ AsmWriteGdtr (&Gdtr);\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx;\r
- UINT64 EncryptionMask;\r
- RETURN_STATUS PcdStatus;\r
+ UINT64 EncryptionMask;\r
+ RETURN_STATUS PcdStatus;\r
\r
//\r
// Check if SEV is enabled\r
return;\r
}\r
\r
- //\r
- // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)\r
- //\r
- AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);\r
- EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits);\r
-\r
//\r
// Set Memory Encryption Mask PCD\r
//\r
- PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);\r
+ EncryptionMask = MemEncryptSevGetEncryptionMask ();\r
+ PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);\r
ASSERT_RETURN_ERROR (PcdStatus);\r
\r
DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));\r
// hypervisor.\r
//\r
if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {\r
- RETURN_STATUS LocateMapStatus;\r
- UINTN MapPagesBase;\r
- UINTN MapPagesCount;\r
+ RETURN_STATUS LocateMapStatus;\r
+ UINTN MapPagesBase;\r
+ UINTN MapPagesCount;\r
\r
LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (\r
&MapPagesBase,\r