Laszlo, Minor comments included below. I know from later items in this thread that SMM_COMMUNICATE has already been removed in your local branch.
Reviewed-by: Michael Kinney <michael.d.kin...@intel.com> Mike > -----Original Message----- > From: Laszlo Ersek [mailto:ler...@redhat.com] > Sent: Tuesday, November 3, 2015 1:01 PM > To: edk2-de...@ml01.01.org > Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Justen, Jordan L > <jordan.l.jus...@intel.com> > Subject: [PATCH v4 07/41] OvmfPkg: add PEIM for providing TSEG-as-SMRAM > during PEI > > "MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf" is the library > instance that implements the LockBoxLib library class with SMRAM access > for the PEI phase. > > Introduce a PEIM that produces the EFI_PEI_SMM_COMMUNICATION_PPI and > PEI_SMM_ACCESS_PPI interfaces, enabling SmmLockBoxPeiLib to work. > > Said library instance can parse and access LockBox data itself (without > additional LockBox drivers) if the > EFI_PEI_SMM_COMMUNICATION_PPI.Communicate() function returns > EFI_NOT_STARTED to it. However it requires that > EFI_PEI_SMM_COMMUNICATION_PPI exist at least. Also, PEI_SMM_ACCESS_PPI > must exist and work. > > The load / installation order of S3Resume2Pei and SmmAccessPei is > indifferent. SmmAccessPei produces the GUIDed HOB during its installation > (which happens during PEI), but S3Resume2Pei accesses the HOB only when > the DXE IPL calls its S3RestoreConfig2 PPI member, as last act of PEI. > > MCH_SMRAM_D_LCK and MCH_ESMRAMC_T_EN are masked out the way they are, in > SmmAccessPeiEntryPoint() and SmramAccessOpen() respectively, in order to > prevent VS20xx from warning about the (otherwise fully intentional) > truncation in the UINT8 casts. (Warnings reported by Michael Kinney.) > > Cc: Michael Kinney <michael.d.kin...@intel.com> > Cc: Jordan Justen <jordan.l.jus...@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Laszlo Ersek <ler...@redhat.com> > --- > > Notes: > v3: > - update bit-neg expressions to silence VS20xx warnings [Mike] > > OvmfPkg/OvmfPkgIa32.dsc | 6 + > OvmfPkg/OvmfPkgIa32X64.dsc | 6 + > OvmfPkg/OvmfPkgX64.dsc | 6 + > OvmfPkg/OvmfPkgIa32.fdf | 3 + > OvmfPkg/OvmfPkgIa32X64.fdf | 3 + > OvmfPkg/OvmfPkgX64.fdf | 3 + > OvmfPkg/SmmAccess/SmmAccessPei.inf | 70 +++ > OvmfPkg/SmmAccess/SmramInternal.h | 89 ++++ > OvmfPkg/SmmAccess/SmmAccessPei.c | 446 ++++++++++++++++++++ > OvmfPkg/SmmAccess/SmramInternal.c | 188 +++++++++ > 10 files changed, 820 insertions(+) > > diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc > index c6850ff..0b729ca 100644 > --- a/OvmfPkg/OvmfPkgIa32.dsc > +++ b/OvmfPkg/OvmfPkgIa32.dsc > @@ -445,6 +445,12 @@ [Components] > <LibraryClasses> > PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf > } > +!if $(SMM_REQUIRE) == TRUE > + OvmfPkg/SmmAccess/SmmAccessPei.inf { > + <LibraryClasses> > + PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf > + } > +!endif > > # > # DXE Phase modules > diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc > index dd65bf9..7f672d9 100644 > --- a/OvmfPkg/OvmfPkgIa32X64.dsc > +++ b/OvmfPkg/OvmfPkgIa32X64.dsc > @@ -451,6 +451,12 @@ [Components.IA32] > <LibraryClasses> > PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf > } > +!if $(SMM_REQUIRE) == TRUE > + OvmfPkg/SmmAccess/SmmAccessPei.inf { > + <LibraryClasses> > + PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf > + } > +!endif > > [Components.X64] > # > diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc > index 0de3c85..986c019 100644 > --- a/OvmfPkg/OvmfPkgX64.dsc > +++ b/OvmfPkg/OvmfPkgX64.dsc > @@ -450,6 +450,12 @@ [Components] > <LibraryClasses> > PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf > } > +!if $(SMM_REQUIRE) == TRUE > + OvmfPkg/SmmAccess/SmmAccessPei.inf { > + <LibraryClasses> > + PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf > + } > +!endif > > # > # DXE Phase modules > diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf > index 44e4a92..650dab1 100644 > --- a/OvmfPkg/OvmfPkgIa32.fdf > +++ b/OvmfPkg/OvmfPkgIa32.fdf > @@ -171,6 +171,9 @@ [FV.PEIFV] > INF OvmfPkg/PlatformPei/PlatformPei.inf > INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf > INF UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf > +!if $(SMM_REQUIRE) == TRUE > +INF OvmfPkg/SmmAccess/SmmAccessPei.inf > +!endif > > > ################################################################################ > > diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf > index 67bfbe7..5830401 100644 > --- a/OvmfPkg/OvmfPkgIa32X64.fdf > +++ b/OvmfPkg/OvmfPkgIa32X64.fdf > @@ -171,6 +171,9 @@ [FV.PEIFV] > INF OvmfPkg/PlatformPei/PlatformPei.inf > INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf > INF UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf > +!if $(SMM_REQUIRE) == TRUE > +INF OvmfPkg/SmmAccess/SmmAccessPei.inf > +!endif > > > ################################################################################ > > diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf > index 6624789..9dd6171 100644 > --- a/OvmfPkg/OvmfPkgX64.fdf > +++ b/OvmfPkg/OvmfPkgX64.fdf > @@ -171,6 +171,9 @@ [FV.PEIFV] > INF OvmfPkg/PlatformPei/PlatformPei.inf > INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf > INF UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf > +!if $(SMM_REQUIRE) == TRUE > +INF OvmfPkg/SmmAccess/SmmAccessPei.inf > +!endif > > > ################################################################################ > > diff --git a/OvmfPkg/SmmAccess/SmmAccessPei.inf > b/OvmfPkg/SmmAccess/SmmAccessPei.inf > new file mode 100644 > index 0000000..94eb6c9 > --- /dev/null > +++ b/OvmfPkg/SmmAccess/SmmAccessPei.inf > @@ -0,0 +1,70 @@ > +## @file > +# A PEIM with the following responsibilities: > +# > +# - provide SMRAM access by producing PEI_SMM_ACCESS_PPI, > +# - provide a simple EFI_PEI_SMM_COMMUNICATION_PPI (always returning > +# EFI_NOT_STARTED), > +# - verify & configure the Q35 TSEG in the entry point, > +# - set aside the SMM_S3_RESUME_STATE object at the bottom of TSEG, and > expose > +# it via the gEfiAcpiVariableGuid GUIDed HOB. > +# > +# Copyright (C) 2013, 2015, Red Hat, Inc. > +# > +# This program and the accompanying materials are licensed and made available > +# under the terms and conditions of the BSD License which accompanies this > +# distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > WITHOUT > +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > +## > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = SmmAccessPei > + FILE_GUID = 6C0E75B4-B0B9-44D1-8210-3377D7B4E066 > + MODULE_TYPE = PEIM > + VERSION_STRING = 1.0 > + ENTRY_POINT = SmmAccessPeiEntryPoint > + > +# > +# The following information is for reference only and not required by the > build tools. > +# > +# VALID_ARCHITECTURES = IA32 X64 > +# > + > +[Sources] > + SmmAccessPei.c > + SmramInternal.c Missing source file SmramInternal.h > + > +[Packages] > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + OvmfPkg/OvmfPkg.dec > + > +[Guids] > + gEfiAcpiVariableGuid > + > +[LibraryClasses] > + BaseMemoryLib > + DebugLib > + HobLib > + IoLib > + PcdLib > + PciLib > + PeiServicesLib > + PeimEntryPoint > + > +[FeaturePcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire > + > +[FixedPcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes > + > +[Ppis] > + gEfiPeiSmmCommunicationPpiGuid # PPI ALWAYS_PRODUCED > + gPeiSmmAccessPpiGuid # PPI ALWAYS_PRODUCED Comment should be: ## PRODUCES > + > +[Depex] > + TRUE > diff --git a/OvmfPkg/SmmAccess/SmramInternal.h > b/OvmfPkg/SmmAccess/SmramInternal.h > new file mode 100644 > index 0000000..4e9ac05 > --- /dev/null > +++ b/OvmfPkg/SmmAccess/SmramInternal.h > @@ -0,0 +1,89 @@ > +/** @file > + > + Functions and types shared by the SMM accessor PEI and DXE modules. > + > + Copyright (C) 2015, Red Hat, Inc. > + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > WITHOUT > + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include <Pi/PiMultiPhase.h> > + > +// > +// We'll have two SMRAM ranges. > +// > +// The first is a tiny one that hosts an SMM_S3_RESUME_STATE object, to be > +// filled in by the CPU SMM driver during normal boot, for the PEI instance > of > +// the LockBox library (which will rely on the object during S3 resume). > +// > +// The other SMRAM range is the main one, for the SMM core and the SMM > drivers. > +// > +typedef enum { > + DescIdxSmmS3ResumeState = 0, > + DescIdxMain = 1, > + DescIdxCount = 2 > +} DESCRIPTOR_INDEX; > + > +/** > + Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and > + OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL > object, > + from the D_LCK and T_EN bits. > + > + PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely > on > + the LockState and OpenState fields being up-to-date on entry, and they need > + to restore the same invariant on exit, if they touch the bits in question. > + > + @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is > + locked. > + @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE > + iff SMRAM is open. > +**/ > +VOID > +GetStates ( > + OUT BOOLEAN *LockState, > + OUT BOOLEAN *OpenState > + ); > + > +// > +// The functions below follow the PEI_SMM_ACCESS_PPI and > +// EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This > +// pointers are removed (TSEG doesn't depend on them), and so is the > +// DescriptorIndex parameter (TSEG doesn't support range-wise locking). > +// > +// The LockState and OpenState members that are common to both > +// PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in > +// isolation from the rest of the (non-shared) members. > +// > + > +EFI_STATUS > +SmramAccessOpen ( > + OUT BOOLEAN *LockState, > + OUT BOOLEAN *OpenState > + ); > + > +EFI_STATUS > +SmramAccessClose ( > + OUT BOOLEAN *LockState, > + OUT BOOLEAN *OpenState > + ); > + > +EFI_STATUS > +SmramAccessLock ( > + OUT BOOLEAN *LockState, > + IN OUT BOOLEAN *OpenState > + ); > + > +EFI_STATUS > +SmramAccessGetCapabilities ( > + IN BOOLEAN LockState, > + IN BOOLEAN OpenState, > + IN OUT UINTN *SmramMapSize, > + IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap > + ); > diff --git a/OvmfPkg/SmmAccess/SmmAccessPei.c > b/OvmfPkg/SmmAccess/SmmAccessPei.c > new file mode 100644 > index 0000000..8de4e4f > --- /dev/null > +++ b/OvmfPkg/SmmAccess/SmmAccessPei.c > @@ -0,0 +1,446 @@ > +/** @file > + > + A PEIM with the following responsibilities: > + > + - verify & configure the Q35 TSEG in the entry point, > + - provide SMRAM access by producing PEI_SMM_ACCESS_PPI, > + - provide a simple EFI_PEI_SMM_COMMUNICATION_PPI (always returning > + EFI_NOT_STARTED), > + - set aside the SMM_S3_RESUME_STATE object at the bottom of TSEG, and > expose > + it via the gEfiAcpiVariableGuid GUID HOB. > + > + This PEIM runs from RAM, so we can write to variables with static storage > + duration. > + > + Copyright (C) 2013, 2015, Red Hat, Inc.<BR> > + Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> > + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > WITHOUT > + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include <Guid/AcpiS3Context.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > +#include <Library/HobLib.h> > +#include <Library/IoLib.h> > +#include <Library/PcdLib.h> > +#include <Library/PciLib.h> > +#include <Library/PeiServicesLib.h> > +#include <Ppi/SmmAccess.h> > +#include <Ppi/SmmCommunication.h> > + > +#include <OvmfPlatforms.h> > + > +#include "SmramInternal.h" > + > +// > +// EFI_PEI_SMM_COMMUNICATION_PPI implementation. > +// > + > +/** > + Communicates with a registered handler. > + > + This function provides a service to send and receive messages from a > + registered UEFI service. > + > + @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance. > + @param[in] CommBuffer A pointer to the buffer to convey into > SMRAM. > + @param[in] CommSize The size of the data buffer being passed > in.On > + exit, the size of data being returned. Zero > if > + the handler does not wish to reply with any > + data. > + > + @retval EFI_SUCCESS The message was successfully posted. > + @retval EFI_INVALID_PARAMETER The CommBuffer was NULL. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +SmmCommunicate ( > + IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This, > + IN OUT VOID *CommBuffer, > + IN OUT UINTN *CommSize > + ) > +{ > + // > + // This return status is not documented, but it causes > + // "MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c" to look for the > + // LockBox in SMRAM itself. It allows us to avoid implementing > + // EFI_PEI_SMM_COMMUNICATION_PPI with real functionality, plus we can > + // completely skip PEI_SMM_CONTROL_PPI (which the former would arguably > rely > + // on). > + // > + return EFI_NOT_STARTED; > +} > + > +STATIC EFI_PEI_SMM_COMMUNICATION_PPI mCommunication = { > + &SmmCommunicate > +}; > + > + > +// > +// PEI_SMM_ACCESS_PPI implementation. > +// > + > +/** > + Opens the SMRAM area to be accessible by a PEIM driver. > + > + This function "opens" SMRAM so that it is visible while not inside of SMM. > + The function should return EFI_UNSUPPORTED if the hardware does not support > + hiding of SMRAM. The function should return EFI_DEVICE_ERROR if the SMRAM > + configuration is locked. > + > + @param PeiServices General purpose services available to every > + PEIM. > + @param This The pointer to the SMM Access Interface. > + @param DescriptorIndex The region of SMRAM to Open. > + > + @retval EFI_SUCCESS The region was successfully opened. > + @retval EFI_DEVICE_ERROR The region could not be opened because > locked > + by chipset. > + @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds. > + > +**/ > +STATIC Recommend removing STATIC > +EFI_STATUS > +EFIAPI > +SmmAccessPeiOpen ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN PEI_SMM_ACCESS_PPI *This, > + IN UINTN DescriptorIndex > + ) > +{ > + if (DescriptorIndex >= DescIdxCount) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // According to current practice, DescriptorIndex is not considered at all, > + // beyond validating it. > + // > + return SmramAccessOpen (&This->LockState, &This->OpenState); > +} > + > +/** > + Inhibits access to the SMRAM. > + > + This function "closes" SMRAM so that it is not visible while outside of > SMM. > + The function should return EFI_UNSUPPORTED if the hardware does not support > + hiding of SMRAM. > + > + @param PeiServices General purpose services available to > every > + PEIM. > + @param This The pointer to the SMM Access Interface. > + @param DescriptorIndex The region of SMRAM to Close. > + > + @retval EFI_SUCCESS The region was successfully closed. > + @retval EFI_DEVICE_ERROR The region could not be closed because > + locked by chipset. > + @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds. > + > +**/ > +STATIC Recommend removing STATIC > +EFI_STATUS > +EFIAPI > +SmmAccessPeiClose ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN PEI_SMM_ACCESS_PPI *This, > + IN UINTN DescriptorIndex > + ) > +{ > + if (DescriptorIndex >= DescIdxCount) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // According to current practice, DescriptorIndex is not considered at all, > + // beyond validating it. > + // > + return SmramAccessClose (&This->LockState, &This->OpenState); > +} > + > +/** > + Inhibits access to the SMRAM. > + > + This function prohibits access to the SMRAM region. This function is > usually > + implemented such that it is a write-once operation. > + > + @param PeiServices General purpose services available to > every > + PEIM. > + @param This The pointer to the SMM Access Interface. > + @param DescriptorIndex The region of SMRAM to Close. > + > + @retval EFI_SUCCESS The region was successfully locked. > + @retval EFI_DEVICE_ERROR The region could not be locked because at > + least one range is still open. > + @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds. > + > +**/ > +STATIC Recommend removing STATIC > +EFI_STATUS > +EFIAPI > +SmmAccessPeiLock ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN PEI_SMM_ACCESS_PPI *This, > + IN UINTN DescriptorIndex > + ) > +{ > + if (DescriptorIndex >= DescIdxCount) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // According to current practice, DescriptorIndex is not considered at all, > + // beyond validating it. > + // > + return SmramAccessLock (&This->LockState, &This->OpenState); > +} > + > +/** > + Queries the memory controller for the possible regions that will support > + SMRAM. > + > + @param PeiServices General purpose services available to every > + PEIM. > + @param This The pointer to the SmmAccessPpi Interface. > + @param SmramMapSize The pointer to the variable containing size > of > + the buffer to contain the description > + information. > + @param SmramMap The buffer containing the data describing the > + Smram region descriptors. > + > + @retval EFI_BUFFER_TOO_SMALL The user did not provide a sufficient buffer. > + @retval EFI_SUCCESS The user provided a sufficiently-sized > buffer. > + > +**/ > +STATIC Recommend removing STATIC > +EFI_STATUS > +EFIAPI > +SmmAccessPeiGetCapabilities ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN PEI_SMM_ACCESS_PPI *This, > + IN OUT UINTN *SmramMapSize, > + IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap > + ) > +{ > + return SmramAccessGetCapabilities (This->LockState, This->OpenState, > + SmramMapSize, SmramMap); > +} > + > +// > +// LockState and OpenState will be filled in by the entry point. > +// > +STATIC PEI_SMM_ACCESS_PPI mAccess = { > + &SmmAccessPeiOpen, > + &SmmAccessPeiClose, > + &SmmAccessPeiLock, > + &SmmAccessPeiGetCapabilities > +}; Recommend removing STATIC Global variables should be before function implementations > + > + > +STATIC EFI_PEI_PPI_DESCRIPTOR mPpiList[] = { > + { > + EFI_PEI_PPI_DESCRIPTOR_PPI, > + &gEfiPeiSmmCommunicationPpiGuid, &mCommunication > + }, > + { > + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, > + &gPeiSmmAccessPpiGuid, &mAccess > + } > +}; Recommend removing STATIC > + > + > +// > +// Utility functions. > +// > +STATIC Recommend removing STATIC > +UINT8 > +CmosRead8 ( > + IN UINT8 Index > + ) > +{ > + IoWrite8 (0x70, Index); > + return IoRead8 (0x71); > +} > + > +STATIC Recommend removing STATIC > +UINT32 > +GetSystemMemorySizeBelow4gb ( > + VOID > + ) > +{ > + UINT32 Cmos0x34; > + UINT32 Cmos0x35; > + > + Cmos0x34 = CmosRead8 (0x34); > + Cmos0x35 = CmosRead8 (0x35); > + > + return ((Cmos0x35 << 8 | Cmos0x34) << 16) + SIZE_16MB; > +} > + > + > +// > +// Entry point of this driver. > +// > +EFI_STATUS > +EFIAPI > +SmmAccessPeiEntryPoint ( > + IN EFI_PEI_FILE_HANDLE FileHandle, > + IN CONST EFI_PEI_SERVICES **PeiServices > + ) > +{ > + UINT16 HostBridgeDevId; > + UINT8 EsmramcVal; > + UINT8 RegMask8; > + UINT32 TopOfLowRam, TopOfLowRamMb; > + EFI_STATUS Status; > + UINTN SmramMapSize; > + EFI_SMRAM_DESCRIPTOR SmramMap[DescIdxCount]; > + VOID *GuidHob; > + > + // > + // This module should only be included if SMRAM support is required. > + // > + ASSERT (FeaturePcdGet (PcdSmmSmramRequire)); > + > + // > + // Verify if we're running on a Q35 machine type. > + // > + HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); > + if (HostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) { > + DEBUG ((EFI_D_ERROR, "%a: no SMRAM with host bridge DID=0x%04x; only " > + "DID=0x%04x (Q35) is supported\n", __FUNCTION__, HostBridgeDevId, > + INTEL_Q35_MCH_DEVICE_ID)); > + goto WrongConfig; > + } > + > + // > + // Confirm if QEMU supports SMRAM. > + // > + // With no support for it, the ESMRAMC (Extended System Management RAM > + // Control) register reads as zero. If there is support, the cache-enable > + // bits are hard-coded as 1 by QEMU. > + // > + EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)); > + RegMask8 = MCH_ESMRAMC_SM_CACHE | MCH_ESMRAMC_SM_L1 | MCH_ESMRAMC_SM_L2; > + if ((EsmramcVal & RegMask8) != RegMask8) { > + DEBUG ((EFI_D_ERROR, "%a: this Q35 implementation lacks SMRAM\n", > + __FUNCTION__)); > + goto WrongConfig; > + } > + > + TopOfLowRam = GetSystemMemorySizeBelow4gb (); > + ASSERT ((TopOfLowRam & (SIZE_1MB - 1)) == 0); > + TopOfLowRamMb = TopOfLowRam >> 20; > + > + // > + // Some of the following registers are no-ops for QEMU at the moment, but > it > + // is recommended to set them correctly, since the ESMRAMC that we > ultimately > + // care about is in the same set of registers. > + // > + // First, we disable the integrated VGA, and set both the GTT Graphics > Memory > + // Size and the Graphics Mode Select memory pre-allocation fields to zero. > + // This takes just one write to the Graphics Control Register. > + // > + PciWrite16 (DRAMC_REGISTER_Q35 (MCH_GGC), MCH_GGC_IVD); > + > + // > + // Set Top of Low Usable DRAM. > + // > + PciWrite16 (DRAMC_REGISTER_Q35 (MCH_TOLUD), > + (UINT16)(TopOfLowRamMb << MCH_TOLUD_MB_SHIFT)); > + > + // > + // Given the zero graphics memory sizes configured above, set the > + // graphics-related stolen memory bases to the same as TOLUD. > + // > + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_GBSM), > + TopOfLowRamMb << MCH_GBSM_MB_SHIFT); > + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_BGSM), > + TopOfLowRamMb << MCH_BGSM_MB_SHIFT); > + > + // > + // Set TSEG Memory Base. > + // > + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB), > + (TopOfLowRamMb - FixedPcdGet8 (PcdQ35TsegMbytes)) << > MCH_TSEGMB_MB_SHIFT); > + > + // > + // Set TSEG size, and disable TSEG visibility outside of SMM. Note that the > + // T_EN bit has inverse meaning; when T_EN is set, then TSEG visibility is > + // *restricted* to SMM. > + // > + EsmramcVal &= ~(UINT32)MCH_ESMRAMC_TSEG_MASK; > + EsmramcVal |= FixedPcdGet8 (PcdQ35TsegMbytes) == 8 ? MCH_ESMRAMC_TSEG_8MB : > + FixedPcdGet8 (PcdQ35TsegMbytes) == 2 ? MCH_ESMRAMC_TSEG_2MB : > + MCH_ESMRAMC_TSEG_1MB; > + EsmramcVal |= MCH_ESMRAMC_T_EN; > + PciWrite8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), EsmramcVal); > + > + // > + // TSEG should be closed (see above), but unlocked, initially. Set G_SMRAME > + // (Global SMRAM Enable) too, as both D_LCK and T_EN depend on it. > + // > + PciAndThenOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), > + (UINT8)((~(UINT32)MCH_SMRAM_D_LCK) & 0xff), MCH_SMRAM_G_SMRAME); > + > + // > + // Create the GUID HOB and point it to the first SMRAM range. > + // > + GetStates (&mAccess.LockState, &mAccess.OpenState); > + SmramMapSize = sizeof SmramMap; > + Status = SmramAccessGetCapabilities (mAccess.LockState, mAccess.OpenState, > + &SmramMapSize, SmramMap); > + ASSERT_EFI_ERROR (Status); > + > + DEBUG_CODE_BEGIN (); > + { > + UINTN Count; > + UINTN Idx; > + > + Count = SmramMapSize / sizeof SmramMap[0]; > + DEBUG ((EFI_D_VERBOSE, "%a: SMRAM map follows, %d entries\n", > __FUNCTION__, > + (INT32)Count)); > + DEBUG ((EFI_D_VERBOSE, "% 20a % 20a % 20a % 20a\n", "PhysicalStart(0x)", > + "PhysicalSize(0x)", "CpuStart(0x)", "RegionState(0x)")); > + for (Idx = 0; Idx < Count; ++Idx) { > + DEBUG ((EFI_D_VERBOSE, "% 20Lx % 20Lx % 20Lx % 20Lx\n", > + SmramMap[Idx].PhysicalStart, SmramMap[Idx].PhysicalSize, > + SmramMap[Idx].CpuStart, SmramMap[Idx].RegionState)); > + } > + } > + DEBUG_CODE_END (); > + > + GuidHob = BuildGuidHob (&gEfiAcpiVariableGuid, > + sizeof SmramMap[DescIdxSmmS3ResumeState]); > + if (GuidHob == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + CopyMem (GuidHob, &SmramMap[DescIdxSmmS3ResumeState], > + sizeof SmramMap[DescIdxSmmS3ResumeState]); > + > + // > + // We're done. The next step should succeed, but even if it fails, we can't > + // roll back the above BuildGuidHob() allocation, because PEI doesn't > support > + // releasing memory. > + // > + return PeiServicesInstallPpi (mPpiList); > + > +WrongConfig: > + // > + // We really don't want to continue in this case. > + // > + // _ASSERT() is never compiled out, and it respects PcdDebugPropertyMask > (ie. > + // prevent further execution with CPU breakpoint vs. dead loop). > + // > + _ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > diff --git a/OvmfPkg/SmmAccess/SmramInternal.c > b/OvmfPkg/SmmAccess/SmramInternal.c > new file mode 100644 > index 0000000..c3267ca > --- /dev/null > +++ b/OvmfPkg/SmmAccess/SmramInternal.c > @@ -0,0 +1,188 @@ > +/** @file > + > + Functions and types shared by the SMM accessor PEI and DXE modules. > + > + Copyright (C) 2015, Red Hat, Inc. > + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > WITHOUT > + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include <Guid/AcpiS3Context.h> > +#include <IndustryStandard/Q35MchIch9.h> > +#include <Library/DebugLib.h> > +#include <Library/PciLib.h> > + > +#include "SmramInternal.h" > + > +/** > + Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and > + OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL > object, > + from the D_LCK and T_EN bits. > + > + PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely > on > + the LockState and OpenState fields being up-to-date on entry, and they need > + to restore the same invariant on exit, if they touch the bits in question. > + > + @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is > + locked. > + @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE > + iff SMRAM is open. > +**/ > +VOID > +GetStates ( > + OUT BOOLEAN *LockState, > + OUT BOOLEAN *OpenState > +) > +{ > + UINT8 SmramVal, EsmramcVal; > + > + SmramVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM)); > + EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)); > + > + *LockState = !!(SmramVal & MCH_SMRAM_D_LCK); > + *OpenState = !(EsmramcVal & MCH_ESMRAMC_T_EN); > +} > + > +// > +// The functions below follow the PEI_SMM_ACCESS_PPI and > +// EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This > +// pointers are removed (TSEG doesn't depend on them), and so is the > +// DescriptorIndex parameter (TSEG doesn't support range-wise locking). > +// > +// The LockState and OpenState members that are common to both > +// PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in > +// isolation from the rest of the (non-shared) members. > +// > + > +EFI_STATUS > +SmramAccessOpen ( > + OUT BOOLEAN *LockState, > + OUT BOOLEAN *OpenState > + ) > +{ > + // > + // Open TSEG by clearing T_EN. > + // > + PciAnd8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), > + (UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff)); > + > + GetStates (LockState, OpenState); > + if (!*OpenState) { > + return EFI_DEVICE_ERROR; > + } > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +SmramAccessClose ( > + OUT BOOLEAN *LockState, > + OUT BOOLEAN *OpenState > + ) > +{ > + // > + // Close TSEG by setting T_EN. > + // > + PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN); > + > + GetStates (LockState, OpenState); > + if (*OpenState) { > + return EFI_DEVICE_ERROR; > + } > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +SmramAccessLock ( > + OUT BOOLEAN *LockState, > + IN OUT BOOLEAN *OpenState > + ) > +{ > + if (*OpenState) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Close & lock TSEG by setting T_EN and D_LCK. > + // > + PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN); > + PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK); > + > + GetStates (LockState, OpenState); > + if (*OpenState || !*LockState) { > + return EFI_DEVICE_ERROR; > + } > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +SmramAccessGetCapabilities ( > + IN BOOLEAN LockState, > + IN BOOLEAN OpenState, > + IN OUT UINTN *SmramMapSize, > + IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap > + ) > +{ > + UINTN OriginalSize; > + UINT32 TsegMemoryBaseMb, TsegMemoryBase; > + UINT64 CommonRegionState; > + UINT8 TsegSizeBits; > + > + OriginalSize = *SmramMapSize; > + *SmramMapSize = DescIdxCount * sizeof *SmramMap; > + if (OriginalSize < *SmramMapSize) { > + return EFI_BUFFER_TOO_SMALL; > + } > + > + // > + // Read the TSEG Memory Base register. > + // > + TsegMemoryBaseMb = PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB)); > + TsegMemoryBase = (TsegMemoryBaseMb >> MCH_TSEGMB_MB_SHIFT) << 20; > + > + // > + // Precompute the region state bits that will be set for all regions. > + // > + CommonRegionState = (OpenState ? EFI_SMRAM_OPEN : EFI_SMRAM_CLOSED) | > + (LockState ? EFI_SMRAM_LOCKED : 0) | > + EFI_CACHEABLE; > + > + // > + // The first region hosts an SMM_S3_RESUME_STATE object. It is located at > the > + // start of TSEG. We round up the size to whole pages, and we report it as > + // EFI_ALLOCATED, so that the SMM_CORE stays away from it. > + // > + SmramMap[DescIdxSmmS3ResumeState].PhysicalStart = TsegMemoryBase; > + SmramMap[DescIdxSmmS3ResumeState].CpuStart = TsegMemoryBase; > + SmramMap[DescIdxSmmS3ResumeState].PhysicalSize = > + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (sizeof (SMM_S3_RESUME_STATE))); > + SmramMap[DescIdxSmmS3ResumeState].RegionState = > + CommonRegionState | EFI_ALLOCATED; > + > + // > + // Get the TSEG size bits from the ESMRAMC register. > + // > + TsegSizeBits = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)) & > + MCH_ESMRAMC_TSEG_MASK; > + > + // > + // The second region is the main one, following the first. > + // > + SmramMap[DescIdxMain].PhysicalStart = > + SmramMap[DescIdxSmmS3ResumeState].PhysicalStart + > + SmramMap[DescIdxSmmS3ResumeState].PhysicalSize; > + SmramMap[DescIdxMain].CpuStart = SmramMap[DescIdxMain].PhysicalStart; > + SmramMap[DescIdxMain].PhysicalSize = > + (TsegSizeBits == MCH_ESMRAMC_TSEG_8MB ? SIZE_8MB : > + TsegSizeBits == MCH_ESMRAMC_TSEG_2MB ? SIZE_2MB : > + SIZE_1MB) - SmramMap[DescIdxSmmS3ResumeState].PhysicalSize; > + SmramMap[DescIdxMain].RegionState = CommonRegionState; > + > + return EFI_SUCCESS; > +} > -- > 1.8.3.1 > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel