]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Sec/AmdSev.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Sec / AmdSev.c
CommitLineData
2ddacfb6
BS
1/** @file\r
2 File defines the Sec routines for the AMD SEV\r
3\r
4 Copyright (c) 2021, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include <Library/BaseLib.h>\r
11#include <Library/DebugLib.h>\r
12#include <Library/MemEncryptSevLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14#include <Register/Amd/Ghcb.h>\r
15#include <Register/Amd/Msr.h>\r
16\r
17#include "AmdSev.h"\r
18\r
19/**\r
20 Handle an SEV-ES/GHCB protocol check failure.\r
21\r
22 Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest\r
23 wishes to be terminated.\r
24\r
25 @param[in] ReasonCode Reason code to provide to the hypervisor for the\r
26 termination request.\r
27\r
28**/\r
29VOID\r
30SevEsProtocolFailure (\r
31 IN UINT8 ReasonCode\r
32 )\r
33{\r
34 MSR_SEV_ES_GHCB_REGISTER Msr;\r
35\r
36 //\r
37 // Use the GHCB MSR Protocol to request termination by the hypervisor\r
38 //\r
39 Msr.GhcbPhysicalAddress = 0;\r
40 Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;\r
41 Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;\r
42 Msr.GhcbTerminate.ReasonCode = ReasonCode;\r
43 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
44\r
45 AsmVmgExit ();\r
46\r
47 ASSERT (FALSE);\r
48 CpuDeadLoop ();\r
49}\r
50\r
7c3b2892
BS
51/**\r
52 Determine if SEV-SNP is active.\r
53\r
54 @retval TRUE SEV-SNP is enabled\r
55 @retval FALSE SEV-SNP is not enabled\r
56\r
57**/\r
7c3b2892
BS
58BOOLEAN\r
59SevSnpIsEnabled (\r
60 VOID\r
61 )\r
62{\r
63 MSR_SEV_STATUS_REGISTER Msr;\r
64\r
65 //\r
66 // Read the SEV_STATUS MSR to determine whether SEV-SNP is active.\r
67 //\r
68 Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);\r
69\r
70 //\r
71 // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)\r
72 //\r
73 if (Msr.Bits.SevSnpBit) {\r
74 return TRUE;\r
75 }\r
76\r
77 return FALSE;\r
78}\r
79\r
80/**\r
81 Register the GHCB GPA\r
82\r
83*/\r
84STATIC\r
85VOID\r
86SevSnpGhcbRegister (\r
87 EFI_PHYSICAL_ADDRESS Address\r
88 )\r
89{\r
90 MSR_SEV_ES_GHCB_REGISTER Msr;\r
91\r
92 //\r
93 // Use the GHCB MSR Protocol to request to register the GPA.\r
94 //\r
95 Msr.GhcbPhysicalAddress = Address & ~EFI_PAGE_MASK;\r
96 Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;\r
97 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
98\r
99 AsmVmgExit ();\r
100\r
101 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
102\r
103 //\r
104 // If hypervisor responded with a different GPA than requested then fail.\r
105 //\r
106 if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||\r
107 ((Msr.GhcbPhysicalAddress & ~EFI_PAGE_MASK) != Address))\r
108 {\r
109 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);\r
110 }\r
111}\r
112\r
113/**\r
114 Verify that Hypervisor supports the SNP feature.\r
115\r
116 */\r
117STATIC\r
118BOOLEAN\r
119HypervisorSnpFeatureCheck (\r
120 VOID\r
121 )\r
122{\r
123 MSR_SEV_ES_GHCB_REGISTER Msr;\r
124 UINT64 Features;\r
125\r
126 //\r
127 // Use the GHCB MSR Protocol to query the hypervisor capabilities\r
128 //\r
129 Msr.GhcbPhysicalAddress = 0;\r
130 Msr.GhcbHypervisorFeatures.Function = GHCB_HYPERVISOR_FEATURES_REQUEST;\r
131 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
132\r
133 AsmVmgExit ();\r
134\r
135 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
136\r
137 Features = RShiftU64 (Msr.GhcbPhysicalAddress, 12);\r
138\r
139 if ((Msr.GhcbHypervisorFeatures.Function != GHCB_HYPERVISOR_FEATURES_RESPONSE) ||\r
140 (!(Features & GHCB_HV_FEATURES_SNP)))\r
141 {\r
142 return FALSE;\r
143 }\r
144\r
145 return TRUE;\r
146}\r
147\r
2ddacfb6
BS
148/**\r
149 Validate the SEV-ES/GHCB protocol level.\r
150\r
151 Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor\r
152 and the guest intersect. If they don't intersect, request termination.\r
153\r
154**/\r
155VOID\r
156SevEsProtocolCheck (\r
157 VOID\r
158 )\r
159{\r
160 MSR_SEV_ES_GHCB_REGISTER Msr;\r
161 GHCB *Ghcb;\r
162\r
163 //\r
164 // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for\r
165 // protocol checking\r
166 //\r
167 Msr.GhcbPhysicalAddress = 0;\r
168 Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;\r
169 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
170\r
171 AsmVmgExit ();\r
172\r
173 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
174\r
175 if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {\r
176 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);\r
177 }\r
178\r
179 if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {\r
180 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);\r
181 }\r
182\r
183 if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||\r
184 (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN))\r
185 {\r
186 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);\r
187 }\r
188\r
7c3b2892
BS
189 //\r
190 // We cannot use the MemEncryptSevSnpIsEnabled () because the\r
191 // ProcessLibraryConstructorList () is not called yet.\r
192 //\r
193 if (SevSnpIsEnabled ()) {\r
194 //\r
195 // Check if hypervisor supports the SNP feature\r
196 //\r
197 if (!HypervisorSnpFeatureCheck ()) {\r
198 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);\r
199 }\r
200\r
201 //\r
202 // Unlike the SEV-ES guest, the SNP requires that GHCB GPA must be\r
203 // registered with the Hypervisor before the use. This can be done\r
204 // using the new VMGEXIT defined in the GHCB v2. Register the GPA\r
205 // before it is used.\r
206 //\r
207 SevSnpGhcbRegister ((EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase));\r
208 }\r
209\r
2ddacfb6
BS
210 //\r
211 // SEV-ES protocol checking succeeded, set the initial GHCB address\r
212 //\r
213 Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);\r
214 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
215\r
216 Ghcb = Msr.Ghcb;\r
2fe8edfe 217 SetMem (Ghcb, FixedPcdGet32 (PcdOvmfSecGhcbSize), 0);\r
2ddacfb6
BS
218\r
219 //\r
220 // Set the version to the maximum that can be supported\r
221 //\r
222 Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);\r
223 Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;\r
224}\r
225\r
226/**\r
227 Determine if the SEV is active.\r
228\r
229 During the early booting, GuestType is set in the work area. Verify that it\r
230 is an SEV guest.\r
231\r
232 @retval TRUE SEV is enabled\r
233 @retval FALSE SEV is not enabled\r
234\r
235**/\r
236BOOLEAN\r
237IsSevGuest (\r
238 VOID\r
239 )\r
240{\r
241 OVMF_WORK_AREA *WorkArea;\r
242\r
243 //\r
244 // Ensure that the size of the Confidential Computing work area header\r
245 // is same as what is provided through a fixed PCD.\r
246 //\r
247 ASSERT (\r
248 (UINTN)FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader) ==\r
249 sizeof (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER)\r
250 );\r
251\r
252 WorkArea = (OVMF_WORK_AREA *)FixedPcdGet32 (PcdOvmfWorkAreaBase);\r
253\r
d020ac55 254 return ((WorkArea != NULL) && (WorkArea->Header.GuestType == CcGuestTypeAmdSev));\r
2ddacfb6
BS
255}\r
256\r
257/**\r
258 Determine if SEV-ES is active.\r
259\r
260 During early booting, SEV-ES support code will set a flag to indicate that\r
261 SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES\r
262 is enabled.\r
263\r
264 @retval TRUE SEV-ES is enabled\r
265 @retval FALSE SEV-ES is not enabled\r
266\r
267**/\r
268BOOLEAN\r
269SevEsIsEnabled (\r
270 VOID\r
271 )\r
272{\r
273 SEC_SEV_ES_WORK_AREA *SevEsWorkArea;\r
274\r
275 if (!IsSevGuest ()) {\r
276 return FALSE;\r
277 }\r
278\r
279 SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *)FixedPcdGet32 (PcdSevEsWorkAreaBase);\r
280\r
63c50d3f 281 return ((SevEsWorkArea->SevStatusMsrValue & BIT1) != 0);\r
2ddacfb6 282}\r
202fb22b
BS
283\r
284/**\r
285 Validate System RAM used for decompressing the PEI and DXE firmware volumes\r
286 when SEV-SNP is active. The PCDs SecValidatedStart and SecValidatedEnd are\r
1ef86f12 287 set in OvmfPkg/Include/Fdf/FvmainCompactScratchEnd.fdf.inc.\r
202fb22b
BS
288\r
289**/\r
290VOID\r
291SecValidateSystemRam (\r
292 VOID\r
293 )\r
294{\r
295 PHYSICAL_ADDRESS Start, End;\r
296\r
297 if (IsSevGuest () && SevSnpIsEnabled ()) {\r
298 Start = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecValidatedStart);\r
299 End = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecValidatedEnd);\r
300\r
301 MemEncryptSevSnpPreValidateSystemRam (Start, EFI_SIZE_TO_PAGES ((UINTN)(End - Start)));\r
302 }\r
303}\r