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