Laszlo, Thanks for the details. Your implementation looks good.
I will discuss this further with Jiewen to see if it makes sense to provide additional implementations of this PPI that could be shared by multiple platforms. Thanks, Mike >-----Original Message----- >From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of >Laszlo Ersek >Sent: Thursday, November 05, 2015 3:15 AM >To: Kinney, Michael D; edk2-de...@ml01.01.org >Cc: Justen, Jordan L >Subject: Re: [edk2] [PATCH v4 07/41] OvmfPkg: add PEIM for providing TSEG- >as-SMRAM during PEI > >On 11/05/15 02:32, Kinney, Michael D wrote: >> Laszlo, >> >> For the EFI_PEI_COMMUNICATION_PPI, is there a reason you are not using >> UefiCpuPkg\PiSmmCommunication\PiSmmCommunicationPei.inf to produce >that PPI? > >Yes. > >When I wrote this patch originally on April 27th and the days after, >there was no EFI_PEI_COMMUNICATION_PPI implementation in edk2; neither >were plans known to add one. > >In addition, we had discussed the behavior of SmmLockBoxPeiLib at >length, in an off-list thread that you had been CC'd on. Please search >your archives for the message with the following metadata, and the >sub-thread rooted in it: > >Message-ID: <553f96cc.9050...@redhat.com> >Date: Tue, 28 Apr 2015 16:18:52 +0200 >From: Laszlo Ersek <ler...@redhat.com> >To: Yao, Jiewen <jiewen....@intel.com> >CC: Justen, Jordan L <jordan.l.jus...@intel.com>, > Zimmer, Vincent <vincent.zim...@intel.com>, > Kinney, Michael D <michael.d.kin...@intel.com>, > Paolo Bonzini <pbonz...@redhat.com>, > Gerd Hoffmann <kra...@redhat.com>, > Michael S. Tsirkin <m...@redhat.com> >Subject: Re: open-sourcing Intel's "IA32FamilyCpuPkg/PiSmmCpuDxeSmm" > >In that message, I asked: > >> In the whitepaper entitled "A Tour Beyond BIOS: Implementing S3 Resume >> with EDKII", page 25 says, under the heading "PEI Instance": >> >> The PEI instance of SmmLockboxLib has two ways to communicate with >> the LockBox in SMRAM. >> >> 1) It uses the SMM_COMMUNICATION PPI to communicate the SmmLockbox >> service provider, similar as DXE instance. >> 2) When the PEI instance is used before SMM ready, the >> SMM_COMMUNICATION PPI will return EFI_NOT_STARTED. In this case, >> PEI SmmLockBoxLib needs to search the SMRAM region directly to >> find LockBox content. >> >> The question is why a platform would choose option (1), ever. >> >> Namely, option (1) depends on additional drivers: >> - SMM_COMMUNICATION_PPI that actually works >> - (which might further depend on PEI_SMM_CONTROL_PPI) >> - a PEIM driver that implements the privileged (SMM) half of lockbox >> >> Whereas, option (2) is much simpler for the platform. It just needs to >> provide a minimal SMM_COMMUNICATION_PPI where it always returns >> EFI_NOT_STARTED. Then the lockbox library will do everything (and >> depend only on PEI_SMM_ACCESS_PPI). >> >> So, the question is: why would a platform ever pick (1), given that it >> is much more work to implement, for (as far as I can see) no benefit? > >And Jiewen replied (the same day), > >> Ah, I see. The only reason is that: A PEIM might need to restore >> lockbox data *before* SMM rebase happen. Then it has to use #2. >> >> A PEIM might need to restore lockbox data *after* SMM rebase happen. >> Then it has to use #1. (Scanning SMRAM does not work at that moment, >> which is enforced by SMRR) > >I couldn't see any grounds from Jiewen's answer to abandon option (2). >Option (2) actually worked, plus it was actually the *only* possibility >to make SmmLockboxLib work in OVMF (see above). > >I would like to stick with this approach. > >Thanks >Laszlo > >> >> Thanks, >> >> Mike >> >>> -----Original Message----- >>> From: Laszlo Ersek [mailto:ler...@redhat.com] >>> Sent: Tuesday, November 03, 2015 1:01 PM >>> To: edk2-de...@ml01.01.org >>> Cc: Kinney, Michael D; Justen, Jordan L >>> 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 >>> + >>> +[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 >>> + >>> +[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 >>> +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 >>> +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 >>> +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 >>> +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 >>> +}; >>> + >>> + >>> +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 >>> + } >>> +}; >>> + >>> + >>> +// >>> +// Utility functions. >>> +// >>> +STATIC >>> +UINT8 >>> +CmosRead8 ( >>> + IN UINT8 Index >>> + ) >>> +{ >>> + IoWrite8 (0x70, Index); >>> + return IoRead8 (0x71); >>> +} >>> + >>> +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 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel