--- /dev/null
+/** @file\r
+This is the driver that publishes the SMM Access Protocol\r
+instance for the Tylersburg chipset.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SmmAccessDriver.h"\r
+\r
+\r
+\r
+SMM_ACCESS_PRIVATE_DATA mSmmAccess;\r
+\r
+VOID\r
+SmmAccessOnBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+);\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAccessDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Installs an SMM Access Protocol.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - Handle for the image of this driver.\r
+ SystemTable - Pointer to the EFI System Table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Protocol successfully started and installed.\r
+ EFI_UNSUPPORTED - Protocol can't be started.\r
+ EFI_NOT_FOUND - Protocol not found.\r
+--*/\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_EVENT BootEvent;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ UINTN Index;\r
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+\r
+\r
+ //\r
+ // Initialize private data\r
+ //\r
+ ZeroMem (&mSmmAccess, sizeof (mSmmAccess));\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ NULL,\r
+ (VOID **) &PciRootBridgeIo\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Build SMM related information\r
+ //\r
+ mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;\r
+ mSmmAccess.Handle = NULL;\r
+ mSmmAccess.PciRootBridgeIo = PciRootBridgeIo;\r
+\r
+ //\r
+ // Get Hob list\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);\r
+ DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);\r
+ ASSERT (DescriptorBlock);\r
+\r
+\r
+ //\r
+ // Get CPU Max bus number\r
+ //\r
+ mSmmAccess.MaxBusNumber = PCI_BUS_NUMBER_QNC;\r
+ for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {\r
+ mSmmAccess.SocketPopulated[Index] = TRUE;\r
+ }\r
+\r
+ //\r
+ // Use the hob to publish SMRAM capabilities\r
+ //\r
+ ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);\r
+ for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+ mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;\r
+ mSmmAccess.SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;\r
+ mSmmAccess.SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;\r
+ mSmmAccess.SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;\r
+ DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart,\r
+ mSmmAccess.SmramDesc[Index].PhysicalSize));\r
+ }\r
+\r
+ mSmmAccess.NumberRegions = Index;\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
+ //\r
+ // Install our protocol interfaces on the device's handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSmmAccess.Handle,\r
+ &gEfiSmmAccess2ProtocolGuid,\r
+ &mSmmAccess.SmmAccess,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart)));\r
+ DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize)));\r
+\r
+ mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize);\r
+ //\r
+ // T Seg setting done in QPI RC\r
+ //\r
+\r
+ //\r
+ // Prior ReadyToBoot, lock CSEG\r
+ //\r
+ Status = EfiCreateEventReadyToBootEx(\r
+ TPL_NOTIFY,\r
+ SmmAccessOnBoot,\r
+ NULL,\r
+ &BootEvent );\r
+ ASSERT (!EFI_ERROR (Status));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Open (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\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
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Open.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully opened.\r
+ EFI_DEVICE_ERROR - The region could not be opened because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {\r
+ DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Open TSEG\r
+ //\r
+ if (!QNCOpenSmramRegion ()) {\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;\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
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN;\r
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);\r
+ SmmAccess->SmmAccess.OpenState = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Close (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "close" a region of SMRAM. This is valid for\r
+ compatible SMRAM region.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Close.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully closed.\r
+ EFI_DEVICE_ERROR - The region could not be closed because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+ BOOLEAN OpenState;\r
+ UINTN Index;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {\r
+ //\r
+ // Cannot close a "locked" region\r
+ //\r
+ DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Close TSEG\r
+ //\r
+ if (!QNCCloseSmramRegion ()) {\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN;\r
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));\r
+ mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+\r
+ //\r
+ // Find out if any regions are still open\r
+ //\r
+ OpenState = FALSE;\r
+ for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {\r
+ if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {\r
+ OpenState = TRUE;\r
+ }\r
+ }\r
+\r
+ SmmAccess->SmmAccess.OpenState = OpenState;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Lock (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\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
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Lock.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully locked.\r
+ EFI_DEVICE_ERROR - The region could not be locked because at least\r
+ one range is still open.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (SmmAccess->SmmAccess.OpenState) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;\r
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);\r
+ SmmAccess->SmmAccess.LockState = TRUE;\r
+\r
+ //\r
+ // Lock TSEG\r
+ //\r
+ QNCLockSmramRegion ();\r
+\r
+ return EFI_SUCCESS;\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
+\r
+Routine Description:\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
+Arguments:\r
+\r
+ This - Pointer to the SMRAM Access Interface.\r
+ SmramMapSize - Pointer to the variable containing size of the\r
+ buffer to contain the description information.\r
+ SmramMap - Buffer containing the data describing the Smram\r
+ region descriptors.\r
+Returns:\r
+\r
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.\r
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+ UINTN BufferSize;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+ BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+ if (*SmramMapSize < BufferSize) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ *SmramMapSize = BufferSize;\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+SmmAccessOnBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+)\r
+{\r
+\r
+}\r
+VOID\r
+SyncRegionState2SmramDesc(\r
+ IN BOOLEAN OrAnd,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {\r
+ if (OrAnd) {\r
+ mSmmAccess.SmramDesc[Index].RegionState |= Value;\r
+ } else {\r
+ mSmmAccess.SmramDesc[Index].RegionState &= Value;\r
+ }\r
+ }\r
+}\r