2 Initialize Secure Encrypted Virtualization (SEV) support
4 Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 // The package level header files this module uses
12 #include <IndustryStandard/Q35MchIch9.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/HobLib.h>
16 #include <Library/MemEncryptSevLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
20 #include <Register/Amd/Cpuid.h>
21 #include <Register/Amd/Msr.h>
22 #include <Register/Cpuid.h>
23 #include <Register/Intel/SmramSaveStateMap.h>
29 Initialize SEV-ES support if running as an SEV-ES guest.
39 PHYSICAL_ADDRESS GhcbBasePa
;
40 UINTN GhcbPageCount
, PageCount
;
41 RETURN_STATUS PcdStatus
, DecryptStatus
;
45 if (!MemEncryptSevEsIsEnabled ()) {
49 PcdStatus
= PcdSetBoolS (PcdSevEsIsEnabled
, TRUE
);
50 ASSERT_RETURN_ERROR (PcdStatus
);
53 // Allocate GHCB and per-CPU variable pages.
55 GhcbPageCount
= mMaxCpuCount
* 2;
56 GhcbBase
= AllocatePages (GhcbPageCount
);
57 ASSERT (GhcbBase
!= NULL
);
59 GhcbBasePa
= (PHYSICAL_ADDRESS
)(UINTN
) GhcbBase
;
62 // Each vCPU gets two consecutive pages, the first is the GHCB and the
63 // second is the per-CPU variable page. Loop through the allocation and
64 // only clear the encryption mask for the GHCB pages.
66 for (PageCount
= 0; PageCount
< GhcbPageCount
; PageCount
+= 2) {
67 DecryptStatus
= MemEncryptSevClearPageEncMask (
69 GhcbBasePa
+ EFI_PAGES_TO_SIZE (PageCount
),
73 ASSERT_RETURN_ERROR (DecryptStatus
);
76 ZeroMem (GhcbBase
, EFI_PAGES_TO_SIZE (GhcbPageCount
));
78 PcdStatus
= PcdSet64S (PcdGhcbBase
, GhcbBasePa
);
79 ASSERT_RETURN_ERROR (PcdStatus
);
80 PcdStatus
= PcdSet64S (PcdGhcbSize
, EFI_PAGES_TO_SIZE (GhcbPageCount
));
81 ASSERT_RETURN_ERROR (PcdStatus
);
84 "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
85 (UINT64
)GhcbPageCount
, GhcbBase
));
87 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, GhcbBasePa
);
90 // The SEV support will clear the C-bit from non-RAM areas. The early GDT
91 // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
92 // will be read as un-encrypted even though it was created before the C-bit
93 // was cleared (encrypted). This will result in a failure to be able to
94 // handle the exception.
98 Gdt
= AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
) Gdtr
.Limit
+ 1));
101 CopyMem (Gdt
, (VOID
*) Gdtr
.Base
, Gdtr
.Limit
+ 1);
102 Gdtr
.Base
= (UINTN
) Gdt
;
103 AsmWriteGdtr (&Gdtr
);
108 Function checks if SEV support is available, if present then it sets
109 the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
117 CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx
;
118 UINT64 EncryptionMask
;
119 RETURN_STATUS PcdStatus
;
122 // Check if SEV is enabled
124 if (!MemEncryptSevIsEnabled ()) {
129 // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)
131 AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO
, NULL
, &Ebx
.Uint32
, NULL
, NULL
);
132 EncryptionMask
= LShiftU64 (1, Ebx
.Bits
.PtePosBits
);
135 // Set Memory Encryption Mask PCD
137 PcdStatus
= PcdSet64S (PcdPteMemoryEncryptionAddressOrMask
, EncryptionMask
);
138 ASSERT_RETURN_ERROR (PcdStatus
);
140 DEBUG ((DEBUG_INFO
, "SEV is enabled (mask 0x%lx)\n", EncryptionMask
));
143 // Set Pcd to Deny the execution of option ROM when security
146 PcdStatus
= PcdSet32S (PcdOptionRomImageVerificationPolicy
, 0x4);
147 ASSERT_RETURN_ERROR (PcdStatus
);
150 // When SMM is required, cover the pages containing the initial SMRAM Save
151 // State Map with a memory allocation HOB:
153 // There's going to be a time interval between our decrypting those pages for
154 // SMBASE relocation and re-encrypting the same pages after SMBASE
155 // relocation. We shall ensure that the DXE phase stay away from those pages
156 // until after re-encryption, in order to prevent an information leak to the
159 if (FeaturePcdGet (PcdSmmSmramRequire
) && (mBootMode
!= BOOT_ON_S3_RESUME
)) {
160 RETURN_STATUS LocateMapStatus
;
164 LocateMapStatus
= MemEncryptSevLocateInitialSmramSaveStateMapPages (
168 ASSERT_RETURN_ERROR (LocateMapStatus
);
170 if (mQ35SmramAtDefaultSmbase
) {
172 // The initial SMRAM Save State Map has been covered as part of a larger
173 // reserved memory allocation in InitializeRamRegions().
175 ASSERT (SMM_DEFAULT_SMBASE
<= MapPagesBase
);
177 (MapPagesBase
+ EFI_PAGES_TO_SIZE (MapPagesCount
) <=
178 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
)
181 BuildMemoryAllocationHob (
182 MapPagesBase
, // BaseAddress
183 EFI_PAGES_TO_SIZE (MapPagesCount
), // Length
184 EfiBootServicesData
// MemoryType
190 // Check and perform SEV-ES initialization if required.
192 AmdSevEsInitialize ();