__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout OvmfPkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
		
			
				
	
	
		
			440 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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,
 | |
|   - 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>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <Guid/AcpiS3Context.h>
 | |
| #include <Library/BaseLib.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 <OvmfPlatforms.h>
 | |
| 
 | |
| #include "SmramInternal.h"
 | |
| 
 | |
| //
 | |
| // 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 | 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 ((
 | |
|       DEBUG_ERROR,
 | |
|       "%a: no SMRAM with host bridge DID=0x%04x; only "
 | |
|       "DID=0x%04x (Q35) is supported\n",
 | |
|       __func__,
 | |
|       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 ((
 | |
|       DEBUG_ERROR,
 | |
|       "%a: this Q35 implementation lacks SMRAM\n",
 | |
|       __func__
 | |
|       ));
 | |
|     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.
 | |
|   //
 | |
|   InitQ35TsegMbytes ();
 | |
|   PciWrite32 (
 | |
|     DRAMC_REGISTER_Q35 (MCH_TSEGMB),
 | |
|     (TopOfLowRamMb - mQ35TsegMbytes) << 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 |= mQ35TsegMbytes == 8 ? MCH_ESMRAMC_TSEG_8MB :
 | |
|                 mQ35TsegMbytes == 2 ? MCH_ESMRAMC_TSEG_2MB :
 | |
|                 mQ35TsegMbytes == 1 ? MCH_ESMRAMC_TSEG_1MB :
 | |
|                 MCH_ESMRAMC_TSEG_EXT;
 | |
|   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 ((
 | |
|       DEBUG_VERBOSE,
 | |
|       "%a: SMRAM map follows, %d entries\n",
 | |
|       __func__,
 | |
|       (INT32)Count
 | |
|       ));
 | |
|     DEBUG ((
 | |
|       DEBUG_VERBOSE,
 | |
|       "% 20a % 20a % 20a % 20a\n",
 | |
|       "PhysicalStart(0x)",
 | |
|       "PhysicalSize(0x)",
 | |
|       "CpuStart(0x)",
 | |
|       "RegionState(0x)"
 | |
|       ));
 | |
|     for (Idx = 0; Idx < Count; ++Idx) {
 | |
|       DEBUG ((
 | |
|         DEBUG_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]
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // SmramAccessLock() depends on "mQ35SmramAtDefaultSmbase"; init the latter
 | |
|   // just before exposing the former via PEI_SMM_ACCESS_PPI.Lock().
 | |
|   //
 | |
|   InitQ35SmramAtDefaultSmbase ();
 | |
| 
 | |
|   //
 | |
|   // 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 (FALSE);
 | |
|   CpuDeadLoop ();
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 |