123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- /** @file
- File defines the Sec routines for the AMD SEV
- Copyright (c) 2021, Advanced Micro Devices, Inc. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Library/BaseLib.h>
- #include <Library/DebugLib.h>
- #include <Library/MemEncryptSevLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Register/Amd/Ghcb.h>
- #include <Register/Amd/Msr.h>
- #include "AmdSev.h"
- /**
- Handle an SEV-ES/GHCB protocol check failure.
- Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
- wishes to be terminated.
- @param[in] ReasonCode Reason code to provide to the hypervisor for the
- termination request.
- **/
- VOID
- SevEsProtocolFailure (
- IN UINT8 ReasonCode
- )
- {
- MSR_SEV_ES_GHCB_REGISTER Msr;
- //
- // Use the GHCB MSR Protocol to request termination by the hypervisor
- //
- Msr.GhcbPhysicalAddress = 0;
- Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
- Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
- Msr.GhcbTerminate.ReasonCode = ReasonCode;
- AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
- AsmVmgExit ();
- ASSERT (FALSE);
- CpuDeadLoop ();
- }
- /**
- Determine if SEV-SNP is active.
- @retval TRUE SEV-SNP is enabled
- @retval FALSE SEV-SNP is not enabled
- **/
- BOOLEAN
- SevSnpIsEnabled (
- VOID
- )
- {
- MSR_SEV_STATUS_REGISTER Msr;
- //
- // Read the SEV_STATUS MSR to determine whether SEV-SNP is active.
- //
- Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
- //
- // Check MSR_0xC0010131 Bit 2 (Sev-Snp Enabled)
- //
- if (Msr.Bits.SevSnpBit) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- Register the GHCB GPA
- */
- STATIC
- VOID
- SevSnpGhcbRegister (
- EFI_PHYSICAL_ADDRESS Address
- )
- {
- MSR_SEV_ES_GHCB_REGISTER Msr;
- //
- // Use the GHCB MSR Protocol to request to register the GPA.
- //
- Msr.GhcbPhysicalAddress = Address & ~EFI_PAGE_MASK;
- Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
- AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
- AsmVmgExit ();
- Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
- //
- // If hypervisor responded with a different GPA than requested then fail.
- //
- if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
- ((Msr.GhcbPhysicalAddress & ~EFI_PAGE_MASK) != Address))
- {
- SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
- }
- }
- /**
- Verify that Hypervisor supports the SNP feature.
- */
- STATIC
- BOOLEAN
- HypervisorSnpFeatureCheck (
- VOID
- )
- {
- MSR_SEV_ES_GHCB_REGISTER Msr;
- UINT64 Features;
- //
- // Use the GHCB MSR Protocol to query the hypervisor capabilities
- //
- Msr.GhcbPhysicalAddress = 0;
- Msr.GhcbHypervisorFeatures.Function = GHCB_HYPERVISOR_FEATURES_REQUEST;
- AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
- AsmVmgExit ();
- Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
- Features = RShiftU64 (Msr.GhcbPhysicalAddress, 12);
- if ((Msr.GhcbHypervisorFeatures.Function != GHCB_HYPERVISOR_FEATURES_RESPONSE) ||
- (!(Features & GHCB_HV_FEATURES_SNP)))
- {
- return FALSE;
- }
- return TRUE;
- }
- /**
- Validate the SEV-ES/GHCB protocol level.
- Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
- and the guest intersect. If they don't intersect, request termination.
- **/
- VOID
- SevEsProtocolCheck (
- VOID
- )
- {
- MSR_SEV_ES_GHCB_REGISTER Msr;
- GHCB *Ghcb;
- //
- // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
- // protocol checking
- //
- Msr.GhcbPhysicalAddress = 0;
- Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;
- AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
- AsmVmgExit ();
- Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
- if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {
- SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
- }
- if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {
- SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
- }
- if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||
- (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN))
- {
- SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
- }
- //
- // We cannot use the MemEncryptSevSnpIsEnabled () because the
- // ProcessLibraryConstructorList () is not called yet.
- //
- if (SevSnpIsEnabled ()) {
- //
- // Check if hypervisor supports the SNP feature
- //
- if (!HypervisorSnpFeatureCheck ()) {
- SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);
- }
- //
- // Unlike the SEV-ES guest, the SNP requires that GHCB GPA must be
- // registered with the Hypervisor before the use. This can be done
- // using the new VMGEXIT defined in the GHCB v2. Register the GPA
- // before it is used.
- //
- SevSnpGhcbRegister ((EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase));
- }
- //
- // SEV-ES protocol checking succeeded, set the initial GHCB address
- //
- Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);
- AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
- Ghcb = Msr.Ghcb;
- SetMem (Ghcb, FixedPcdGet32 (PcdOvmfSecGhcbSize), 0);
- //
- // Set the version to the maximum that can be supported
- //
- Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);
- Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;
- }
- /**
- Determine if the SEV is active.
- During the early booting, GuestType is set in the work area. Verify that it
- is an SEV guest.
- @retval TRUE SEV is enabled
- @retval FALSE SEV is not enabled
- **/
- BOOLEAN
- IsSevGuest (
- VOID
- )
- {
- OVMF_WORK_AREA *WorkArea;
- //
- // Ensure that the size of the Confidential Computing work area header
- // is same as what is provided through a fixed PCD.
- //
- ASSERT (
- (UINTN)FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader) ==
- sizeof (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER)
- );
- WorkArea = (OVMF_WORK_AREA *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
- return ((WorkArea != NULL) && (WorkArea->Header.GuestType == CcGuestTypeAmdSev));
- }
- /**
- Determine if SEV-ES is active.
- During early booting, SEV-ES support code will set a flag to indicate that
- SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
- is enabled.
- @retval TRUE SEV-ES is enabled
- @retval FALSE SEV-ES is not enabled
- **/
- BOOLEAN
- SevEsIsEnabled (
- VOID
- )
- {
- SEC_SEV_ES_WORK_AREA *SevEsWorkArea;
- if (!IsSevGuest ()) {
- return FALSE;
- }
- SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *)FixedPcdGet32 (PcdSevEsWorkAreaBase);
- return ((SevEsWorkArea->SevStatusMsrValue & BIT1) != 0);
- }
- /**
- Validate System RAM used for decompressing the PEI and DXE firmware volumes
- when SEV-SNP is active. The PCDs SecValidatedStart and SecValidatedEnd are
- set in OvmfPkg/Include/Fdf/FvmainCompactScratchEnd.fdf.inc.
- **/
- VOID
- SecValidateSystemRam (
- VOID
- )
- {
- PHYSICAL_ADDRESS Start, End;
- if (IsSevGuest () && SevSnpIsEnabled ()) {
- Start = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecValidatedStart);
- End = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecValidatedEnd);
- MemEncryptSevSnpPreValidateSystemRam (Start, EFI_SIZE_TO_PAGES ((UINTN)(End - Start)));
- }
- }
|