VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/Sec/AmdSev.c@ 105668

最後變更 在這個檔案從105668是 99404,由 vboxsync 提交於 2 年 前

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

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

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