]>
Commit | Line | Data |
---|---|---|
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 | |
29 | VOID\r | |
30 | SevEsProtocolFailure (\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 |
58 | BOOLEAN\r |
59 | SevSnpIsEnabled (\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 | |
84 | STATIC\r | |
85 | VOID\r | |
86 | SevSnpGhcbRegister (\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 | |
117 | STATIC\r | |
118 | BOOLEAN\r | |
119 | HypervisorSnpFeatureCheck (\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 | |
155 | VOID\r | |
156 | SevEsProtocolCheck (\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 | |
236 | BOOLEAN\r | |
237 | IsSevGuest (\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 | |
254 | return ((WorkArea != NULL) && (WorkArea->Header.GuestType == GUEST_TYPE_AMD_SEV));\r | |
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 | |
268 | BOOLEAN\r | |
269 | SevEsIsEnabled (\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 | |
287 | set in OvmfPkg/FvmainCompactScratchEnd.fdf.inc.\r | |
288 | \r | |
289 | **/\r | |
290 | VOID\r | |
291 | SecValidateSystemRam (\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 |