VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/Sec/AmdSev.c@ 105681

最後變更 在這個檔案從105681是 105670,由 vboxsync 提交於 4 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 8.6 KB
 
1/** @file
2 File defines the Sec routines for the AMD SEV
3
4 Copyright (c) 2021, Advanced Micro Devices, Inc. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include <Library/BaseLib.h>
11#include <Library/CpuLib.h>
12#include <Library/CpuPageTableLib.h>
13#include <Library/DebugLib.h>
14#include <Library/LocalApicLib.h>
15#include <Library/MemEncryptSevLib.h>
16#include <Library/BaseMemoryLib.h>
17#include <Register/Amd/Ghcb.h>
18#include <Register/Amd/Msr.h>
19
20#include "AmdSev.h"
21
22/**
23 Handle an SEV-ES/GHCB protocol check failure.
24
25 Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
26 wishes to be terminated.
27
28 @param[in] ReasonCode Reason code to provide to the hypervisor for the
29 termination request.
30
31**/
32VOID
33SevEsProtocolFailure (
34 IN UINT8 ReasonCode
35 )
36{
37 MSR_SEV_ES_GHCB_REGISTER Msr;
38
39 //
40 // Use the GHCB MSR Protocol to request termination by the hypervisor
41 //
42 Msr.GhcbPhysicalAddress = 0;
43 Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
44 Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
45 Msr.GhcbTerminate.ReasonCode = ReasonCode;
46 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
47
48 AsmVmgExit ();
49
50 ASSERT (FALSE);
51 CpuDeadLoop ();
52}
53
54/**
55 Determine if SEV-SNP is active.
56
57 @retval TRUE SEV-SNP is enabled
58 @retval FALSE SEV-SNP is not enabled
59
60**/
61BOOLEAN
62SevSnpIsEnabled (
63 VOID
64 )
65{
66 MSR_SEV_STATUS_REGISTER Msr;
67
68 //
69 // Read the SEV_STATUS MSR to determine whether SEV-SNP is active.
70 //
71 Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
72
73 //
74 // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
75 //
76 if (Msr.Bits.SevSnpBit) {
77 return TRUE;
78 }
79
80 return FALSE;
81}
82
83/**
84 Register the GHCB GPA
85
86*/
87STATIC
88VOID
89SevSnpGhcbRegister (
90 EFI_PHYSICAL_ADDRESS Address
91 )
92{
93 MSR_SEV_ES_GHCB_REGISTER Msr;
94
95 //
96 // Use the GHCB MSR Protocol to request to register the GPA.
97 //
98 Msr.GhcbPhysicalAddress = Address & ~EFI_PAGE_MASK;
99 Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
100 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
101
102 AsmVmgExit ();
103
104 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
105
106 //
107 // If hypervisor responded with a different GPA than requested then fail.
108 //
109 if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
110 ((Msr.GhcbPhysicalAddress & ~EFI_PAGE_MASK) != Address))
111 {
112 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
113 }
114}
115
116/**
117 Verify that Hypervisor supports the SNP feature.
118
119 */
120STATIC
121BOOLEAN
122HypervisorSnpFeatureCheck (
123 VOID
124 )
125{
126 MSR_SEV_ES_GHCB_REGISTER Msr;
127 UINT64 Features;
128
129 //
130 // Use the GHCB MSR Protocol to query the hypervisor capabilities
131 //
132 Msr.GhcbPhysicalAddress = 0;
133 Msr.GhcbHypervisorFeatures.Function = GHCB_HYPERVISOR_FEATURES_REQUEST;
134 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
135
136 AsmVmgExit ();
137
138 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
139
140 Features = RShiftU64 (Msr.GhcbPhysicalAddress, 12);
141
142 if ((Msr.GhcbHypervisorFeatures.Function != GHCB_HYPERVISOR_FEATURES_RESPONSE) ||
143 (!(Features & GHCB_HV_FEATURES_SNP)))
144 {
145 return FALSE;
146 }
147
148 return TRUE;
149}
150
151/**
152 Validate the SEV-ES/GHCB protocol level.
153
154 Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
155 and the guest intersect. If they don't intersect, request termination.
156
157**/
158VOID
159SevEsProtocolCheck (
160 VOID
161 )
162{
163 MSR_SEV_ES_GHCB_REGISTER Msr;
164 GHCB *Ghcb;
165
166 //
167 // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
168 // protocol checking
169 //
170 Msr.GhcbPhysicalAddress = 0;
171 Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;
172 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
173
174 AsmVmgExit ();
175
176 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
177
178 if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {
179 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
180 }
181
182 if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
183 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
184 }
185
186 if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
187 (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN))
188 {
189 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
190 }
191
192 //
193 // We cannot use the MemEncryptSevSnpIsEnabled () because the
194 // ProcessLibraryConstructorList () is not called yet.
195 //
196 if (SevSnpIsEnabled ()) {
197 //
198 // Check if hypervisor supports the SNP feature
199 //
200 if (!HypervisorSnpFeatureCheck ()) {
201 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
202 }
203
204 //
205 // Unlike the SEV-ES guest, the SNP requires that GHCB GPA must be
206 // registered with the Hypervisor before the use. This can be done
207 // using the new VMGEXIT defined in the GHCB v2. Register the GPA
208 // before it is used.
209 //
210 SevSnpGhcbRegister ((EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase));
211 }
212
213 //
214 // SEV-ES protocol checking succeeded, set the initial GHCB address
215 //
216 Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);
217 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
218
219 Ghcb = Msr.Ghcb;
220 SetMem (Ghcb, FixedPcdGet32 (PcdOvmfSecGhcbSize), 0);
221
222 //
223 // Set the version to the maximum that can be supported
224 //
225 Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
226 Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
227}
228
229/**
230 Determine if the SEV is active.
231
232 During the early booting, GuestType is set in the work area. Verify that it
233 is an SEV guest.
234
235 @retval TRUE SEV is enabled
236 @retval FALSE SEV is not enabled
237
238**/
239BOOLEAN
240IsSevGuest (
241 VOID
242 )
243{
244 OVMF_WORK_AREA *WorkArea;
245
246 //
247 // Ensure that the size of the Confidential Computing work area header
248 // is same as what is provided through a fixed PCD.
249 //
250 ASSERT (
251 (UINTN)FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader) ==
252 sizeof (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER)
253 );
254
255 WorkArea = (OVMF_WORK_AREA *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
256
257 return ((WorkArea != NULL) && (WorkArea->Header.GuestType == CcGuestTypeAmdSev));
258}
259
260/**
261 Determine if SEV-ES is active.
262
263 During early booting, SEV-ES support code will set a flag to indicate that
264 SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
265 is enabled.
266
267 @retval TRUE SEV-ES is enabled
268 @retval FALSE SEV-ES is not enabled
269
270**/
271BOOLEAN
272SevEsIsEnabled (
273 VOID
274 )
275{
276 SEC_SEV_ES_WORK_AREA *SevEsWorkArea;
277
278 if (!IsSevGuest ()) {
279 return FALSE;
280 }
281
282 SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *)FixedPcdGet32 (PcdSevEsWorkAreaBase);
283
284 return ((SevEsWorkArea->SevStatusMsrValue & BIT1) != 0);
285}
286
287/**
288 Validate System RAM used for decompressing the PEI and DXE firmware volumes
289 when SEV-SNP is active. The PCDs SecValidatedStart and SecValidatedEnd are
290 set in OvmfPkg/Include/Fdf/FvmainCompactScratchEnd.fdf.inc.
291
292**/
293VOID
294SecValidateSystemRam (
295 VOID
296 )
297{
298 PHYSICAL_ADDRESS Start, End;
299
300 if (IsSevGuest () && SevSnpIsEnabled ()) {
301 Start = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecValidatedStart);
302 End = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecValidatedEnd);
303
304 MemEncryptSevSnpPreValidateSystemRam (Start, EFI_SIZE_TO_PAGES ((UINTN)(End - Start)));
305 }
306}
307
308/**
309 Map known MMIO regions unencrypted if SEV-ES is active.
310
311 During early booting, page table entries default to having the encryption bit
312 set for SEV-ES/SEV-SNP guests. In cases where there is MMIO to an address, the
313 encryption bit should be cleared. Clear it here for any known MMIO accesses
314 during SEC, which is currently just the APIC base address.
315
316**/
317VOID
318SecMapApicBaseUnencrypted (
319 VOID
320 )
321{
322 PHYSICAL_ADDRESS Cr3;
323 UINT64 ApicAddress;
324 VOID *Buffer;
325 UINTN BufferSize;
326 IA32_MAP_ATTRIBUTE MapAttribute;
327 IA32_MAP_ATTRIBUTE MapMask;
328 RETURN_STATUS Status;
329
330 if (!SevEsIsEnabled ()) {
331 return;
332 }
333
334 ApicAddress = (UINT64)GetLocalApicBaseAddress ();
335 Buffer = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecApicPageTableBase);
336 Cr3 = AsmReadCr3 ();
337
338 MapAttribute.Uint64 = ApicAddress;
339 MapAttribute.Bits.Present = 1;
340 MapAttribute.Bits.ReadWrite = 1;
341 MapMask.Uint64 = MAX_UINT64;
342 BufferSize = SIZE_4KB;
343
344 Status = PageTableMap (
345 (UINTN *)&Cr3,
346 Paging4Level,
347 Buffer,
348 &BufferSize,
349 ApicAddress,
350 SIZE_4KB,
351 &MapAttribute,
352 &MapMask,
353 NULL
354 );
355 if (RETURN_ERROR (Status)) {
356 DEBUG ((DEBUG_ERROR, "Failed to map APIC MMIO region as unencrypted: %d\n", Status));
357 ASSERT (FALSE);
358 }
359
360 CpuFlushTlb ();
361}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette