2 File defines the Sec routines for the AMD SEV
4 Copyright (c) 2021, Advanced Micro Devices, Inc. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
20 Handle an SEV-ES/GHCB protocol check failure.
22 Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
23 wishes to be terminated.
25 @param[in] ReasonCode Reason code to provide to the hypervisor for the
30 SevEsProtocolFailure (
34 MSR_SEV_ES_GHCB_REGISTER Msr
;
37 // Use the GHCB MSR Protocol to request termination by the hypervisor
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
);
52 Determine if SEV-SNP is active.
54 @retval TRUE SEV-SNP is enabled
55 @retval FALSE SEV-SNP is not enabled
63 MSR_SEV_STATUS_REGISTER Msr
;
66 // Read the SEV_STATUS MSR to determine whether SEV-SNP is active.
68 Msr
.Uint32
= AsmReadMsr32 (MSR_SEV_STATUS
);
71 // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
73 if (Msr
.Bits
.SevSnpBit
) {
87 EFI_PHYSICAL_ADDRESS Address
90 MSR_SEV_ES_GHCB_REGISTER Msr
;
93 // Use the GHCB MSR Protocol to request to register the GPA.
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
);
101 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
104 // If hypervisor responded with a different GPA than requested then fail.
106 if ((Msr
.GhcbGpaRegister
.Function
!= GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE
) ||
107 ((Msr
.GhcbPhysicalAddress
& ~EFI_PAGE_MASK
) != Address
))
109 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL
);
114 Verify that Hypervisor supports the SNP feature.
119 HypervisorSnpFeatureCheck (
123 MSR_SEV_ES_GHCB_REGISTER Msr
;
127 // Use the GHCB MSR Protocol to query the hypervisor capabilities
129 Msr
.GhcbPhysicalAddress
= 0;
130 Msr
.GhcbHypervisorFeatures
.Function
= GHCB_HYPERVISOR_FEATURES_REQUEST
;
131 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
135 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
137 Features
= RShiftU64 (Msr
.GhcbPhysicalAddress
, 12);
139 if ((Msr
.GhcbHypervisorFeatures
.Function
!= GHCB_HYPERVISOR_FEATURES_RESPONSE
) ||
140 (!(Features
& GHCB_HV_FEATURES_SNP
)))
149 Validate the SEV-ES/GHCB protocol level.
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.
160 MSR_SEV_ES_GHCB_REGISTER Msr
;
164 // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
167 Msr
.GhcbPhysicalAddress
= 0;
168 Msr
.GhcbInfo
.Function
= GHCB_INFO_SEV_INFO_GET
;
169 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
173 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
175 if (Msr
.GhcbInfo
.Function
!= GHCB_INFO_SEV_INFO
) {
176 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL
);
179 if (Msr
.GhcbProtocol
.SevEsProtocolMin
> Msr
.GhcbProtocol
.SevEsProtocolMax
) {
180 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
183 if ((Msr
.GhcbProtocol
.SevEsProtocolMin
> GHCB_VERSION_MAX
) ||
184 (Msr
.GhcbProtocol
.SevEsProtocolMax
< GHCB_VERSION_MIN
))
186 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
190 // We cannot use the MemEncryptSevSnpIsEnabled () because the
191 // ProcessLibraryConstructorList () is not called yet.
193 if (SevSnpIsEnabled ()) {
195 // Check if hypervisor supports the SNP feature
197 if (!HypervisorSnpFeatureCheck ()) {
198 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
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.
207 SevSnpGhcbRegister ((EFI_PHYSICAL_ADDRESS
)(UINTN
)FixedPcdGet32 (PcdOvmfSecGhcbBase
));
211 // SEV-ES protocol checking succeeded, set the initial GHCB address
213 Msr
.GhcbPhysicalAddress
= FixedPcdGet32 (PcdOvmfSecGhcbBase
);
214 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
217 SetMem (Ghcb
, FixedPcdGet32 (PcdOvmfSecGhcbSize
), 0);
220 // Set the version to the maximum that can be supported
222 Ghcb
->ProtocolVersion
= MIN (Msr
.GhcbProtocol
.SevEsProtocolMax
, GHCB_VERSION_MAX
);
223 Ghcb
->GhcbUsage
= GHCB_STANDARD_USAGE
;
227 Determine if the SEV is active.
229 During the early booting, GuestType is set in the work area. Verify that it
232 @retval TRUE SEV is enabled
233 @retval FALSE SEV is not enabled
241 OVMF_WORK_AREA
*WorkArea
;
244 // Ensure that the size of the Confidential Computing work area header
245 // is same as what is provided through a fixed PCD.
248 (UINTN
)FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader
) ==
249 sizeof (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER
)
252 WorkArea
= (OVMF_WORK_AREA
*)FixedPcdGet32 (PcdOvmfWorkAreaBase
);
254 return ((WorkArea
!= NULL
) && (WorkArea
->Header
.GuestType
== CcGuestTypeAmdSev
));
258 Determine if SEV-ES is active.
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
264 @retval TRUE SEV-ES is enabled
265 @retval FALSE SEV-ES is not enabled
273 SEC_SEV_ES_WORK_AREA
*SevEsWorkArea
;
275 if (!IsSevGuest ()) {
279 SevEsWorkArea
= (SEC_SEV_ES_WORK_AREA
*)FixedPcdGet32 (PcdSevEsWorkAreaBase
);
281 return ((SevEsWorkArea
->SevStatusMsrValue
& BIT1
) != 0);
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/FvmainCompactScratchEnd.fdf.inc.
291 SecValidateSystemRam (
295 PHYSICAL_ADDRESS Start
, End
;
297 if (IsSevGuest () && SevSnpIsEnabled ()) {
298 Start
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecValidatedStart
);
299 End
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)PcdGet32 (PcdOvmfSecValidatedEnd
);
301 MemEncryptSevSnpPreValidateSystemRam (Start
, EFI_SIZE_TO_PAGES ((UINTN
)(End
- Start
)));