]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformPei/AmdSev.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / PlatformPei / AmdSev.c
1 /**@file
2 Initialize Secure Encrypted Virtualization (SEV) support
3
4 Copyright (c) 2017 - 2020, Advanced Micro Devices. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9 //
10 // The package level header files this module uses
11 //
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>
19 #include <PiPei.h>
20 #include <Register/Amd/Msr.h>
21 #include <Register/Intel/SmramSaveStateMap.h>
22
23 #include "Platform.h"
24
25 /**
26
27 Initialize SEV-ES support if running as an SEV-ES guest.
28
29 **/
30 STATIC
31 VOID
32 AmdSevEsInitialize (
33 VOID
34 )
35 {
36 UINT8 *GhcbBase;
37 PHYSICAL_ADDRESS GhcbBasePa;
38 UINTN GhcbPageCount;
39 UINT8 *GhcbBackupBase;
40 UINT8 *GhcbBackupPages;
41 UINTN GhcbBackupPageCount;
42 SEV_ES_PER_CPU_DATA *SevEsData;
43 UINTN PageCount;
44 RETURN_STATUS PcdStatus, DecryptStatus;
45 IA32_DESCRIPTOR Gdtr;
46 VOID *Gdt;
47
48 if (!MemEncryptSevEsIsEnabled ()) {
49 return;
50 }
51
52 PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
53 ASSERT_RETURN_ERROR (PcdStatus);
54
55 //
56 // Allocate GHCB and per-CPU variable pages.
57 // Since the pages must survive across the UEFI to OS transition
58 // make them reserved.
59 //
60 GhcbPageCount = mMaxCpuCount * 2;
61 GhcbBase = AllocateReservedPages (GhcbPageCount);
62 ASSERT (GhcbBase != NULL);
63
64 GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN)GhcbBase;
65
66 //
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.
70 //
71 for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {
72 DecryptStatus = MemEncryptSevClearPageEncMask (
73 0,
74 GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),
75 1
76 );
77 ASSERT_RETURN_ERROR (DecryptStatus);
78 }
79
80 ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
81
82 PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
83 ASSERT_RETURN_ERROR (PcdStatus);
84 PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
85 ASSERT_RETURN_ERROR (PcdStatus);
86
87 DEBUG ((
88 DEBUG_INFO,
89 "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
90 (UINT64)GhcbPageCount,
91 GhcbBase
92 ));
93
94 //
95 // Allocate #VC recursion backup pages. The number of backup pages needed is
96 // one less than the maximum VC count.
97 //
98 GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
99 GhcbBackupBase = AllocatePages (GhcbBackupPageCount);
100 ASSERT (GhcbBackupBase != NULL);
101
102 GhcbBackupPages = GhcbBackupBase;
103 for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) {
104 SevEsData =
105 (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount));
106 SevEsData->GhcbBackupPages = GhcbBackupPages;
107
108 GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
109 }
110
111 DEBUG ((
112 DEBUG_INFO,
113 "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",
114 (UINT64)GhcbBackupPageCount,
115 GhcbBackupBase
116 ));
117
118 AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
119
120 //
121 // The SEV support will clear the C-bit from non-RAM areas. The early GDT
122 // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
123 // will be read as un-encrypted even though it was created before the C-bit
124 // was cleared (encrypted). This will result in a failure to be able to
125 // handle the exception.
126 //
127 AsmReadGdtr (&Gdtr);
128
129 Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)Gdtr.Limit + 1));
130 ASSERT (Gdt != NULL);
131
132 CopyMem (Gdt, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
133 Gdtr.Base = (UINTN)Gdt;
134 AsmWriteGdtr (&Gdtr);
135 }
136
137 /**
138
139 Function checks if SEV support is available, if present then it sets
140 the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
141
142 **/
143 VOID
144 AmdSevInitialize (
145 VOID
146 )
147 {
148 UINT64 EncryptionMask;
149 RETURN_STATUS PcdStatus;
150
151 //
152 // Check if SEV is enabled
153 //
154 if (!MemEncryptSevIsEnabled ()) {
155 return;
156 }
157
158 //
159 // Set Memory Encryption Mask PCD
160 //
161 EncryptionMask = MemEncryptSevGetEncryptionMask ();
162 PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);
163 ASSERT_RETURN_ERROR (PcdStatus);
164
165 DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));
166
167 //
168 // Set Pcd to Deny the execution of option ROM when security
169 // violation.
170 //
171 PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);
172 ASSERT_RETURN_ERROR (PcdStatus);
173
174 //
175 // When SMM is required, cover the pages containing the initial SMRAM Save
176 // State Map with a memory allocation HOB:
177 //
178 // There's going to be a time interval between our decrypting those pages for
179 // SMBASE relocation and re-encrypting the same pages after SMBASE
180 // relocation. We shall ensure that the DXE phase stay away from those pages
181 // until after re-encryption, in order to prevent an information leak to the
182 // hypervisor.
183 //
184 if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {
185 RETURN_STATUS LocateMapStatus;
186 UINTN MapPagesBase;
187 UINTN MapPagesCount;
188
189 LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (
190 &MapPagesBase,
191 &MapPagesCount
192 );
193 ASSERT_RETURN_ERROR (LocateMapStatus);
194
195 if (mQ35SmramAtDefaultSmbase) {
196 //
197 // The initial SMRAM Save State Map has been covered as part of a larger
198 // reserved memory allocation in InitializeRamRegions().
199 //
200 ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
201 ASSERT (
202 (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
203 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
204 );
205 } else {
206 BuildMemoryAllocationHob (
207 MapPagesBase, // BaseAddress
208 EFI_PAGES_TO_SIZE (MapPagesCount), // Length
209 EfiBootServicesData // MemoryType
210 );
211 }
212 }
213
214 //
215 // Check and perform SEV-ES initialization if required.
216 //
217 AmdSevEsInitialize ();
218 }