2 Initialize Secure Encrypted Virtualization (SEV) support
4 Copyright (c) 2017 - 2020, 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/Msr.h>
21 #include <Register/Intel/SmramSaveStateMap.h>
27 Initialize SEV-ES support if running as an SEV-ES guest.
37 PHYSICAL_ADDRESS GhcbBasePa
;
39 UINT8
*GhcbBackupBase
;
40 UINT8
*GhcbBackupPages
;
41 UINTN GhcbBackupPageCount
;
42 SEV_ES_PER_CPU_DATA
*SevEsData
;
44 RETURN_STATUS PcdStatus
, DecryptStatus
;
48 if (!MemEncryptSevEsIsEnabled ()) {
52 PcdStatus
= PcdSetBoolS (PcdSevEsIsEnabled
, TRUE
);
53 ASSERT_RETURN_ERROR (PcdStatus
);
56 // Allocate GHCB and per-CPU variable pages.
57 // Since the pages must survive across the UEFI to OS transition
58 // make them reserved.
60 GhcbPageCount
= mMaxCpuCount
* 2;
61 GhcbBase
= AllocateReservedPages (GhcbPageCount
);
62 ASSERT (GhcbBase
!= NULL
);
64 GhcbBasePa
= (PHYSICAL_ADDRESS
)(UINTN
) GhcbBase
;
67 // Each vCPU gets two consecutive pages, the first is the GHCB and the
68 // second is the per-CPU variable page. Loop through the allocation and
69 // only clear the encryption mask for the GHCB pages.
71 for (PageCount
= 0; PageCount
< GhcbPageCount
; PageCount
+= 2) {
72 DecryptStatus
= MemEncryptSevClearPageEncMask (
74 GhcbBasePa
+ EFI_PAGES_TO_SIZE (PageCount
),
78 ASSERT_RETURN_ERROR (DecryptStatus
);
81 ZeroMem (GhcbBase
, EFI_PAGES_TO_SIZE (GhcbPageCount
));
83 PcdStatus
= PcdSet64S (PcdGhcbBase
, GhcbBasePa
);
84 ASSERT_RETURN_ERROR (PcdStatus
);
85 PcdStatus
= PcdSet64S (PcdGhcbSize
, EFI_PAGES_TO_SIZE (GhcbPageCount
));
86 ASSERT_RETURN_ERROR (PcdStatus
);
89 "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
90 (UINT64
)GhcbPageCount
, GhcbBase
));
93 // Allocate #VC recursion backup pages. The number of backup pages needed is
94 // one less than the maximum VC count.
96 GhcbBackupPageCount
= mMaxCpuCount
* (VMGEXIT_MAXIMUM_VC_COUNT
- 1);
97 GhcbBackupBase
= AllocatePages (GhcbBackupPageCount
);
98 ASSERT (GhcbBackupBase
!= NULL
);
100 GhcbBackupPages
= GhcbBackupBase
;
101 for (PageCount
= 1; PageCount
< GhcbPageCount
; PageCount
+= 2) {
103 (SEV_ES_PER_CPU_DATA
*)(GhcbBase
+ EFI_PAGES_TO_SIZE (PageCount
));
104 SevEsData
->GhcbBackupPages
= GhcbBackupPages
;
106 GhcbBackupPages
+= EFI_PAGE_SIZE
* (VMGEXIT_MAXIMUM_VC_COUNT
- 1);
110 "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",
111 (UINT64
)GhcbBackupPageCount
, GhcbBackupBase
));
113 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, GhcbBasePa
);
116 // The SEV support will clear the C-bit from non-RAM areas. The early GDT
117 // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
118 // will be read as un-encrypted even though it was created before the C-bit
119 // was cleared (encrypted). This will result in a failure to be able to
120 // handle the exception.
124 Gdt
= AllocatePages (EFI_SIZE_TO_PAGES ((UINTN
) Gdtr
.Limit
+ 1));
125 ASSERT (Gdt
!= NULL
);
127 CopyMem (Gdt
, (VOID
*) Gdtr
.Base
, Gdtr
.Limit
+ 1);
128 Gdtr
.Base
= (UINTN
) Gdt
;
129 AsmWriteGdtr (&Gdtr
);
134 Function checks if SEV support is available, if present then it sets
135 the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
143 UINT64 EncryptionMask
;
144 RETURN_STATUS PcdStatus
;
147 // Check if SEV is enabled
149 if (!MemEncryptSevIsEnabled ()) {
154 // Set Memory Encryption Mask PCD
156 EncryptionMask
= MemEncryptSevGetEncryptionMask ();
157 PcdStatus
= PcdSet64S (PcdPteMemoryEncryptionAddressOrMask
, EncryptionMask
);
158 ASSERT_RETURN_ERROR (PcdStatus
);
160 DEBUG ((DEBUG_INFO
, "SEV is enabled (mask 0x%lx)\n", EncryptionMask
));
163 // Set Pcd to Deny the execution of option ROM when security
166 PcdStatus
= PcdSet32S (PcdOptionRomImageVerificationPolicy
, 0x4);
167 ASSERT_RETURN_ERROR (PcdStatus
);
170 // When SMM is required, cover the pages containing the initial SMRAM Save
171 // State Map with a memory allocation HOB:
173 // There's going to be a time interval between our decrypting those pages for
174 // SMBASE relocation and re-encrypting the same pages after SMBASE
175 // relocation. We shall ensure that the DXE phase stay away from those pages
176 // until after re-encryption, in order to prevent an information leak to the
179 if (FeaturePcdGet (PcdSmmSmramRequire
) && (mBootMode
!= BOOT_ON_S3_RESUME
)) {
180 RETURN_STATUS LocateMapStatus
;
184 LocateMapStatus
= MemEncryptSevLocateInitialSmramSaveStateMapPages (
188 ASSERT_RETURN_ERROR (LocateMapStatus
);
190 if (mQ35SmramAtDefaultSmbase
) {
192 // The initial SMRAM Save State Map has been covered as part of a larger
193 // reserved memory allocation in InitializeRamRegions().
195 ASSERT (SMM_DEFAULT_SMBASE
<= MapPagesBase
);
197 (MapPagesBase
+ EFI_PAGES_TO_SIZE (MapPagesCount
) <=
198 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
)
201 BuildMemoryAllocationHob (
202 MapPagesBase
, // BaseAddress
203 EFI_PAGES_TO_SIZE (MapPagesCount
), // Length
204 EfiBootServicesData
// MemoryType
210 // Check and perform SEV-ES initialization if required.
212 AmdSevEsInitialize ();