| /** @file | |
| This driver publishes the SMM Access 2 Protocol. | |
| Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "SmmAccessDxe.h" | |
| SMM_ACCESS_PRIVATE_DATA mSmmAccess; | |
| /** | |
| Update region state from SMRAM description | |
| @param[in] OrLogic Indicate to use OR if true or AND if false. | |
| @param[in] Value The value to set to region state based on OrLogic. | |
| **/ | |
| VOID | |
| SyncRegionState2SmramDesc ( | |
| IN BOOLEAN OrLogic, | |
| IN UINT64 Value | |
| ) | |
| { | |
| UINT32 Index; | |
| for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) { | |
| if (OrLogic) { | |
| mSmmAccess.SmramDesc[Index].RegionState |= Value; | |
| } else { | |
| mSmmAccess.SmramDesc[Index].RegionState &= Value; | |
| } | |
| } | |
| } | |
| /** | |
| This routine accepts a request to "open" a region of SMRAM. The | |
| region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. | |
| The use of "open" means that the memory is visible from all boot-service | |
| and SMM agents. | |
| @param This Pointer to the SMM Access Interface. | |
| @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. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Open ( | |
| IN EFI_SMM_ACCESS2_PROTOCOL *This | |
| ) | |
| { | |
| if ((mSmmAccess.SmmRegionState & EFI_SMRAM_LOCKED) != 0) { | |
| // | |
| // Cannot open a "locked" region | |
| // | |
| DEBUG ((DEBUG_INFO, "Cannot open the locked SMRAM Region\n")); | |
| return EFI_DEVICE_ERROR; | |
| } | |
| mSmmAccess.SmmRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED); | |
| SyncRegionState2SmramDesc (FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED))); | |
| mSmmAccess.SmmRegionState |= EFI_SMRAM_OPEN; | |
| SyncRegionState2SmramDesc (TRUE, EFI_SMRAM_OPEN); | |
| mSmmAccess.SmmAccess.OpenState = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This routine accepts a request to "close" a region of SMRAM. The region | |
| could be legacy AB or TSEG near top of physical memory. | |
| The use of "close" means that the memory is only visible from SMM agents, | |
| not from BS or RT code. | |
| @param This Pointer to the SMM Access Interface. | |
| @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. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Close ( | |
| IN EFI_SMM_ACCESS2_PROTOCOL *This | |
| ) | |
| { | |
| if ((mSmmAccess.SmmRegionState & EFI_SMRAM_LOCKED) != 0) { | |
| // | |
| // Cannot close a "locked" region | |
| // | |
| DEBUG ((DEBUG_INFO, "Cannot close the locked SMRAM Region\n")); | |
| return EFI_DEVICE_ERROR; | |
| } | |
| if ((mSmmAccess.SmmRegionState & EFI_SMRAM_CLOSED) != 0) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| mSmmAccess.SmmRegionState &= ~EFI_SMRAM_OPEN; | |
| SyncRegionState2SmramDesc (FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN)); | |
| mSmmAccess.SmmRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED); | |
| SyncRegionState2SmramDesc (TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED); | |
| mSmmAccess.SmmAccess.OpenState = FALSE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This routine accepts a request to "lock" SMRAM. The | |
| region could be legacy AB or TSEG near top of physical memory. | |
| The use of "lock" means that the memory can no longer be opened | |
| to BS state. | |
| @param This Pointer to the SMM Access Interface. | |
| @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. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Lock ( | |
| IN EFI_SMM_ACCESS2_PROTOCOL *This | |
| ) | |
| { | |
| if (mSmmAccess.SmmAccess.OpenState) { | |
| DEBUG ((DEBUG_INFO, "Cannot lock SMRAM when it is still open\n")); | |
| return EFI_DEVICE_ERROR; | |
| } | |
| mSmmAccess.SmmRegionState |= EFI_SMRAM_LOCKED; | |
| SyncRegionState2SmramDesc (TRUE, EFI_SMRAM_LOCKED); | |
| mSmmAccess.SmmAccess.LockState = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This routine services a user request to discover the SMRAM | |
| capabilities of this platform. This will report the possible | |
| ranges that are possible for SMRAM access, based upon the | |
| memory controller capabilities. | |
| @param This Pointer to the SMRAM Access Interface. | |
| @param SmramMapSize Pointer to the variable containing size of the | |
| buffer to contain the description information. | |
| @param SmramMap 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. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetCapabilities ( | |
| IN CONST EFI_SMM_ACCESS2_PROTOCOL *This, | |
| IN OUT UINTN *SmramMapSize, | |
| IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN NecessaryBufferSize; | |
| NecessaryBufferSize = mSmmAccess.NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR); | |
| if (*SmramMapSize < NecessaryBufferSize) { | |
| Status = EFI_BUFFER_TOO_SMALL; | |
| } else { | |
| CopyMem (SmramMap, mSmmAccess.SmramDesc, NecessaryBufferSize); | |
| Status = EFI_SUCCESS; | |
| } | |
| *SmramMapSize = NecessaryBufferSize; | |
| return Status; | |
| } | |
| /** | |
| This function installs EFI_SMM_ACCESS_PROTOCOL. | |
| @param ImageHandle Handle for the image of this driver | |
| @param SystemTable Pointer to the EFI System Table | |
| @retval EFI_UNSUPPORTED There's no Intel ICH on this platform | |
| @return The status returned from InstallProtocolInterface(). | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmAccessEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HOB_GUID_TYPE *GuidHob; | |
| UINT32 SmmRegionNum; | |
| EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHob; | |
| UINT32 Index; | |
| // | |
| // Get SMRAM info HOB | |
| // | |
| GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid); | |
| if (GuidHob == NULL) { | |
| DEBUG ((DEBUG_INFO, "SMRAM HOB NOT found\n")); | |
| return EFI_NOT_FOUND; | |
| } | |
| SmramHob = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)GET_GUID_HOB_DATA (GuidHob); | |
| SmmRegionNum = SmramHob->NumberOfSmmReservedRegions; | |
| mSmmAccess.SmramDesc = AllocateZeroPool (sizeof (EFI_SMRAM_DESCRIPTOR) * SmmRegionNum); | |
| if (mSmmAccess.SmramDesc == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem (mSmmAccess.SmramDesc, &SmramHob->Descriptor, sizeof (EFI_SMRAM_DESCRIPTOR) * SmmRegionNum); | |
| DEBUG ((DEBUG_INFO, "NumberOfSmmReservedRegions = 0x%x\n", SmmRegionNum)); | |
| for (Index = 0; Index < SmmRegionNum; Index++) { | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%d: base=0x%x, size = 0x%x, State=0x%x\n", | |
| Index, | |
| SmramHob->Descriptor[Index].PhysicalStart, | |
| SmramHob->Descriptor[Index].PhysicalSize, | |
| SmramHob->Descriptor[Index].RegionState | |
| )); | |
| mSmmAccess.SmramDesc[Index].RegionState &= EFI_ALLOCATED; | |
| mSmmAccess.SmramDesc[Index].RegionState |= EFI_SMRAM_CLOSED | EFI_CACHEABLE; | |
| } | |
| mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE; | |
| mSmmAccess.NumberRegions = SmmRegionNum; | |
| mSmmAccess.SmmAccess.Open = Open; | |
| mSmmAccess.SmmAccess.Close = Close; | |
| mSmmAccess.SmmAccess.Lock = Lock; | |
| mSmmAccess.SmmAccess.GetCapabilities = GetCapabilities; | |
| mSmmAccess.SmmAccess.LockState = FALSE; | |
| mSmmAccess.SmmAccess.OpenState = FALSE; | |
| mSmmAccess.SmmRegionState = EFI_SMRAM_CLOSED; | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &mSmmAccess.Handle, | |
| &gEfiSmmAccess2ProtocolGuid, | |
| &mSmmAccess.SmmAccess, | |
| NULL | |
| ); | |
| return Status; | |
| } |