]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add PI SMM IPL and PI SMM Core
authormdkinney <mdkinney@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 25 Feb 2010 23:41:19 +0000 (23:41 +0000)
committermdkinney <mdkinney@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 25 Feb 2010 23:41:19 +0000 (23:41 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10094 6f19259b-4bc3-4df7-8a09-765794883524

15 files changed:
MdeModulePkg/Core/PiSmmCore/Dependency.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Dispatcher.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Handle.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Locate.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Notify.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Page.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/PiSmmCore.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/PiSmmCore.h [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Pool.c [new file with mode: 0644]
MdeModulePkg/Core/PiSmmCore/Smi.c [new file with mode: 0644]

diff --git a/MdeModulePkg/Core/PiSmmCore/Dependency.c b/MdeModulePkg/Core/PiSmmCore/Dependency.c
new file mode 100644 (file)
index 0000000..800892d
--- /dev/null
@@ -0,0 +1,371 @@
+/** @file\r
+  SMM Driver Dispatcher Dependency Evaluator\r
+\r
+  This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine\r
+  if a driver can be scheduled for execution.  The criteria for\r
+  schedulability is that the dependency expression is satisfied.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+///\r
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependecy expression\r
+///                        to save time.  A EFI_DEP_PUSH is evauated one an\r
+///                        replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2\r
+///                        Driver Execution Environment Core Interface use 0xff\r
+///                        as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be\r
+///                        defined to a new value that is not conflicting with PI spec.\r
+///\r
+#define EFI_DEP_REPLACE_TRUE  0xff\r
+\r
+///\r
+/// Define the initial size of the dependency expression evaluation stack\r
+///\r
+#define DEPEX_STACK_SIZE_INCREMENT  0x1000\r
+\r
+//\r
+// Global stack used to evaluate dependency expressions\r
+//\r
+BOOLEAN  *mDepexEvaluationStack        = NULL;\r
+BOOLEAN  *mDepexEvaluationStackEnd     = NULL;\r
+BOOLEAN  *mDepexEvaluationStackPointer = NULL;\r
+\r
+/**\r
+  Grow size of the Depex stack\r
+\r
+  @retval EFI_SUCCESS           Stack successfully growed.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+GrowDepexStack (\r
+  VOID\r
+  )\r
+{\r
+  BOOLEAN     *NewStack;\r
+  UINTN       Size;\r
+\r
+  Size = DEPEX_STACK_SIZE_INCREMENT;\r
+  if (mDepexEvaluationStack != NULL) {\r
+    Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);\r
+  }\r
+\r
+  NewStack = AllocatePool (Size * sizeof (BOOLEAN));\r
+  if (NewStack == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (mDepexEvaluationStack != NULL) {\r
+    //\r
+    // Copy to Old Stack to the New Stack\r
+    //\r
+    CopyMem (\r
+      NewStack,\r
+      mDepexEvaluationStack,\r
+      (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)\r
+      );\r
+\r
+    //\r
+    // Free The Old Stack\r
+    //\r
+    FreePool (mDepexEvaluationStack);\r
+  }\r
+\r
+  //\r
+  // Make the Stack pointer point to the old data in the new stack\r
+  //\r
+  mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);\r
+  mDepexEvaluationStack        = NewStack;\r
+  mDepexEvaluationStackEnd     = NewStack + Size;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Push an element onto the Boolean Stack.\r
+\r
+  @param  Value                 BOOLEAN to push.\r
+\r
+  @retval EFI_SUCCESS           The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushBool (\r
+  IN BOOLEAN  Value\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Check for a stack overflow condition\r
+  //\r
+  if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {\r
+    //\r
+    // Grow the stack\r
+    //\r
+    Status = GrowDepexStack ();\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Push the item onto the stack\r
+  //\r
+  *mDepexEvaluationStackPointer = Value;\r
+  mDepexEvaluationStackPointer++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Pop an element from the Boolean stack.\r
+\r
+  @param  Value                 BOOLEAN to pop.\r
+\r
+  @retval EFI_SUCCESS           The value was popped onto the stack.\r
+  @retval EFI_ACCESS_DENIED     The pop operation underflowed the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopBool (\r
+  OUT BOOLEAN  *Value\r
+  )\r
+{\r
+  //\r
+  // Check for a stack underflow condition\r
+  //\r
+  if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Pop the item off the stack\r
+  //\r
+  mDepexEvaluationStackPointer--;\r
+  *Value = *mDepexEvaluationStackPointer;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This is the POSTFIX version of the dependency evaluator.  This code does\r
+  not need to handle Before or After, as it is not valid to call this\r
+  routine in this case. The SOR is just ignored and is a nop in the grammer.\r
+  POSTFIX means all the math is done on top of the stack.\r
+\r
+  @param  DriverEntry           DriverEntry element to update.\r
+\r
+  @retval TRUE                  If driver is ready to run.\r
+  @retval FALSE                 If driver is not ready to run or some fatal error\r
+                                was found.\r
+\r
+**/\r
+BOOLEAN\r
+SmmIsSchedulable (\r
+  IN  EFI_SMM_DRIVER_ENTRY   *DriverEntry\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       *Iterator;\r
+  BOOLEAN     Operator;\r
+  BOOLEAN     Operator2;\r
+  EFI_GUID    DriverGuid;\r
+  VOID        *Interface;\r
+\r
+  Operator = FALSE;\r
+  Operator2 = FALSE;\r
+\r
+  if (DriverEntry->After || DriverEntry->Before) {\r
+    //\r
+    // If Before or After Depex skip as SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()\r
+    // processes them.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  if (DriverEntry->Depex == NULL) {\r
+    //\r
+    // A NULL Depex means that the SMM driver is not built correctly.  \r
+    // All SMM drivers must have a valid depex expressiion.\r
+    //\r
+    ASSERT (FALSE);\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by\r
+  // incorrectly formed DEPEX expressions\r
+  //\r
+  mDepexEvaluationStackPointer = mDepexEvaluationStack;\r
+\r
+\r
+  Iterator = DriverEntry->Depex;\r
+\r
+  while (TRUE) {\r
+    //\r
+    // Check to see if we are attempting to fetch dependency expression instructions\r
+    // past the end of the dependency expression.\r
+    //\r
+    if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {\r
+      return FALSE;\r
+    }\r
+\r
+    //\r
+    // Look at the opcode of the dependency expression instruction.\r
+    //\r
+    switch (*Iterator) {\r
+    case EFI_DEP_BEFORE:\r
+    case EFI_DEP_AFTER:\r
+      //\r
+      // For a well-formed Dependency Expression, the code should never get here.\r
+      // The BEFORE and AFTER are processed prior to this routine's invocation.\r
+      // If the code flow arrives at this point, there was a BEFORE or AFTER\r
+      // that were not the first opcodes.\r
+      //\r
+      ASSERT (FALSE);\r
+    case EFI_DEP_SOR:\r
+      //\r
+      // These opcodes can only appear once as the first opcode.  If it is found\r
+      // at any other location, then the dependency expression evaluates to FALSE\r
+      //\r
+      if (Iterator != DriverEntry->Depex) {\r
+        return FALSE;\r
+      }\r
+      //\r
+      // Otherwise, it is the first opcode and should be treated as a NOP.\r
+      //\r
+      break;\r
+\r
+    case EFI_DEP_PUSH:\r
+      //\r
+      // Push operator is followed by a GUID. Test to see if the GUID protocol\r
+      // is installed and push the boolean result on the stack.\r
+      //\r
+      CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));\r
+\r
+      Status = SmmLocateProtocol (&DriverGuid, NULL, &Interface);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // For SMM Driver, it may depend on uefi protocols\r
+        //\r
+        Status = gBS->LocateProtocol (&DriverGuid, NULL, &Interface);\r
+      }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        Status = PushBool (FALSE);\r
+      } else {\r
+        *Iterator = EFI_DEP_REPLACE_TRUE;\r
+        Status = PushBool (TRUE);\r
+      }\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Iterator += sizeof (EFI_GUID);\r
+      break;\r
+\r
+    case EFI_DEP_AND:\r
+      Status = PopBool (&Operator);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Status = PopBool (&Operator2);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Status = PushBool ((BOOLEAN)(Operator && Operator2));\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_DEP_OR:\r
+      Status = PopBool (&Operator);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Status = PopBool (&Operator2);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Status = PushBool ((BOOLEAN)(Operator || Operator2));\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_DEP_NOT:\r
+      Status = PopBool (&Operator);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Status = PushBool ((BOOLEAN)(!Operator));\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_DEP_TRUE:\r
+      Status = PushBool (TRUE);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_DEP_FALSE:\r
+      Status = PushBool (FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_DEP_END:\r
+      Status = PopBool (&Operator);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+      return Operator;\r
+\r
+    case EFI_DEP_REPLACE_TRUE:\r
+      Status = PushBool (TRUE);\r
+      if (EFI_ERROR (Status)) {\r
+        return FALSE;\r
+      }\r
+\r
+      Iterator += sizeof (EFI_GUID);\r
+      break;\r
+\r
+    default:\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Skip over the Dependency Op Code we just processed in the switch.\r
+    // The math is done out of order, but it should not matter. That is\r
+    // we may add in the sizeof (EFI_GUID) before we account for the OP Code.\r
+    // This is not an issue, since we just need the correct end result. You\r
+    // need to be careful using Iterator in the loop as it's intermediate value\r
+    // may be strange.\r
+    //\r
+    Iterator++;\r
+  }\r
+\r
+Done:\r
+  return FALSE;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c
new file mode 100644 (file)
index 0000000..9e1a778
--- /dev/null
@@ -0,0 +1,1174 @@
+/** @file\r
+  SMM Driver Dispatcher.\r
+\r
+  Step #1 - When a FV protocol is added to the system every driver in the FV\r
+            is added to the mDiscoveredList. The SOR, Before, and After Depex are\r
+            pre-processed as drivers are added to the mDiscoveredList. If an Apriori\r
+            file exists in the FV those drivers are addeded to the\r
+            mScheduledQueue. The mFvHandleList is used to make sure a\r
+            FV is only processed once.\r
+\r
+  Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and\r
+            start it. After mScheduledQueue is drained check the\r
+            mDiscoveredList to see if any item has a Depex that is ready to\r
+            be placed on the mScheduledQueue.\r
+\r
+  Step #3 - Adding to the mScheduledQueue requires that you process Before\r
+            and After dependencies. This is done recursively as the call to add\r
+            to the mScheduledQueue checks for Before and recursively adds\r
+            all Befores. It then addes the item that was passed in and then\r
+            processess the After dependecies by recursively calling the routine.\r
+\r
+  Dispatcher Rules:\r
+  The rules for the dispatcher are similar to the DXE dispatcher.\r
+\r
+  The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3\r
+  is the state diagram for the DXE dispatcher\r
+\r
+  Depex - Dependency Expresion.\r
+  SOR   - Schedule On Request - Don't schedule if this bit is set.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+//\r
+// SMM Dispatcher Data structures\r
+//\r
+#define KNOWN_HANDLE_SIGNATURE  SIGNATURE_32('k','n','o','w')\r
+typedef struct {\r
+  UINTN           Signature;\r
+  LIST_ENTRY      Link;         // mFvHandleList\r
+  EFI_HANDLE      Handle;\r
+} KNOWN_HANDLE;\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+\r
+/**\r
+  Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
+  must add any driver with a before dependency on InsertedDriverEntry first.\r
+  You do this by recursively calling this routine. After all the Befores are\r
+  processed you can add InsertedDriverEntry to the mScheduledQueue.\r
+  Then you can add any driver with an After dependency on InsertedDriverEntry\r
+  by recursively calling this routine.\r
+\r
+  @param  InsertedDriverEntry   The driver to insert on the ScheduledLink Queue\r
+\r
+**/\r
+VOID\r
+SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
+  IN  EFI_SMM_DRIVER_ENTRY   *InsertedDriverEntry\r
+  );\r
+\r
+//\r
+// The Driver List contains one copy of every driver that has been discovered.\r
+// Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY\r
+//\r
+LIST_ENTRY  mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);\r
+\r
+//\r
+// Queue of drivers that are ready to dispatch. This queue is a subset of the\r
+// mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY.\r
+//\r
+LIST_ENTRY  mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);\r
+\r
+//\r
+// List of handles who's Fv's have been parsed and added to the mFwDriverList.\r
+//\r
+LIST_ENTRY  mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);\r
+\r
+//\r
+// Flag for the SMM Dispacher.  TRUE if dispatcher is execuing.\r
+//\r
+BOOLEAN  gDispatcherRunning = FALSE;\r
+\r
+//\r
+// Flag for the SMM Dispacher.  TRUE if there is one or more SMM drivers ready to be dispatched\r
+//\r
+BOOLEAN  gRequestDispatch = FALSE;\r
+\r
+//\r
+// List of file types supported by dispatcher\r
+//\r
+EFI_FV_FILETYPE mSmmFileTypes[] = {\r
+  EFI_FV_FILETYPE_SMM,\r
+  EFI_FV_FILETYPE_COMBINED_SMM_DXE\r
+  //\r
+  // Note: DXE core will process the FV image file, so skip it in SMM core\r
+  // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
+  //\r
+};\r
+\r
+typedef struct {\r
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  File;\r
+  EFI_DEVICE_PATH_PROTOCOL           End;\r
+} FV_FILEPATH_DEVICE_PATH;\r
+\r
+FV_FILEPATH_DEVICE_PATH  mFvDevicePath;\r
+\r
+//\r
+// DXE Architecture Protocols\r
+//\r
+EFI_SECURITY_ARCH_PROTOCOL  *mSecurity = NULL;\r
+\r
+/**\r
+  Loads an EFI image into SMRAM.\r
+\r
+  @param  DriverEntry             EFI_SMM_DRIVER_ENTRY instance\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLoadImage (\r
+  IN OUT EFI_SMM_DRIVER_ENTRY  *DriverEntry\r
+  )\r
+{\r
+  UINT32                         AuthenticationStatus;\r
+  UINTN                          FilePathSize;\r
+  VOID                           *Buffer;\r
+  UINTN                          Size;\r
+  UINTN                          PageCount;\r
+  EFI_GUID                       *NameGuid;\r
+  EFI_STATUS                     Status;\r
+  EFI_STATUS                     SecurityStatus;\r
+  EFI_HANDLE                     DeviceHandle;\r
+  EFI_PHYSICAL_ADDRESS           DstBuffer;\r
+  EFI_DEVICE_PATH_PROTOCOL       *FilePath;\r
+  EFI_DEVICE_PATH_PROTOCOL       *OriginalFilePath;\r
+  EFI_DEVICE_PATH_PROTOCOL       *HandleFilePath;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT   ImageContext;\r
+   \r
+  Buffer               = NULL;\r
+  Size                 = 0;\r
+  Fv                   = DriverEntry->Fv;\r
+  NameGuid             = &DriverEntry->FileName;\r
+  FilePath             = DriverEntry->FvFileDevicePath;\r
+\r
+  OriginalFilePath     = FilePath;\r
+  HandleFilePath       = FilePath;\r
+  DeviceHandle         = NULL;\r
+  SecurityStatus       = EFI_SUCCESS;\r
+  Status               = EFI_SUCCESS;\r
+  AuthenticationStatus = 0;\r
+\r
+  //\r
+  // Try to get the image device handle by checking the match protocol.\r
+  //\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // If the Security Architectural Protocol has not been located yet, then attempt to locate it\r
+  //\r
+  if (mSecurity == NULL) {\r
+    gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);\r
+  }\r
+\r
+  //\r
+  // Verify the Authentication Status through the Security Architectural Protocol\r
+  //\r
+  if ((mSecurity != NULL) && (OriginalFilePath != NULL)) {\r
+    SecurityStatus = mSecurity->FileAuthenticationState (\r
+                                  mSecurity,\r
+                                  AuthenticationStatus,\r
+                                  OriginalFilePath\r
+                                  );\r
+    if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {\r
+      Status = SecurityStatus;\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Pull out just the file portion of the DevicePath for the LoadedImage FilePath\r
+  //\r
+  FilePath = OriginalFilePath;\r
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);\r
+  if (!EFI_ERROR (Status)) {\r
+    FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
+    FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );\r
+  }\r
+\r
+  //\r
+  // Try reading PE32 section firstly\r
+  //\r
+  Status = Fv->ReadSection (\r
+                 Fv,\r
+                 NameGuid,\r
+                 EFI_SECTION_PE32,\r
+                 0,\r
+                 &Buffer,\r
+                 &Size,\r
+                 &AuthenticationStatus\r
+                 );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Try reading TE section secondly\r
+    //\r
+    Buffer = NULL;\r
+    Size   = 0;\r
+    Status = Fv->ReadSection (\r
+                  Fv,\r
+                  NameGuid,\r
+                  EFI_SECTION_TE,\r
+                  0,\r
+                  &Buffer,\r
+                  &Size,\r
+                  &AuthenticationStatus\r
+                  );\r
+  }\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Initialize ImageContext\r
+  //\r
+  ImageContext.Handle = Buffer;\r
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+  //\r
+  // Get information about the image being loaded\r
+  //\r
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+  DstBuffer = (UINTN)(-1);\r
+  \r
+  Status = SmmAllocatePages (\r
+             AllocateMaxAddress,\r
+             EfiRuntimeServicesCode,\r
+             PageCount,\r
+             &DstBuffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;\r
+  //\r
+  // Align buffer on section boundry\r
+  //\r
+  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+  ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+  //\r
+  // Load the image to our new buffer\r
+  //\r
+  Status = PeCoffLoaderLoadImage (&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    SmmFreePages (DstBuffer, PageCount);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Relocate the image in our new buffer\r
+  //\r
+  Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    SmmFreePages (DstBuffer, PageCount);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Flush the instruction cache so the image data are written before we execute it\r
+  //\r
+  InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);\r
+\r
+  //\r
+  // Save Image EntryPoint in DriverEntry\r
+  //\r
+  DriverEntry->ImageEntryPoint  = ImageContext.EntryPoint;\r
+  DriverEntry->ImageBuffer      = DstBuffer; \r
+  DriverEntry->NumberOfPage     = PageCount;\r
+\r
+  //\r
+  // Allocate a Loaded Image Protocol in EfiBootServicesData\r
+  //\r
+  Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    SmmFreePages (DstBuffer, PageCount);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Fill in the remaining fields of the Loaded Image Protocol instance.\r
+  // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.\r
+  //\r
+  DriverEntry->LoadedImage->Revision      = EFI_LOADED_IMAGE_PROTOCOL_REVISION;\r
+  DriverEntry->LoadedImage->ParentHandle  = gSmmCorePrivate->SmmIplImageHandle;\r
+  DriverEntry->LoadedImage->SystemTable   = gST;\r
+  DriverEntry->LoadedImage->DeviceHandle  = DeviceHandle;\r
+\r
+  //\r
+  // Make an EfiBootServicesData buffer copy of FilePath\r
+  //\r
+  Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Buffer != NULL) {\r
+      Status = gBS->FreePool (Buffer);\r
+    }\r
+    SmmFreePages (DstBuffer, PageCount);\r
+    return Status;\r
+  }\r
+  CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));\r
+\r
+  DriverEntry->LoadedImage->ImageBase     = (VOID *)(UINTN)DriverEntry->ImageBuffer;\r
+  DriverEntry->LoadedImage->ImageSize     = ImageContext.ImageSize;\r
+  DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;\r
+  DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;\r
+\r
+  //\r
+  // Create a new image handle in the UEFI handle database for the SMM Driver\r
+  //\r
+  DriverEntry->ImageHandle = NULL;\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &DriverEntry->ImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage,\r
+                  NULL\r
+                  );\r
+\r
+  //\r
+  // Print the load address and the PDB file name if it is available\r
+  //\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+\r
+    UINTN Index;\r
+    UINTN StartIndex;\r
+    CHAR8 EfiFileName[256];\r
+\r
+\r
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD,\r
+           "Loading driver at 0x%11p EntryPoint=0x%11p ",\r
+           (VOID *)(UINTN) ImageContext.ImageAddress,\r
+           FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));\r
+\r
+\r
+    //\r
+    // Print Module Name by Pdb file path.\r
+    // Windows and Unix style file path are all trimmed correctly.\r
+    //\r
+    if (ImageContext.PdbPointer != NULL) {\r
+      StartIndex = 0;\r
+      for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {\r
+        if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {\r
+          StartIndex = Index + 1;\r
+        }\r
+      }\r
+      //\r
+      // Copy the PDB file name to our temporary string, and replace .pdb with .efi\r
+      // The PDB file name is limited in the range of 0~255.\r
+      // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.\r
+      //\r
+      for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {\r
+        EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];\r
+        if (EfiFileName[Index] == 0) {\r
+          EfiFileName[Index] = '.';\r
+        }\r
+        if (EfiFileName[Index] == '.') {\r
+          EfiFileName[Index + 1] = 'e';\r
+          EfiFileName[Index + 2] = 'f';\r
+          EfiFileName[Index + 3] = 'i';\r
+          EfiFileName[Index + 4] = 0;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Index == sizeof (EfiFileName) - 4) {\r
+        EfiFileName[Index] = 0;\r
+      }\r
+      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));\r
+    }\r
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));\r
+\r
+  DEBUG_CODE_END ();\r
+\r
+  //\r
+  // Free buffer allocated by Fv->ReadSection.\r
+  //\r
+  // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection \r
+  // used the UEFI Boot Services AllocatePool() function\r
+  //\r
+  Status = gBS->FreePool(Buffer);\r
+  return Status;  \r
+}\r
+\r
+/**\r
+  Preprocess dependency expression and update DriverEntry to reflect the\r
+  state of  Before, After, and SOR dependencies. If DriverEntry->Before\r
+  or DriverEntry->After is set it will never be cleared. If SOR is set\r
+  it will be cleared by SmmSchedule(), and then the driver can be\r
+  dispatched.\r
+\r
+  @param  DriverEntry           DriverEntry element to update .\r
+\r
+  @retval EFI_SUCCESS           It always works.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmPreProcessDepex (\r
+  IN EFI_SMM_DRIVER_ENTRY  *DriverEntry\r
+  )\r
+{\r
+  UINT8  *Iterator;\r
+\r
+  Iterator = DriverEntry->Depex;\r
+  if (*Iterator == EFI_DEP_SOR) {\r
+    DriverEntry->Unrequested = TRUE;\r
+  } else {\r
+    DriverEntry->Dependent = TRUE;\r
+  }\r
+\r
+  if (*Iterator == EFI_DEP_BEFORE) {\r
+    DriverEntry->Before = TRUE;\r
+  } else if (*Iterator == EFI_DEP_AFTER) {\r
+    DriverEntry->After = TRUE;\r
+  }\r
+\r
+  if (DriverEntry->Before || DriverEntry->After) {\r
+    CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read Depex and pre-process the Depex for Before and After. If Section Extraction\r
+  protocol returns an error via ReadSection defer the reading of the Depex.\r
+\r
+  @param  DriverEntry           Driver to work on.\r
+\r
+  @retval EFI_SUCCESS           Depex read and preprossesed\r
+  @retval EFI_PROTOCOL_ERROR    The section extraction protocol returned an error\r
+                                and  Depex reading needs to be retried.\r
+  @retval Error                 DEPEX not found.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmGetDepexSectionAndPreProccess (\r
+  IN EFI_SMM_DRIVER_ENTRY  *DriverEntry\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_SECTION_TYPE               SectionType;\r
+  UINT32                         AuthenticationStatus;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;\r
+\r
+  Fv = DriverEntry->Fv;\r
+\r
+  //\r
+  // Grab Depex info, it will never be free'ed.\r
+  // (Note: DriverEntry->Depex is in DXE memory)\r
+  //\r
+  SectionType         = EFI_SECTION_SMM_DEPEX;\r
+  Status = Fv->ReadSection (\r
+                DriverEntry->Fv,\r
+                &DriverEntry->FileName,\r
+                SectionType,\r
+                0,\r
+                &DriverEntry->Depex,\r
+                (UINTN *)&DriverEntry->DepexSize,\r
+                &AuthenticationStatus\r
+                );\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_PROTOCOL_ERROR) {\r
+      //\r
+      // The section extraction protocol failed so set protocol error flag\r
+      //\r
+      DriverEntry->DepexProtocolError = TRUE;\r
+    } else {\r
+      //\r
+      // If no Depex assume depend on all architectural protocols\r
+      //\r
+      DriverEntry->Depex = NULL;\r
+      DriverEntry->Dependent = TRUE;\r
+      DriverEntry->DepexProtocolError = FALSE;\r
+    }\r
+  } else {\r
+    //\r
+    // Set Before, After, and Unrequested state information based on Depex\r
+    // Driver will be put in Dependent or Unrequested state\r
+    //\r
+    SmmPreProcessDepex (DriverEntry);\r
+    DriverEntry->DepexProtocolError = FALSE;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check every driver and locate a matching one. If the driver is found, the Unrequested\r
+  state flag is cleared.\r
+\r
+  @param  FirmwareVolumeHandle  The handle of the Firmware Volume that contains\r
+                                the firmware  file specified by DriverName.\r
+  @param  DriverName            The Driver name to put in the Dependent state.\r
+\r
+  @retval EFI_SUCCESS           The DriverName was found and it's SOR bit was\r
+                                cleared\r
+  @retval EFI_NOT_FOUND         The DriverName does not exist or it's SOR bit was\r
+                                not set.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmSchedule (\r
+  IN  EFI_HANDLE  FirmwareVolumeHandle,\r
+  IN  EFI_GUID    *DriverName\r
+  )\r
+{\r
+  LIST_ENTRY            *Link;\r
+  EFI_SMM_DRIVER_ENTRY  *DriverEntry;\r
+\r
+  //\r
+  // Check every driver\r
+  //\r
+  for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+    DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+    if (DriverEntry->FvHandle == FirmwareVolumeHandle &&\r
+        DriverEntry->Unrequested &&\r
+        CompareGuid (DriverName, &DriverEntry->FileName)) {\r
+      //\r
+      // Move the driver from the Unrequested to the Dependent state\r
+      //\r
+      DriverEntry->Unrequested  = FALSE;\r
+      DriverEntry->Dependent    = TRUE;\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This is the main Dispatcher for SMM and it exits when there are no more\r
+  drivers to run. Drain the mScheduledQueue and load and start a PE\r
+  image for each driver. Search the mDiscoveredList to see if any driver can\r
+  be placed on the mScheduledQueue. If no drivers are placed on the\r
+  mScheduledQueue exit the function. On exit it is assumed the Bds()\r
+  will be called, and when the Bds() exits the Dispatcher will be called\r
+  again.\r
+\r
+  @retval EFI_ALREADY_STARTED   The SMM Dispatcher is already running\r
+  @retval EFI_NOT_FOUND         No SMM Drivers were dispatched\r
+  @retval EFI_SUCCESS           One or more SMM Drivers were dispatched\r
+\r
+**/\r
+EFI_STATUS\r
+SmmDispatcher (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_STATUS            ReturnStatus;\r
+  LIST_ENTRY            *Link;\r
+  EFI_SMM_DRIVER_ENTRY  *DriverEntry;\r
+  BOOLEAN               ReadyToRun;\r
+\r
+  if (!gRequestDispatch) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (gDispatcherRunning) {\r
+    //\r
+    // If the dispatcher is running don't let it be restarted.\r
+    //\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  gDispatcherRunning = TRUE;\r
+\r
+  ReturnStatus = EFI_NOT_FOUND;\r
+  do {\r
+    //\r
+    // Drain the Scheduled Queue\r
+    //\r
+    while (!IsListEmpty (&mScheduledQueue)) {\r
+      DriverEntry = CR (\r
+                      mScheduledQueue.ForwardLink,\r
+                      EFI_SMM_DRIVER_ENTRY,\r
+                      ScheduledLink,\r
+                      EFI_SMM_DRIVER_ENTRY_SIGNATURE\r
+                      );\r
+\r
+      //\r
+      // Load the SMM Driver image into memory. If the Driver was transitioned from\r
+      // Untrused to Scheduled it would have already been loaded so we may need to\r
+      // skip the LoadImage\r
+      //\r
+      if (DriverEntry->ImageHandle == NULL) {\r
+        Status = SmmLoadImage (DriverEntry);\r
+\r
+        //\r
+        // Update the driver state to reflect that it's been loaded\r
+        //\r
+        if (EFI_ERROR (Status)) {\r
+\r
+          if (Status == EFI_SECURITY_VIOLATION) {\r
+            //\r
+            // Take driver from Scheduled to Untrused state\r
+            //\r
+            DriverEntry->Untrusted = TRUE;\r
+          } else {\r
+            //\r
+            // The SMM Driver could not be loaded, and do not attempt to load or start it again.\r
+            // Take driver from Scheduled to Initialized.\r
+            //\r
+            // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned\r
+            //\r
+            DriverEntry->Initialized  = TRUE;\r
+          }\r
+\r
+          DriverEntry->Scheduled = FALSE;\r
+          RemoveEntryList (&DriverEntry->ScheduledLink);\r
+\r
+          //\r
+          // If it's an error don't try the StartImage\r
+          //\r
+          continue;\r
+        }\r
+      }\r
+\r
+      DriverEntry->Scheduled    = FALSE;\r
+      DriverEntry->Initialized  = TRUE;\r
+      RemoveEntryList (&DriverEntry->ScheduledLink);\r
+\r
+      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
+        EFI_PROGRESS_CODE,\r
+        EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,\r
+        &DriverEntry->ImageHandle,\r
+        sizeof (DriverEntry->ImageHandle)\r
+        );\r
+\r
+      //\r
+      // For each SMM driver, pass NULL as ImageHandle\r
+      //\r
+      Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);\r
+      if (EFI_ERROR(Status)){\r
+        SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);\r
+      }\r
+\r
+      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
+        EFI_PROGRESS_CODE,\r
+        EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,\r
+        &DriverEntry->ImageHandle,\r
+        sizeof (DriverEntry->ImageHandle)\r
+        );\r
+\r
+      ReturnStatus = EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Search DriverList for items to place on Scheduled Queue\r
+    //\r
+    ReadyToRun = FALSE;\r
+    for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+      DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+\r
+      if (DriverEntry->DepexProtocolError){\r
+        //\r
+        // If Section Extraction Protocol did not let the Depex be read before retry the read\r
+        //\r
+        Status = SmmGetDepexSectionAndPreProccess (DriverEntry);\r
+      }\r
+\r
+      if (DriverEntry->Dependent) {\r
+        if (SmmIsSchedulable (DriverEntry)) {\r
+          SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
+          ReadyToRun = TRUE;\r
+        }\r
+      }\r
+    }\r
+  } while (ReadyToRun);\r
+\r
+  //\r
+  // If there is no more SMM driver to dispatch, stop the dispatch request\r
+  //\r
+  gRequestDispatch = FALSE;\r
+  for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+    DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+\r
+    if (!DriverEntry->Initialized){\r
+      //\r
+      // We have SMM driver pending to dispatch\r
+      //\r
+      gRequestDispatch = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  gDispatcherRunning = FALSE;\r
+\r
+  return ReturnStatus;\r
+}\r
+\r
+/**\r
+  Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
+  must add any driver with a before dependency on InsertedDriverEntry first.\r
+  You do this by recursively calling this routine. After all the Befores are\r
+  processed you can add InsertedDriverEntry to the mScheduledQueue.\r
+  Then you can add any driver with an After dependency on InsertedDriverEntry\r
+  by recursively calling this routine.\r
+\r
+  @param  InsertedDriverEntry   The driver to insert on the ScheduledLink Queue\r
+\r
+**/\r
+VOID\r
+SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
+  IN  EFI_SMM_DRIVER_ENTRY   *InsertedDriverEntry\r
+  )\r
+{\r
+  LIST_ENTRY            *Link;\r
+  EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+\r
+  //\r
+  // Process Before Dependency\r
+  //\r
+  for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+    DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+    if (DriverEntry->Before && DriverEntry->Dependent) {\r
+      if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
+        //\r
+        // Recursively process BEFORE\r
+        //\r
+        SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Convert driver from Dependent to Scheduled state\r
+  //\r
+\r
+  InsertedDriverEntry->Dependent = FALSE;\r
+  InsertedDriverEntry->Scheduled = TRUE;\r
+  InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);\r
+\r
+\r
+  //\r
+  // Process After Dependency\r
+  //\r
+  for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+    DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+    if (DriverEntry->After && DriverEntry->Dependent) {\r
+      if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
+        //\r
+        // Recursively process AFTER\r
+        //\r
+        SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Return TRUE if the Fv has been processed, FALSE if not.\r
+\r
+  @param  FvHandle              The handle of a FV that's being tested\r
+\r
+  @retval TRUE                  Fv protocol on FvHandle has been processed\r
+  @retval FALSE                 Fv protocol on FvHandle has not yet been\r
+                                processed\r
+\r
+**/\r
+BOOLEAN\r
+FvHasBeenProcessed (\r
+  IN EFI_HANDLE  FvHandle\r
+  )\r
+{\r
+  LIST_ENTRY    *Link;\r
+  KNOWN_HANDLE  *KnownHandle;\r
+\r
+  for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {\r
+    KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);\r
+    if (KnownHandle->Handle == FvHandle) {\r
+      return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Remember that Fv protocol on FvHandle has had it's drivers placed on the\r
+  mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are\r
+  never removed/freed from the mFvHandleList.\r
+\r
+  @param  FvHandle              The handle of a FV that has been processed\r
+\r
+**/\r
+VOID\r
+FvIsBeingProcesssed (\r
+  IN EFI_HANDLE  FvHandle\r
+  )\r
+{\r
+  KNOWN_HANDLE  *KnownHandle;\r
+\r
+  KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));\r
+  ASSERT (KnownHandle != NULL);\r
+\r
+  KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;\r
+  KnownHandle->Handle = FvHandle;\r
+  InsertTailList (&mFvHandleList, &KnownHandle->Link);\r
+}\r
+\r
+/**\r
+  Convert FvHandle and DriverName into an EFI device path\r
+\r
+  @param  Fv                    Fv protocol, needed to read Depex info out of\r
+                                FLASH.\r
+  @param  FvHandle              Handle for Fv, needed in the\r
+                                EFI_SMM_DRIVER_ENTRY so that the PE image can be\r
+                                read out of the FV at a later time.\r
+  @param  DriverName            Name of driver to add to mDiscoveredList.\r
+\r
+  @return Pointer to device path constructed from FvHandle and DriverName\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+SmmFvToDevicePath (\r
+  IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,\r
+  IN  EFI_HANDLE                      FvHandle,\r
+  IN  EFI_GUID                        *DriverName\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_DEVICE_PATH_PROTOCOL            *FvDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL            *FileNameDevicePath;\r
+\r
+  //\r
+  // Remember the device path of the FV\r
+  //\r
+  Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    FileNameDevicePath = NULL;\r
+  } else {\r
+    //\r
+    // Build a device path to the file in the FV to pass into gBS->LoadImage\r
+    //\r
+    EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);\r
+    SetDevicePathEndNode (&mFvDevicePath.End);\r
+\r
+    //\r
+    // Note: FileNameDevicePath is in DXE memory\r
+    //\r
+    FileNameDevicePath = AppendDevicePath (\r
+                            FvDevicePath,\r
+                            (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
+                            );\r
+  }\r
+  return FileNameDevicePath;\r
+}\r
+\r
+/**\r
+  Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,\r
+  and initilize any state variables. Read the Depex from the FV and store it\r
+  in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.\r
+  The Discovered list is never free'ed and contains booleans that represent the\r
+  other possible SMM driver states.\r
+\r
+  @param  Fv                    Fv protocol, needed to read Depex info out of\r
+                                FLASH.\r
+  @param  FvHandle              Handle for Fv, needed in the\r
+                                EFI_SMM_DRIVER_ENTRY so that the PE image can be\r
+                                read out of the FV at a later time.\r
+  @param  DriverName            Name of driver to add to mDiscoveredList.\r
+\r
+  @retval EFI_SUCCESS           If driver was added to the mDiscoveredList.\r
+  @retval EFI_ALREADY_STARTED   The driver has already been started. Only one\r
+                                DriverName may be active in the system at any one\r
+                                time.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmAddToDriverList (\r
+  IN EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,\r
+  IN EFI_HANDLE                     FvHandle,\r
+  IN EFI_GUID                       *DriverName\r
+  )\r
+{\r
+  EFI_SMM_DRIVER_ENTRY  *DriverEntry;\r
+\r
+  //\r
+  // Create the Driver Entry for the list. ZeroPool initializes lots of variables to\r
+  // NULL or FALSE.\r
+  //\r
+  DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));\r
+  ASSERT (DriverEntry != NULL);\r
+\r
+  DriverEntry->Signature        = EFI_SMM_DRIVER_ENTRY_SIGNATURE;\r
+  CopyGuid (&DriverEntry->FileName, DriverName);\r
+  DriverEntry->FvHandle         = FvHandle;\r
+  DriverEntry->Fv               = Fv;\r
+  DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);\r
+\r
+  SmmGetDepexSectionAndPreProccess (DriverEntry);\r
+\r
+  InsertTailList (&mDiscoveredList, &DriverEntry->Link);\r
+  gRequestDispatch = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is the main entry point for an SMM handler dispatch\r
+  or communicate-based callback.\r
+\r
+  Event notification that is fired every time a FV dispatch protocol is added.\r
+  More than one protocol may have been added when this event is fired, so you\r
+  must loop on SmmLocateHandle () to see how many protocols were added and\r
+  do the following to each FV:\r
+  If the Fv has already been processed, skip it. If the Fv has not been\r
+  processed then mark it as being processed, as we are about to process it.\r
+  Read the Fv and add any driver in the Fv to the mDiscoveredList.The\r
+  mDiscoveredList is never free'ed and contains variables that define\r
+  the other states the SMM driver transitions to..\r
+  While you are at it read the A Priori file into memory.\r
+  Place drivers in the A Priori list onto the mScheduledQueue.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-SMM environment into an SMM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmDriverDispatchHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         HandleCount;\r
+  EFI_HANDLE                    *HandleBuffer;\r
+  EFI_STATUS                    GetNextFileStatus;\r
+  EFI_STATUS                    SecurityStatus;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+  EFI_DEVICE_PATH_PROTOCOL      *FvDevicePath;\r
+  EFI_HANDLE                    FvHandle;\r
+  EFI_GUID                      NameGuid;\r
+  UINTN                         Key;\r
+  EFI_FV_FILETYPE               Type;\r
+  EFI_FV_FILE_ATTRIBUTES        Attributes;\r
+  UINTN                         Size;\r
+  EFI_SMM_DRIVER_ENTRY          *DriverEntry;\r
+  EFI_GUID                      *AprioriFile;\r
+  UINTN                         AprioriEntryCount;\r
+  UINTN                         Index;\r
+  LIST_ENTRY                    *Link;\r
+  UINT32                        AuthenticationStatus;\r
+  UINTN                         SizeOfBuffer;\r
+\r
+  HandleBuffer = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolume2ProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    FvHandle = HandleBuffer[Index];\r
+\r
+    if (FvHasBeenProcessed (FvHandle)) {\r
+      //\r
+      // This Fv has already been processed so lets skip it!\r
+      //\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Since we are about to process this Fv mark it as processed.\r
+    //\r
+    FvIsBeingProcesssed (FvHandle);\r
+\r
+    Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.\r
+      //\r
+      ASSERT (FALSE);\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // The Firmware volume doesn't have device path, can't be dispatched.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // If the Security Architectural Protocol has not been located yet, then attempt to locate it\r
+    //\r
+    if (mSecurity == NULL) {\r
+      gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);\r
+    }\r
+\r
+    //\r
+    // Evaluate the authentication status of the Firmware Volume through\r
+    // Security Architectural Protocol\r
+    //\r
+    if (mSecurity != NULL) {\r
+      SecurityStatus = mSecurity->FileAuthenticationState (\r
+                                    mSecurity,\r
+                                    0,\r
+                                    FvDevicePath\r
+                                    );\r
+      if (SecurityStatus != EFI_SUCCESS) {\r
+        //\r
+        // Security check failed. The firmware volume should not be used for any purpose.\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Discover Drivers in FV and add them to the Discovered Driver List.\r
+    // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE\r
+    //\r
+    for (Index = 0; Index < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) {\r
+      //\r
+      // Initialize the search key\r
+      //\r
+      Key = 0;\r
+      do {\r
+        Type = mSmmFileTypes[Index];\r
+        GetNextFileStatus = Fv->GetNextFile (\r
+                                  Fv,\r
+                                  &Key,\r
+                                  &Type,\r
+                                  &NameGuid,\r
+                                  &Attributes,\r
+                                  &Size\r
+                                  );\r
+        if (!EFI_ERROR (GetNextFileStatus)) {\r
+          SmmAddToDriverList (Fv, FvHandle, &NameGuid);\r
+        }\r
+      } while (!EFI_ERROR (GetNextFileStatus));\r
+    }\r
+\r
+    //\r
+    // Read the array of GUIDs from the Apriori file if it is present in the firmware volume\r
+    // (Note: AprioriFile is in DXE memory)\r
+    //\r
+    AprioriFile = NULL;\r
+    Status = Fv->ReadSection (\r
+                  Fv,\r
+                  &gAprioriGuid,\r
+                  EFI_SECTION_RAW,\r
+                  0,\r
+                  (VOID **)&AprioriFile,\r
+                  &SizeOfBuffer,\r
+                  &AuthenticationStatus\r
+                  );\r
+    if (!EFI_ERROR (Status)) {\r
+      AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);\r
+    } else {\r
+      AprioriEntryCount = 0;\r
+    }\r
+\r
+    //\r
+    // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes\r
+    // drivers not in the current FV and these must be skipped since the a priori list\r
+    // is only valid for the FV that it resided in.\r
+    //\r
+\r
+    for (Index = 0; Index < AprioriEntryCount; Index++) {\r
+      for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+        DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+        if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&\r
+            (FvHandle == DriverEntry->FvHandle)) {\r
+          DriverEntry->Dependent = FALSE;\r
+          DriverEntry->Scheduled = TRUE;\r
+          InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Free data allocated by Fv->ReadSection ()\r
+    //\r
+    // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection \r
+    // used the UEFI Boot Services AllocatePool() function\r
+    //\r
+    gBS->FreePool (AprioriFile);\r
+  }\r
+\r
+  //\r
+  // Execute the SMM Dispatcher on any newly discovered FVs and previously \r
+  // discovered SMM drivers that have been discovered but not dispatched.\r
+  //\r
+  return SmmDispatcher ();\r
+}\r
+\r
+/**\r
+  Traverse the discovered list for any drivers that were discovered but not loaded\r
+  because the dependency experessions evaluated to false.\r
+\r
+**/\r
+VOID\r
+SmmDisplayDiscoveredNotDispatched (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY                   *Link;\r
+  EFI_SMM_DRIVER_ENTRY         *DriverEntry;\r
+\r
+  for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {\r
+    DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+    if (DriverEntry->Dependent) {\r
+      DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));\r
+    }\r
+  }\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Handle.c b/MdeModulePkg/Core/PiSmmCore/Handle.c
new file mode 100644 (file)
index 0000000..7625c38
--- /dev/null
@@ -0,0 +1,532 @@
+/** @file\r
+  SMM handle & protocol handling.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+//\r
+// mProtocolDatabase     - A list of all protocols in the system.  (simple list for now)\r
+// gHandleList           - A list of all the handles in the system\r
+//\r
+LIST_ENTRY  mProtocolDatabase  = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);\r
+LIST_ENTRY  gHandleList        = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);\r
+\r
+/**\r
+  Check whether a handle is a valid EFI_HANDLE\r
+\r
+  @param  UserHandle             The handle to check\r
+\r
+  @retval EFI_INVALID_PARAMETER  The handle is NULL or not a valid EFI_HANDLE.\r
+  @retval EFI_SUCCESS            The handle is valid EFI_HANDLE.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmValidateHandle (\r
+  IN EFI_HANDLE  UserHandle\r
+  )\r
+{\r
+  IHANDLE  *Handle;\r
+\r
+  Handle = (IHANDLE *)UserHandle;\r
+  if (Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (Handle->Signature != EFI_HANDLE_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Finds the protocol entry for the requested protocol.\r
+\r
+  @param  Protocol               The ID of the protocol\r
+  @param  Create                 Create a new entry if not found\r
+\r
+  @return Protocol entry\r
+\r
+**/\r
+PROTOCOL_ENTRY  *\r
+SmmFindProtocolEntry (\r
+  IN EFI_GUID   *Protocol,\r
+  IN BOOLEAN    Create\r
+  )\r
+{\r
+  LIST_ENTRY          *Link;\r
+  PROTOCOL_ENTRY      *Item;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+\r
+  //\r
+  // Search the database for the matching GUID\r
+  //\r
+\r
+  ProtEntry = NULL;\r
+  for (Link = mProtocolDatabase.ForwardLink;\r
+       Link != &mProtocolDatabase;\r
+       Link = Link->ForwardLink) {\r
+\r
+    Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);\r
+    if (CompareGuid (&Item->ProtocolID, Protocol)) {\r
+      //\r
+      // This is the protocol entry\r
+      //\r
+      ProtEntry = Item;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the protocol entry was not found and Create is TRUE, then\r
+  // allocate a new entry\r
+  //\r
+  if ((ProtEntry == NULL) && Create) {\r
+    ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));\r
+    if (ProtEntry != NULL) {\r
+      //\r
+      // Initialize new protocol entry structure\r
+      //\r
+      ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;\r
+      CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);\r
+      InitializeListHead (&ProtEntry->Protocols);\r
+      InitializeListHead (&ProtEntry->Notify);\r
+\r
+      //\r
+      // Add it to protocol database\r
+      //\r
+      InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);\r
+    }\r
+  }\r
+  return ProtEntry;\r
+}\r
+\r
+/**\r
+  Finds the protocol instance for the requested handle and protocol.\r
+  Note: This function doesn't do parameters checking, it's caller's responsibility\r
+  to pass in valid parameters.\r
+\r
+  @param  Handle                 The handle to search the protocol on\r
+  @param  Protocol               GUID of the protocol\r
+  @param  Interface              The interface for the protocol being searched\r
+\r
+  @return Protocol instance (NULL: Not found)\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmFindProtocolInterface (\r
+  IN IHANDLE   *Handle,\r
+  IN EFI_GUID  *Protocol,\r
+  IN VOID      *Interface\r
+  )\r
+{\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Prot = NULL;\r
+\r
+  //\r
+  // Lookup the protocol entry for this protocol ID\r
+  //\r
+  ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
+  if (ProtEntry != NULL) {\r
+    //\r
+    // Look at each protocol interface for any matches\r
+    //\r
+    for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {\r
+      //\r
+      // If this protocol interface matches, remove it\r
+      //\r
+      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+      if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {\r
+        break;\r
+      }\r
+      Prot = NULL;\r
+    }\r
+  }\r
+  return Prot;\r
+}\r
+\r
+/**\r
+  Wrapper function to SmmInstallProtocolInterfaceNotify.  This is the public API which\r
+  Calls the private one which contains a BOOLEAN parameter for notifications\r
+\r
+  @param  UserHandle             The handle to install the protocol handler on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  Protocol               The protocol to add to the handle\r
+  @param  InterfaceType          Indicates whether Interface is supplied in\r
+                                 native form.\r
+  @param  Interface              The interface for the protocol being added\r
+\r
+  @return Status code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallProtocolInterface (\r
+  IN OUT EFI_HANDLE      *UserHandle,\r
+  IN EFI_GUID            *Protocol,\r
+  IN EFI_INTERFACE_TYPE  InterfaceType,\r
+  IN VOID                *Interface\r
+  )\r
+{\r
+  return SmmInstallProtocolInterfaceNotify (\r
+           UserHandle,\r
+           Protocol,\r
+           InterfaceType,\r
+           Interface,\r
+           TRUE\r
+           );\r
+}\r
+\r
+/**\r
+  Installs a protocol interface into the boot services environment.\r
+\r
+  @param  UserHandle             The handle to install the protocol handler on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  Protocol               The protocol to add to the handle\r
+  @param  InterfaceType          Indicates whether Interface is supplied in\r
+                                 native form.\r
+  @param  Interface              The interface for the protocol being added\r
+  @param  Notify                 indicates whether notify the notification list\r
+                                 for this protocol\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate\r
+  @retval EFI_SUCCESS            Protocol interface successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+SmmInstallProtocolInterfaceNotify (\r
+  IN OUT EFI_HANDLE          *UserHandle,\r
+  IN     EFI_GUID            *Protocol,\r
+  IN     EFI_INTERFACE_TYPE  InterfaceType,\r
+  IN     VOID                *Interface,\r
+  IN     BOOLEAN             Notify\r
+  )\r
+{\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  IHANDLE             *Handle;\r
+  EFI_STATUS          Status;\r
+  VOID                *ExistingInterface;\r
+\r
+  //\r
+  // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.\r
+  // Also added check for invalid UserHandle and Protocol pointers.\r
+  //\r
+  if (UserHandle == NULL || Protocol == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (InterfaceType != EFI_NATIVE_INTERFACE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Print debug message\r
+  //\r
+  DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));\r
+\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+  Prot = NULL;\r
+  Handle = NULL;\r
+\r
+  if (*UserHandle != NULL) {\r
+    Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);\r
+    if (!EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Lookup the Protocol Entry for the requested protocol\r
+  //\r
+  ProtEntry = SmmFindProtocolEntry (Protocol, TRUE);\r
+  if (ProtEntry == NULL) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Allocate a new protocol interface structure\r
+  //\r
+  Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));\r
+  if (Prot == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // If caller didn't supply a handle, allocate a new one\r
+  //\r
+  Handle = (IHANDLE *)*UserHandle;\r
+  if (Handle == NULL) {\r
+    Handle = AllocateZeroPool (sizeof(IHANDLE));\r
+    if (Handle == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Initialize new handler structure\r
+    //\r
+    Handle->Signature = EFI_HANDLE_SIGNATURE;\r
+    InitializeListHead (&Handle->Protocols);\r
+\r
+    //\r
+    // Add this handle to the list global list of all handles\r
+    // in the system\r
+    //\r
+    InsertTailList (&gHandleList, &Handle->AllHandles);\r
+  }\r
+\r
+  Status = SmmValidateHandle (Handle);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Each interface that is added must be unique\r
+  //\r
+  ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL);\r
+\r
+  //\r
+  // Initialize the protocol interface structure\r
+  //\r
+  Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;\r
+  Prot->Handle = Handle;\r
+  Prot->Protocol = ProtEntry;\r
+  Prot->Interface = Interface;\r
+\r
+  //\r
+  // Add this protocol interface to the head of the supported\r
+  // protocol list for this handle\r
+  //\r
+  InsertHeadList (&Handle->Protocols, &Prot->Link);\r
+\r
+  //\r
+  // Add this protocol interface to the tail of the\r
+  // protocol entry\r
+  //\r
+  InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);\r
+\r
+  //\r
+  // Notify the notification list for this protocol\r
+  //\r
+  if (Notify) {\r
+    SmmNotifyProtocol (Prot);\r
+  }\r
+  Status = EFI_SUCCESS;\r
+\r
+Done:\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Return the new handle back to the caller\r
+    //\r
+    *UserHandle = Handle;\r
+  } else {\r
+    //\r
+    // There was an error, clean up\r
+    //\r
+    if (Prot != NULL) {\r
+      FreePool (Prot);\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Uninstalls all instances of a protocol:interfacer from a handle.\r
+  If the last protocol interface is remove from the handle, the\r
+  handle is freed.\r
+\r
+  @param  UserHandle             The handle to remove the protocol handler from\r
+  @param  Protocol               The protocol, of protocol:interface, to remove\r
+  @param  Interface              The interface, of protocol:interface, to remove\r
+\r
+  @retval EFI_INVALID_PARAMETER  Protocol is NULL.\r
+  @retval EFI_SUCCESS            Protocol interface successfully uninstalled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmUninstallProtocolInterface (\r
+  IN EFI_HANDLE  UserHandle,\r
+  IN EFI_GUID    *Protocol,\r
+  IN VOID        *Interface\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  IHANDLE             *Handle;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+\r
+  //\r
+  // Check that Protocol is valid\r
+  //\r
+  if (Protocol == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check that UserHandle is a valid handle\r
+  //\r
+  Status = SmmValidateHandle (UserHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check that Protocol exists on UserHandle, and Interface matches the interface in the database\r
+  //\r
+  Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface);\r
+  if (Prot == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Remove the protocol interface from the protocol\r
+  //\r
+  Status = EFI_NOT_FOUND;\r
+  Handle = (IHANDLE *)UserHandle;\r
+  Prot   = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);\r
+\r
+  if (Prot != NULL) {\r
+    //\r
+    // Remove the protocol interface from the handle\r
+    //\r
+    RemoveEntryList (&Prot->Link);\r
+\r
+    //\r
+    // Free the memory\r
+    //\r
+    Prot->Signature = 0;\r
+    FreePool (Prot);\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If there are no more handlers for the handle, free the handle\r
+  //\r
+  if (IsListEmpty (&Handle->Protocols)) {\r
+    Handle->Signature = 0;\r
+    RemoveEntryList (&Handle->AllHandles);\r
+    FreePool (Handle);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Locate a certain GUID protocol interface in a Handle's protocols.\r
+\r
+  @param  UserHandle             The handle to obtain the protocol interface on\r
+  @param  Protocol               The GUID of the protocol\r
+\r
+  @return The requested protocol interface for the handle\r
+\r
+**/\r
+PROTOCOL_INTERFACE  *\r
+SmmGetProtocolInterface (\r
+  IN EFI_HANDLE  UserHandle,\r
+  IN EFI_GUID    *Protocol\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  IHANDLE             *Handle;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Status = SmmValidateHandle (UserHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Handle = (IHANDLE *)UserHandle;\r
+\r
+  //\r
+  // Look at each protocol interface for a match\r
+  //\r
+  for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
+    Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+    ProtEntry = Prot->Protocol;\r
+    if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {\r
+      return Prot;\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Queries a handle to determine if it supports a specified protocol.\r
+\r
+  @param  UserHandle             The handle being queried.\r
+  @param  Protocol               The published unique identifier of the protocol.\r
+  @param  Interface              Supplies the address where a pointer to the\r
+                                 corresponding Protocol Interface is returned.\r
+\r
+  @retval EFI_SUCCESS            The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED        The device does not support the specified protocol.\r
+  @retval EFI_INVALID_PARAMETER  Handle is not a valid EFI_HANDLE..\r
+  @retval EFI_INVALID_PARAMETER  Protocol is NULL.\r
+  @retval EFI_INVALID_PARAMETER  Interface is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmHandleProtocol (\r
+  IN  EFI_HANDLE  UserHandle,\r
+  IN  EFI_GUID    *Protocol,\r
+  OUT VOID        **Interface\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+\r
+  //\r
+  // Check for invalid Protocol\r
+  //\r
+  if (Protocol == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check for invalid Interface\r
+  //\r
+  if (Interface == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } else {\r
+    *Interface = NULL;\r
+  }\r
+\r
+  //\r
+  // Check for invalid UserHandle\r
+  //\r
+  Status = SmmValidateHandle (UserHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Look at each protocol interface for a match\r
+  //\r
+  Prot = SmmGetProtocolInterface (UserHandle, Protocol);\r
+  if (Prot == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // This is the protocol interface entry for this protocol\r
+  //\r
+  *Interface = Prot->Interface;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c b/MdeModulePkg/Core/PiSmmCore/InstallConfigurationTable.c
new file mode 100644 (file)
index 0000000..9623fae
--- /dev/null
@@ -0,0 +1,161 @@
+/** @file\r
+  System Management System Table Services SmmInstallConfigurationTable service\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+#define CONFIG_TABLE_SIZE_INCREASED 0x10\r
+\r
+UINTN  mSmmSystemTableAllocateSize = 0;\r
+\r
+/**\r
+  The SmmInstallConfigurationTable() function is used to maintain the list\r
+  of configuration tables that are stored in the System Management System\r
+  Table.  The list is stored as an array of (GUID, Pointer) pairs.  The list\r
+  must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.\r
+\r
+  @param  SystemTable      A pointer to the SMM System Table (SMST).\r
+  @param  Guid             A pointer to the GUID for the entry to add, update, or remove.\r
+  @param  Table            A pointer to the buffer of the table to add.\r
+  @param  TableSize        The size of the table to install.\r
+\r
+  @retval EFI_SUCCESS           The (Guid, Table) pair was added, updated, or removed.\r
+  @retval EFI_INVALID_PARAMETER Guid is not valid.\r
+  @retval EFI_NOT_FOUND         An attempt was made to delete a non-existent entry.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough memory available to complete the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallConfigurationTable (\r
+  IN  CONST EFI_SMM_SYSTEM_TABLE2  *SystemTable,\r
+  IN  CONST EFI_GUID               *Guid,\r
+  IN  VOID                         *Table,\r
+  IN  UINTN                        TableSize\r
+  )\r
+{\r
+  UINTN                    Index;\r
+  EFI_CONFIGURATION_TABLE  *ConfigurationTable;\r
+\r
+  //\r
+  // If Guid is NULL, then this operation cannot be performed\r
+  //\r
+  if (Guid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ConfigurationTable = gSmmCoreSmst.SmmConfigurationTable;\r
+\r
+  //\r
+  // Search all the table for an entry that matches Guid\r
+  //\r
+  for (Index = 0; Index < gSmmCoreSmst.NumberOfTableEntries; Index++) {\r
+    if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index < gSmmCoreSmst.NumberOfTableEntries) {\r
+    //\r
+    // A match was found, so this is either a modify or a delete operation\r
+    //\r
+    if (Table != NULL) {\r
+      //\r
+      // If Table is not NULL, then this is a modify operation.\r
+      // Modify the table enty and return.\r
+      //\r
+      ConfigurationTable[Index].VendorTable = Table;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // A match was found and Table is NULL, so this is a delete operation.\r
+    //\r
+    gSmmCoreSmst.NumberOfTableEntries--;\r
+\r
+    //\r
+    // Copy over deleted entry\r
+    //\r
+    CopyMem (\r
+      &(ConfigurationTable[Index]),\r
+      &(ConfigurationTable[Index + 1]),\r
+      (gSmmCoreSmst.NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)\r
+      );\r
+\r
+  } else {\r
+    //\r
+    // No matching GUIDs were found, so this is an add operation.\r
+    //\r
+    if (Table == NULL) {\r
+      //\r
+      // If Table is NULL on an add operation, then return an error.\r
+      //\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    //\r
+    // Assume that Index == gSmmCoreSmst.NumberOfTableEntries\r
+    //\r
+    if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSmmSystemTableAllocateSize) {\r
+      //\r
+      // Allocate a table with one additional entry.\r
+      //\r
+      mSmmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));\r
+      ConfigurationTable = AllocatePool (mSmmSystemTableAllocateSize);\r
+      if (ConfigurationTable == NULL) {\r
+        //\r
+        // If a new table could not be allocated, then return an error.\r
+        //\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      if (gSmmCoreSmst.SmmConfigurationTable != NULL) {\r
+        //\r
+        // Copy the old table to the new table.\r
+        //\r
+        CopyMem (\r
+          ConfigurationTable,\r
+          gSmmCoreSmst.SmmConfigurationTable,\r
+          Index * sizeof (EFI_CONFIGURATION_TABLE)\r
+          );\r
+\r
+        //\r
+        // Free Old Table\r
+        //\r
+        FreePool (gSmmCoreSmst.SmmConfigurationTable);\r
+      }\r
+\r
+      //\r
+      // Update System Table\r
+      //\r
+      gSmmCoreSmst.SmmConfigurationTable = ConfigurationTable;\r
+    }\r
+\r
+    //\r
+    // Fill in the new entry\r
+    //\r
+    CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid);\r
+    ConfigurationTable[Index].VendorTable = Table;\r
+\r
+    //\r
+    // This is an add operation, so increment the number of table entries\r
+    //\r
+    gSmmCoreSmst.NumberOfTableEntries++;\r
+  }\r
+\r
+  //\r
+  // CRC-32 field is ignorable for SMM System Table and should be set to zero\r
+  //\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Locate.c b/MdeModulePkg/Core/PiSmmCore/Locate.c
new file mode 100644 (file)
index 0000000..585d3c8
--- /dev/null
@@ -0,0 +1,499 @@
+/** @file\r
+  Locate handle functions\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+//\r
+// ProtocolRequest - Last LocateHandle request ID\r
+//\r
+UINTN mEfiLocateHandleRequest = 0;\r
+\r
+//\r
+// Internal prototypes\r
+//\r
+\r
+typedef struct {\r
+  EFI_GUID        *Protocol;\r
+  VOID            *SearchKey;\r
+  LIST_ENTRY      *Position;\r
+  PROTOCOL_ENTRY  *ProtEntry;\r
+} LOCATE_POSITION;\r
+\r
+typedef\r
+IHANDLE *\r
+(* CORE_GET_NEXT) (\r
+  IN OUT LOCATE_POSITION    *Position,\r
+  OUT VOID                  **Interface\r
+  );\r
+\r
+/**\r
+  Routine to get the next Handle, when you are searching for all handles.\r
+\r
+  @param  Position               Information about which Handle to seach for.\r
+  @param  Interface              Return the interface structure for the matching\r
+                                 protocol.\r
+\r
+  @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+          Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+SmmGetNextLocateAllHandles (\r
+  IN OUT LOCATE_POSITION  *Position,\r
+  OUT    VOID             **Interface\r
+  )\r
+{\r
+  IHANDLE     *Handle;\r
+\r
+  //\r
+  // Next handle\r
+  //\r
+  Position->Position = Position->Position->ForwardLink;\r
+\r
+  //\r
+  // If not at the end of the list, get the handle\r
+  //\r
+  Handle      = NULL;\r
+  *Interface  = NULL;\r
+  if (Position->Position != &gHandleList) {\r
+    Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);\r
+  }\r
+  return Handle;\r
+}\r
+\r
+/**\r
+  Routine to get the next Handle, when you are searching for register protocol\r
+  notifies.\r
+\r
+  @param  Position               Information about which Handle to seach for.\r
+  @param  Interface              Return the interface structure for the matching\r
+                                 protocol.\r
+\r
+  @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+          Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+SmmGetNextLocateByRegisterNotify (\r
+  IN OUT LOCATE_POSITION  *Position,\r
+  OUT    VOID             **Interface\r
+  )\r
+{\r
+  IHANDLE             *Handle;\r
+  PROTOCOL_NOTIFY     *ProtNotify;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Handle      = NULL;\r
+  *Interface  = NULL;\r
+  ProtNotify = Position->SearchKey;\r
+\r
+  //\r
+  // If this is the first request, get the next handle\r
+  //\r
+  if (ProtNotify != NULL) {\r
+    ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);\r
+    Position->SearchKey = NULL;\r
+\r
+    //\r
+    // If not at the end of the list, get the next handle\r
+    //\r
+    Link = ProtNotify->Position->ForwardLink;\r
+    if (Link != &ProtNotify->Protocol->Protocols) {\r
+      Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
+      Handle = Prot->Handle;\r
+      *Interface = Prot->Interface;\r
+    }\r
+  }\r
+  return Handle;\r
+}\r
+\r
+/**\r
+  Routine to get the next Handle, when you are searching for a given protocol.\r
+\r
+  @param  Position               Information about which Handle to seach for.\r
+  @param  Interface              Return the interface structure for the matching\r
+                                 protocol.\r
+\r
+  @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+          Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+SmmGetNextLocateByProtocol (\r
+  IN OUT LOCATE_POSITION  *Position,\r
+  OUT    VOID             **Interface\r
+  )\r
+{\r
+  IHANDLE             *Handle;\r
+  LIST_ENTRY          *Link;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+\r
+  Handle      = NULL;\r
+  *Interface  = NULL;\r
+  for (; ;) {\r
+    //\r
+    // Next entry\r
+    //\r
+    Link = Position->Position->ForwardLink;\r
+    Position->Position = Link;\r
+\r
+    //\r
+    // If not at the end, return the handle\r
+    //\r
+    if (Link == &Position->ProtEntry->Protocols) {\r
+      Handle = NULL;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Get the handle\r
+    //\r
+    Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
+    Handle = Prot->Handle;\r
+    *Interface = Prot->Interface;\r
+\r
+    //\r
+    // If this handle has not been returned this request, then\r
+    // return it now\r
+    //\r
+    if (Handle->LocateRequest != mEfiLocateHandleRequest) {\r
+      Handle->LocateRequest = mEfiLocateHandleRequest;\r
+      break;\r
+    }\r
+  }\r
+  return Handle;\r
+}\r
+\r
+/**\r
+  Return the first Protocol Interface that matches the Protocol GUID. If\r
+  Registration is pasased in return a Protocol Instance that was just add\r
+  to the system. If Retistration is NULL return the first Protocol Interface\r
+  you find.\r
+\r
+  @param  Protocol               The protocol to search for\r
+  @param  Registration           Optional Registration Key returned from\r
+                                 RegisterProtocolNotify()\r
+  @param  Interface              Return the Protocol interface (instance).\r
+\r
+  @retval EFI_SUCCESS            If a valid Interface is returned\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_NOT_FOUND          Protocol interface not found\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateProtocol (\r
+  IN  EFI_GUID  *Protocol,\r
+  IN  VOID      *Registration OPTIONAL,\r
+  OUT VOID      **Interface\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  LOCATE_POSITION         Position;\r
+  PROTOCOL_NOTIFY         *ProtNotify;\r
+  IHANDLE                 *Handle;\r
+\r
+  if (Interface == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Protocol == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Interface = NULL;\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Set initial position\r
+  //\r
+  Position.Protocol  = Protocol;\r
+  Position.SearchKey = Registration;\r
+  Position.Position  = &gHandleList;\r
+\r
+  mEfiLocateHandleRequest += 1;\r
+\r
+  if (Registration == NULL) {\r
+    //\r
+    // Look up the protocol entry and set the head pointer\r
+    //\r
+    Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
+    if (Position.ProtEntry == NULL) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    Position.Position = &Position.ProtEntry->Protocols;\r
+\r
+    Handle = SmmGetNextLocateByProtocol (&Position, Interface);\r
+  } else {\r
+    Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface);\r
+  }\r
+\r
+  if (Handle == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
+  } else if (Registration != NULL) {\r
+    //\r
+    // If this is a search by register notify and a handle was\r
+    // returned, update the register notification position\r
+    //\r
+    ProtNotify = Registration;\r
+    ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Locates the requested handle(s) and returns them in Buffer.\r
+\r
+  @param  SearchType             The type of search to perform to locate the\r
+                                 handles\r
+  @param  Protocol               The protocol to search for\r
+  @param  SearchKey              Dependant on SearchType\r
+  @param  BufferSize             On input the size of Buffer.  On output the\r
+                                 size of data returned.\r
+  @param  Buffer                 The buffer to return the results in\r
+\r
+  @retval EFI_BUFFER_TOO_SMALL   Buffer too small, required buffer size is\r
+                                 returned in BufferSize.\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_SUCCESS            Successfully found the requested handle(s) and\r
+                                 returns them in Buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateHandle (\r
+  IN     EFI_LOCATE_SEARCH_TYPE  SearchType,\r
+  IN     EFI_GUID                *Protocol   OPTIONAL,\r
+  IN     VOID                    *SearchKey  OPTIONAL,\r
+  IN OUT UINTN                   *BufferSize,\r
+  OUT    EFI_HANDLE              *Buffer\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  LOCATE_POSITION  Position;\r
+  PROTOCOL_NOTIFY  *ProtNotify;\r
+  CORE_GET_NEXT    GetNext;\r
+  UINTN            ResultSize;\r
+  IHANDLE          *Handle;\r
+  IHANDLE          **ResultBuffer;\r
+  VOID             *Interface;\r
+\r
+  if (BufferSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*BufferSize > 0) && (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  GetNext = NULL;\r
+\r
+  //\r
+  // Set initial position\r
+  //\r
+  Position.Protocol  = Protocol;\r
+  Position.SearchKey = SearchKey;\r
+  Position.Position  = &gHandleList;\r
+\r
+  ResultSize = 0;\r
+  ResultBuffer = (IHANDLE **) Buffer;\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Get the search function based on type\r
+  //\r
+  switch (SearchType) {\r
+  case AllHandles:\r
+    GetNext = SmmGetNextLocateAllHandles;\r
+    break;\r
+\r
+  case ByRegisterNotify:\r
+    //\r
+    // Must have SearchKey for locate ByRegisterNotify\r
+    //\r
+    if (SearchKey == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      break;\r
+    }\r
+    GetNext = SmmGetNextLocateByRegisterNotify;\r
+    break;\r
+\r
+  case ByProtocol:\r
+    GetNext = SmmGetNextLocateByProtocol;\r
+    if (Protocol == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      break;\r
+    }\r
+    //\r
+    // Look up the protocol entry and set the head pointer\r
+    //\r
+    Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
+    if (Position.ProtEntry == NULL) {\r
+      Status = EFI_NOT_FOUND;\r
+      break;\r
+    }\r
+    Position.Position = &Position.ProtEntry->Protocols;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    break;\r
+  }\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Enumerate out the matching handles\r
+  //\r
+  mEfiLocateHandleRequest += 1;\r
+  for (; ;) {\r
+    //\r
+    // Get the next handle.  If no more handles, stop\r
+    //\r
+    Handle = GetNext (&Position, &Interface);\r
+    if (NULL == Handle) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Increase the resulting buffer size, and if this handle\r
+    // fits return it\r
+    //\r
+    ResultSize += sizeof(Handle);\r
+    if (ResultSize <= *BufferSize) {\r
+        *ResultBuffer = Handle;\r
+        ResultBuffer += 1;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the result is a zero length buffer, then there were no\r
+  // matching handles\r
+  //\r
+  if (ResultSize == 0) {\r
+    Status = EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // Return the resulting buffer size.  If it's larger than what\r
+    // was passed, then set the error code\r
+    //\r
+    if (ResultSize > *BufferSize) {\r
+      Status = EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    *BufferSize = ResultSize;\r
+\r
+    if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {\r
+      //\r
+      // If this is a search by register notify and a handle was\r
+      // returned, update the register notification position\r
+      //\r
+      ProtNotify = SearchKey;\r
+      ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Function returns an array of handles that support the requested protocol\r
+  in a buffer allocated from pool. This is a version of SmmLocateHandle()\r
+  that allocates a buffer for the caller.\r
+\r
+  @param  SearchType             Specifies which handle(s) are to be returned.\r
+  @param  Protocol               Provides the protocol to search by.    This\r
+                                 parameter is only valid for SearchType\r
+                                 ByProtocol.\r
+  @param  SearchKey              Supplies the search key depending on the\r
+                                 SearchType.\r
+  @param  NumberHandles          The number of handles returned in Buffer.\r
+  @param  Buffer                 A pointer to the buffer to return the requested\r
+                                 array of  handles that support Protocol.\r
+\r
+  @retval EFI_SUCCESS            The result array of handles was returned.\r
+  @retval EFI_NOT_FOUND          No handles match the search.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the\r
+                                 matching results.\r
+  @retval EFI_INVALID_PARAMETER  One or more paramters are not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateHandleBuffer (\r
+  IN     EFI_LOCATE_SEARCH_TYPE  SearchType,\r
+  IN     EFI_GUID                *Protocol OPTIONAL,\r
+  IN     VOID                    *SearchKey OPTIONAL,\r
+  IN OUT UINTN                   *NumberHandles,\r
+  OUT    EFI_HANDLE              **Buffer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BufferSize;\r
+\r
+  if (NumberHandles == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BufferSize = 0;\r
+  *NumberHandles = 0;\r
+  *Buffer = NULL;\r
+  Status = SmmLocateHandle (\r
+             SearchType,\r
+             Protocol,\r
+             SearchKey,\r
+             &BufferSize,\r
+             *Buffer\r
+             );\r
+  //\r
+  // LocateHandleBuffer() returns incorrect status code if SearchType is\r
+  // invalid.\r
+  //\r
+  // Add code to correctly handle expected errors from SmmLocateHandle().\r
+  //\r
+  if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+    if (Status != EFI_INVALID_PARAMETER) {\r
+      Status = EFI_NOT_FOUND;\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  *Buffer = AllocatePool (BufferSize);\r
+  if (*Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = SmmLocateHandle (\r
+             SearchType,\r
+             Protocol,\r
+             SearchKey,\r
+             &BufferSize,\r
+             *Buffer\r
+             );\r
+\r
+  *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
+  if (EFI_ERROR(Status)) {\r
+    *NumberHandles = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Notify.c b/MdeModulePkg/Core/PiSmmCore/Notify.c
new file mode 100644 (file)
index 0000000..8654f6e
--- /dev/null
@@ -0,0 +1,170 @@
+/** @file\r
+  Support functions for UEFI protocol notification infrastructure.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+/**\r
+  Signal event for every protocol in protocol entry.\r
+\r
+  @param  Prot                   Protocol interface\r
+\r
+**/\r
+VOID\r
+SmmNotifyProtocol (\r
+  IN PROTOCOL_INTERFACE  *Prot\r
+  )\r
+{\r
+  PROTOCOL_ENTRY   *ProtEntry;\r
+  PROTOCOL_NOTIFY  *ProtNotify;\r
+  LIST_ENTRY       *Link;\r
+\r
+  ProtEntry = Prot->Protocol;\r
+  for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+    ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+    ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);\r
+  }\r
+}\r
+\r
+/**\r
+  Removes Protocol from the protocol list (but not the handle list).\r
+\r
+  @param  Handle                 The handle to remove protocol on.\r
+  @param  Protocol               GUID of the protocol to be moved\r
+  @param  Interface              The interface of the protocol\r
+\r
+  @return Protocol Entry\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmRemoveInterfaceFromProtocol (\r
+  IN IHANDLE   *Handle,\r
+  IN EFI_GUID  *Protocol,\r
+  IN VOID      *Interface\r
+  )\r
+{\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  PROTOCOL_NOTIFY     *ProtNotify;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Prot = SmmFindProtocolInterface (Handle, Protocol, Interface);\r
+  if (Prot != NULL) {\r
+\r
+    ProtEntry = Prot->Protocol;\r
+\r
+    //\r
+    // If there's a protocol notify location pointing to this entry, back it up one\r
+    //\r
+    for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+      ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+\r
+      if (ProtNotify->Position == &Prot->ByProtocol) {\r
+        ProtNotify->Position = Prot->ByProtocol.BackLink;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Remove the protocol interface entry\r
+    //\r
+    RemoveEntryList (&Prot->ByProtocol);\r
+  }\r
+\r
+  return Prot;\r
+}\r
+\r
+/**\r
+  Add a new protocol notification record for the request protocol.\r
+\r
+  @param  Protocol               The requested protocol to add the notify\r
+                                 registration\r
+  @param  Function               Points to the notification function\r
+  @param  Registration           Returns the registration record\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_SUCCESS            Successfully returned the registration record\r
+                                 that has been added\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmRegisterProtocolNotify (\r
+  IN  CONST EFI_GUID     *Protocol,\r
+  IN  EFI_SMM_NOTIFY_FN  Function,\r
+  OUT VOID               **Registration\r
+  )\r
+{\r
+  PROTOCOL_ENTRY   *ProtEntry;\r
+  PROTOCOL_NOTIFY  *ProtNotify;\r
+  LIST_ENTRY       *Link;\r
+  EFI_STATUS       Status;\r
+\r
+  if ((Protocol == NULL) || (Function == NULL) || (Registration == NULL))  {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ProtNotify = NULL;\r
+\r
+  //\r
+  // Get the protocol entry to add the notification too\r
+  //\r
+  ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);\r
+  if (ProtEntry != NULL) {\r
+    //\r
+    // Find whether notification already exist\r
+    //\r
+    for (Link = ProtEntry->Notify.ForwardLink;\r
+         Link != &ProtEntry->Notify;\r
+         Link = Link->ForwardLink) {\r
+\r
+      ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+      if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&\r
+          (ProtNotify->Function == Function)) {\r
+\r
+        //\r
+        // Notification already exist\r
+        //\r
+        *Registration = ProtNotify;\r
+\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Allocate a new notification record\r
+    //\r
+    ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));\r
+    if (ProtNotify != NULL) {\r
+      ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;\r
+      ProtNotify->Protocol = ProtEntry;\r
+      ProtNotify->Function = Function;\r
+      //\r
+      // Start at the ending\r
+      //\r
+      ProtNotify->Position = ProtEntry->Protocols.BackLink;\r
+\r
+      InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Done.  If we have a protocol notify entry, then return it.\r
+  // Otherwise, we must have run out of resources trying to add one\r
+  //\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+  if (ProtNotify != NULL) {\r
+    *Registration = ProtNotify;\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Page.c b/MdeModulePkg/Core/PiSmmCore/Page.c
new file mode 100644 (file)
index 0000000..ec4dd4f
--- /dev/null
@@ -0,0 +1,318 @@
+/** @file\r
+  SMM Memory page management functions.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+#define TRUNCATE_TO_PAGES(a)  ((a) >> EFI_PAGE_SHIFT)\r
+\r
+typedef struct {\r
+  LIST_ENTRY  Link;\r
+  UINTN       NumberOfPages;\r
+} FREE_PAGE_LIST;\r
+\r
+LIST_ENTRY  mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);\r
+\r
+/**\r
+  Internal Function. Allocate n pages from given free page node.\r
+\r
+  @param  Pages                  The free page node.\r
+  @param  NumberOfPages          Number of pages to be allocated.\r
+  @param  MaxAddress             Request to allocate memory below this address.\r
+\r
+  @return Memory address of allocated pages.\r
+\r
+**/\r
+UINTN\r
+InternalAllocPagesOnOneNode (\r
+  IN OUT FREE_PAGE_LIST  *Pages,\r
+  IN     UINTN           NumberOfPages,\r
+  IN     UINTN           MaxAddress\r
+  )\r
+{\r
+  UINTN           Top;\r
+  UINTN           Bottom;\r
+  FREE_PAGE_LIST  *Node;\r
+\r
+  Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);\r
+  if (Top > Pages->NumberOfPages) {\r
+    Top = Pages->NumberOfPages;\r
+  }\r
+  Bottom = Top - NumberOfPages;\r
+\r
+  if (Top < Pages->NumberOfPages) {\r
+    Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));\r
+    Node->NumberOfPages = Pages->NumberOfPages - Top;\r
+    InsertHeadList (&Pages->Link, &Node->Link);\r
+  }\r
+\r
+  if (Bottom > 0) {\r
+    Pages->NumberOfPages = Bottom;\r
+  } else {\r
+    RemoveEntryList (&Pages->Link);\r
+  }\r
+\r
+  return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);\r
+}\r
+\r
+/**\r
+  Internal Function. Allocate n pages from free page list below MaxAddress.\r
+\r
+  @param  FreePageList           The free page node.\r
+  @param  NumberOfPages          Number of pages to be allocated.\r
+  @param  MaxAddress             Request to allocate memory below this address.\r
+\r
+  @return Memory address of allocated pages.\r
+\r
+**/\r
+UINTN\r
+InternalAllocMaxAddress (\r
+  IN OUT LIST_ENTRY  *FreePageList,\r
+  IN     UINTN       NumberOfPages,\r
+  IN     UINTN       MaxAddress\r
+  )\r
+{\r
+  LIST_ENTRY      *Node;\r
+  FREE_PAGE_LIST  *Pages;\r
+\r
+  for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {\r
+    Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+    if (Pages->NumberOfPages >= NumberOfPages &&\r
+        (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {\r
+      return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);\r
+    }\r
+  }\r
+  return (UINTN)(-1);\r
+}\r
+\r
+/**\r
+  Internal Function. Allocate n pages from free page list at given address.\r
+\r
+  @param  FreePageList           The free page node.\r
+  @param  NumberOfPages          Number of pages to be allocated.\r
+  @param  MaxAddress             Request to allocate memory below this address.\r
+\r
+  @return Memory address of allocated pages.\r
+\r
+**/\r
+UINTN\r
+InternalAllocAddress (\r
+  IN OUT LIST_ENTRY  *FreePageList,\r
+  IN     UINTN       NumberOfPages,\r
+  IN     UINTN       Address\r
+  )\r
+{\r
+  UINTN           EndAddress;\r
+  LIST_ENTRY      *Node;\r
+  FREE_PAGE_LIST  *Pages;\r
+\r
+  if ((Address & EFI_PAGE_MASK) != 0) {\r
+    return ~Address;\r
+  }\r
+\r
+  EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);\r
+  for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {\r
+    Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+    if ((UINTN)Pages <= Address) {\r
+      if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {\r
+        break;\r
+      }\r
+      return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);\r
+    }\r
+  }\r
+  return ~Address;\r
+}\r
+\r
+/**\r
+  Allocates pages from the memory map.\r
+\r
+  @param  Type                   The type of allocation to perform.\r
+  @param  MemoryType             The type of memory to turn the allocated pages\r
+                                 into.\r
+  @param  NumberOfPages          The number of pages to allocate.\r
+  @param  Memory                 A pointer to receive the base allocated memory\r
+                                 address.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in spec.\r
+  @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.\r
+  @retval EFI_SUCCESS            Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePages (\r
+  IN  EFI_ALLOCATE_TYPE     Type,\r
+  IN  EFI_MEMORY_TYPE       MemoryType,\r
+  IN  UINTN                 NumberOfPages,\r
+  OUT EFI_PHYSICAL_ADDRESS  *Memory\r
+  )\r
+{\r
+  UINTN  RequestedAddress;\r
+\r
+  if (MemoryType != EfiRuntimeServicesCode &&\r
+      MemoryType != EfiRuntimeServicesData) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // We don't track memory type in SMM\r
+  //\r
+  RequestedAddress = (UINTN)*Memory;\r
+  switch (Type) {\r
+    case AllocateAnyPages:\r
+      RequestedAddress = (UINTN)(-1);\r
+    case AllocateMaxAddress:\r
+      *Memory = InternalAllocMaxAddress (\r
+                  &mSmmMemoryMap,\r
+                  NumberOfPages,\r
+                  RequestedAddress\r
+                  );\r
+      if (*Memory == (UINTN)-1) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      } \r
+      break;\r
+    case AllocateAddress:\r
+      *Memory = InternalAllocAddress (\r
+                  &mSmmMemoryMap,\r
+                  NumberOfPages,\r
+                  RequestedAddress\r
+                  );\r
+      if (*Memory != RequestedAddress) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+      break;\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Internal Function. Merge two adjacent nodes.\r
+\r
+  @param  First             The first of two nodes to merge.\r
+\r
+  @return Pointer to node after merge (if success) or pointer to next node (if fail).\r
+\r
+**/\r
+FREE_PAGE_LIST *\r
+InternalMergeNodes (\r
+  IN FREE_PAGE_LIST  *First\r
+  )\r
+{\r
+  FREE_PAGE_LIST  *Next;\r
+\r
+  Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);\r
+  ASSERT (\r
+    TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);\r
+\r
+  if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {\r
+    First->NumberOfPages += Next->NumberOfPages;\r
+    RemoveEntryList (&Next->Link);\r
+    Next = First;\r
+  }\r
+  return Next;\r
+}\r
+\r
+/**\r
+  Frees previous allocated pages.\r
+\r
+  @param  Memory                 Base address of memory being freed.\r
+  @param  NumberOfPages          The number of pages to free.\r
+\r
+  @retval EFI_NOT_FOUND          Could not find the entry that covers the range.\r
+  @retval EFI_INVALID_PARAMETER  Address not aligned.\r
+  @return EFI_SUCCESS            Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePages (\r
+  IN EFI_PHYSICAL_ADDRESS  Memory,\r
+  IN UINTN                 NumberOfPages\r
+  )\r
+{\r
+  LIST_ENTRY      *Node;\r
+  FREE_PAGE_LIST  *Pages;\r
+\r
+  if ((Memory & EFI_PAGE_MASK) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Pages = NULL;\r
+  Node = mSmmMemoryMap.ForwardLink;\r
+  while (Node != &mSmmMemoryMap) {\r
+    Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+    if (Memory < (UINTN)Pages) {\r
+      break;\r
+    }\r
+    Node = Node->ForwardLink;\r
+  }\r
+\r
+  if (Node != &mSmmMemoryMap &&\r
+      Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Node->BackLink != &mSmmMemoryMap) {\r
+    Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);\r
+    if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  Pages = (FREE_PAGE_LIST*)(UINTN)Memory;\r
+  Pages->NumberOfPages = NumberOfPages;\r
+  InsertTailList (Node, &Pages->Link);\r
+\r
+  if (Pages->Link.BackLink != &mSmmMemoryMap) {\r
+    Pages = InternalMergeNodes (\r
+              BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)\r
+              );\r
+  }\r
+\r
+  if (Node != &mSmmMemoryMap) {\r
+    InternalMergeNodes (Pages);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Add free SMRAM region for use by memory service.\r
+\r
+  @param  MemBase                Base address of memory region.\r
+  @param  MemLength              Length of the memory region.\r
+  @param  Type                   Memory type.\r
+  @param  Attributes             Memory region state.\r
+\r
+**/\r
+VOID\r
+SmmAddMemoryRegion (\r
+  IN  EFI_PHYSICAL_ADDRESS  MemBase,\r
+  IN  UINT64                MemLength,\r
+  IN  EFI_MEMORY_TYPE       Type,\r
+  IN  UINT64                Attributes\r
+  )\r
+{\r
+  UINTN  AlignedMemBase;\r
+\r
+  AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
+  MemLength -= AlignedMemBase - MemBase;\r
+  SmmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
new file mode 100644 (file)
index 0000000..0a50b5b
--- /dev/null
@@ -0,0 +1,363 @@
+/** @file\r
+  SMM Core Main Entry Point\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+//\r
+// Physical pointer to private structure shared between SMM IPL and the SMM Core\r
+//\r
+SMM_CORE_PRIVATE_DATA  *gSmmCorePrivate;\r
+\r
+//\r
+// SMM Core global variable for SMM System Table.  Only accessed as a physical structure in SMRAM.\r
+//\r
+EFI_SMM_SYSTEM_TABLE2  gSmmCoreSmst = {\r
+  {\r
+    SMM_SMST_SIGNATURE,\r
+    EFI_SMM_SYSTEM_TABLE2_REVISION,\r
+    sizeof (gSmmCoreSmst.Hdr)\r
+  },\r
+  NULL,                          // SmmFirmwareVendor\r
+  0,                             // SmmFirmwareRevision\r
+  SmmInstallConfigurationTable,\r
+  {\r
+    {\r
+      (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5,       // SmmMemRead\r
+      (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5        // SmmMemWrite\r
+    },\r
+    {\r
+      (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5,       // SmmIoRead\r
+      (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5        // SmmIoWrite\r
+    }\r
+  },\r
+  SmmAllocatePool,\r
+  SmmFreePool,\r
+  SmmAllocatePages,\r
+  SmmFreePages,\r
+  NULL,                          // SmmStartupThisAp\r
+  0,                             // CurrentlyExecutingCpu\r
+  0,                             // NumberOfCpus\r
+  NULL,                          // CpuSaveStateSize\r
+  NULL,                          // CpuSaveState\r
+  0,                             // NumberOfTableEntries\r
+  NULL,                          // SmmConfigurationTable\r
+  SmmInstallProtocolInterface,\r
+  SmmUninstallProtocolInterface,\r
+  SmmHandleProtocol,\r
+  SmmRegisterProtocolNotify,\r
+  SmmLocateHandle,\r
+  SmmLocateProtocol,\r
+  SmiManage,\r
+  SmiHandlerRegister,\r
+  SmiHandlerUnRegister\r
+};\r
+\r
+//\r
+// Flag to determine if the platform has performed a legacy boot.\r
+// If this flag is TRUE, then the runtime code and runtime data associated with the \r
+// SMM IPL are converted to free memory, so the SMM COre must guarantee that is\r
+// does not touch of the code/data associated with the SMM IPL if this flag is TRUE.\r
+//\r
+BOOLEAN  mInLegacyBoot = FALSE;\r
+\r
+//\r
+// Table of SMI Handlers that are registered by the SMM Core when it is initialized\r
+//\r
+SMM_CORE_SMI_HANDLERS  mSmmCoreSmiHandlers[] = {\r
+  { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid,          NULL, TRUE  },\r
+  { SmmReadyToLockHandler,    &gEfiDxeSmmReadyToLockProtocolGuid, NULL, FALSE }, \r
+  { SmmLegacyBootHandler,     &gEfiEventLegacyBootGuid,           NULL, FALSE },\r
+  { NULL,                     NULL,                               NULL, FALSE }\r
+};\r
+\r
+/**\r
+  Place holder function until all the SMM System Table Service are available.\r
+\r
+  Note: This function is only used by SMRAM invocation.  It is never used by DXE invocation.\r
+\r
+  @param  Arg1                   Undefined\r
+  @param  Arg2                   Undefined\r
+  @param  Arg3                   Undefined\r
+  @param  Arg4                   Undefined\r
+  @param  Arg5                   Undefined\r
+\r
+  @return EFI_NOT_AVAILABLE_YET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEfiNotAvailableYetArg5 (\r
+  UINTN Arg1,\r
+  UINTN Arg2,\r
+  UINTN Arg3,\r
+  UINTN Arg4,\r
+  UINTN Arg5\r
+  )\r
+{\r
+  //\r
+  // This function should never be executed.  If it does, then the architectural protocols\r
+  // have not been designed correctly.\r
+  //\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Software SMI handler that is called when a Legacy Boot event is signalled.  The SMM\r
+  Core uses this signal to know that a Legacy Boot has been performed and that \r
+  gSmmCorePrivate that is shared between the UEFI and SMM execution environments can\r
+  not be accessed from SMM anymore since that structure is considered free memory by\r
+  a legacy OS.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-SMM environment into an SMM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLegacyBootHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  mInLegacyBoot = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Software SMI handler that is called when the DxeSmmReadyToLock protocol is added\r
+  or if gEfiEventReadyToBootGuid is signalled.  This function unregisters the \r
+  Software SMIs that are nor required after SMRAM is locked and installs the \r
+  SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about \r
+  to be locked.  It also verifies the the SMM CPU I/O 2 Protocol has been installed\r
+  and NULLs gBS and gST because they can not longer be used after SMRAM is locked.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-SMM environment into an SMM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmReadyToLockHandler (\r
+  IN     EFI_HANDLE  DispatchHandle,\r
+  IN     CONST VOID  *Context,        OPTIONAL\r
+  IN OUT VOID        *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN       *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  EFI_HANDLE  SmmHandle;\r
+  VOID        *Interface;\r
+\r
+  //\r
+  // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped\r
+  //\r
+  for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {\r
+    if (mSmmCoreSmiHandlers[Index].UnRegister) {\r
+      SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Install SMM Ready to lock protocol\r
+  //\r
+  SmmHandle = NULL;\r
+  Status = SmmInstallProtocolInterface (\r
+             &SmmHandle,\r
+             &gEfiSmmReadyToLockProtocolGuid,\r
+             EFI_NATIVE_INTERFACE,\r
+             NULL\r
+             );\r
+\r
+  //\r
+  // Make sure SMM CPU I/O 2 Procol has been installed into the handle database\r
+  //\r
+  Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface);\r
+\r
+  //\r
+  // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed\r
+  //\r
+  DEBUG_CODE_BEGIN ();\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));\r
+    }\r
+  DEBUG_CODE_END ();\r
+\r
+  //\r
+  // Assert if the CPU I/O 2 Protocol is not installed\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Display any drivers that were not dispatched because dependency expression\r
+  // evaluated to false if this is a debug build\r
+  //\r
+  DEBUG_CODE_BEGIN ();\r
+    SmmDisplayDiscoveredNotDispatched ();\r
+  DEBUG_CODE_END ();\r
+\r
+  //\r
+  // Not allowed to use gST or gBS after lock\r
+  //\r
+  gST = NULL;\r
+  gBS = NULL;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The main entry point to SMM Foundation.\r
+\r
+  Note: This function is only used by SMRAM invocation.  It is never used by DXE invocation.\r
+\r
+  @param  SmmEntryContext           Processor information and functionality\r
+                                    needed by SMM Foundation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmEntryPoint (\r
+  IN CONST EFI_SMM_ENTRY_CONTEXT  *SmmEntryContext\r
+)\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SMM_COMMUNICATE_HEADER  *CommunicateHeader;\r
+  BOOLEAN                     OldInSmm;\r
+\r
+  //\r
+  // Update SMST using the context\r
+  //\r
+  CopyMem (&gSmmCoreSmst.SmmStartupThisAp, SmmEntryContext, sizeof (EFI_SMM_ENTRY_CONTEXT));\r
+\r
+  //\r
+  // If a legacy boot has occured, then make sure gSmmCorePrivate is not accessed\r
+  //\r
+  if (mInLegacyBoot) {\r
+    //\r
+    // Asynchronous SMI\r
+    //\r
+    SmiManage (NULL, NULL, NULL, NULL);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Save current InSmm state and set InSmm state to TRUE, it will be used by SmmBase2 protocol\r
+  //\r
+  OldInSmm = gSmmCorePrivate->InSmm;\r
+  gSmmCorePrivate->InSmm = TRUE;\r
+\r
+  //\r
+  // Check to see if this is a Synchronous SMI sent through the SMM Communication \r
+  // Protocol or an Asynchronous SMI\r
+  //\r
+  if (gSmmCorePrivate->CommunicationBuffer != NULL) {\r
+    //\r
+    // Synchronous SMI for SMM Core or request from Communicate protocol\r
+    //\r
+    CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)gSmmCorePrivate->CommunicationBuffer;\r
+    *gSmmCorePrivate->BufferSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+    Status = SmiManage (\r
+               &CommunicateHeader->HeaderGuid, \r
+               NULL, \r
+               CommunicateHeader->Data, \r
+               gSmmCorePrivate->BufferSize\r
+               );\r
+\r
+    //\r
+    // Update CommunicationBuffer, BufferSize and ReturnStatus\r
+    // Communicate service finished, reset the pointer to CommBuffer to NULL\r
+    //\r
+    *gSmmCorePrivate->BufferSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+    gSmmCorePrivate->CommunicationBuffer = NULL;\r
+    gSmmCorePrivate->ReturnStatus = (Status == EFI_WARN_INTERRUPT_SOURCE_QUIESCED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // Asynchronous SMI\r
+    //\r
+    SmiManage (NULL, NULL, NULL, NULL);\r
+  }\r
+\r
+  //\r
+  // Restore original InSmm state as we are going to leave SMM\r
+  //\r
+  gSmmCorePrivate->InSmm = OldInSmm;\r
+}\r
+\r
+/**\r
+  The Entry Point for SMM Core\r
+\r
+  Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core \r
+  EntryPoint on the SMI vector.\r
+\r
+  Note: This function is called for both DXE invocation and SMRAM invocation.\r
+\r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param  SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS    The entry point is executed successfully.\r
+  @retval Other          Some error occurred when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMain (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+\r
+  //\r
+  // Get SMM Core Private context passed in from SMM IPL in ImageHandle.\r
+  //\r
+  gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;\r
+\r
+  //\r
+  // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point.\r
+  //\r
+  gSmmCorePrivate->Smst          = &gSmmCoreSmst;\r
+  gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint;\r
+  \r
+  //\r
+  // Initialize memory service using free SMRAM\r
+  //\r
+  SmmInitializeMemoryServices (gSmmCorePrivate->SmramRangeCount, gSmmCorePrivate->SmramRanges);\r
+\r
+  //\r
+  // Register all SMI Handlers required by the SMM Core\r
+  //\r
+  for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {\r
+    Status = SmiHandlerRegister (\r
+               mSmmCoreSmiHandlers[Index].Handler,\r
+               mSmmCoreSmiHandlers[Index].HandlerType,\r
+               &mSmmCoreSmiHandlers[Index].DispatchHandle\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
new file mode 100644 (file)
index 0000000..2926f90
--- /dev/null
@@ -0,0 +1,718 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by SmmCore module.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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
+#ifndef _SMM_CORE_H_\r
+#define _SMM_CORE_H_\r
+\r
+#include <PiSmm.h>\r
+\r
+#include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/SmmReadyToLock.h>\r
+#include <Protocol/CpuIo2.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmAccess2.h>\r
+#include <Protocol/FirmwareVolume2.h>   \r
+#include <Protocol/LoadedImage.h>       \r
+#include <Protocol/DevicePath.h>        \r
+#include <Protocol/Security.h>          \r
+\r
+#include <Guid/Apriori.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/EventLegacyBios.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DevicePathLib.h>             \r
+#include <Library/UefiLib.h>                   \r
+#include <Library/UefiBootServicesTableLib.h>  \r
+\r
+#include "PiSmmCorePrivateData.h"\r
+\r
+//\r
+// Used to build a table of SMI Handlers that the SMM Core registers\r
+//\r
+typedef struct {\r
+  EFI_SMM_HANDLER_ENTRY_POINT2  Handler;\r
+  EFI_GUID                      *HandlerType;\r
+  EFI_HANDLE                    DispatchHandle;\r
+  BOOLEAN                       UnRegister;\r
+} SMM_CORE_SMI_HANDLERS;\r
+\r
+//\r
+// Structure for recording the state of an SMM Driver\r
+//\r
+#define EFI_SMM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v')\r
+\r
+typedef struct {\r
+  UINTN                           Signature;\r
+  LIST_ENTRY                      Link;             // mDriverList\r
+\r
+  LIST_ENTRY                      ScheduledLink;    // mScheduledQueue\r
+\r
+  EFI_HANDLE                      FvHandle;\r
+  EFI_GUID                        FileName;\r
+  EFI_DEVICE_PATH_PROTOCOL        *FvFileDevicePath;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv;\r
+\r
+  VOID                            *Depex;\r
+  UINTN                           DepexSize;\r
+\r
+  BOOLEAN                         Before;\r
+  BOOLEAN                         After;\r
+  EFI_GUID                        BeforeAfterGuid;\r
+\r
+  BOOLEAN                         Dependent;\r
+  BOOLEAN                         Unrequested;\r
+  BOOLEAN                         Scheduled;\r
+  BOOLEAN                         Untrusted;\r
+  BOOLEAN                         Initialized;\r
+  BOOLEAN                         DepexProtocolError;\r
+\r
+  EFI_HANDLE                      ImageHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL       *LoadedImage;\r
+  //\r
+  // Image EntryPoint in SMRAM\r
+  //\r
+  PHYSICAL_ADDRESS                ImageEntryPoint;\r
+  //\r
+  // Image Buffer in SMRAM  \r
+  //\r
+  PHYSICAL_ADDRESS                ImageBuffer;\r
+  //\r
+  // Image Page Number\r
+  //\r
+  UINTN                           NumberOfPage;\r
+} EFI_SMM_DRIVER_ENTRY;\r
+\r
+#define EFI_HANDLE_SIGNATURE            SIGNATURE_32('h','n','d','l')\r
+\r
+///\r
+/// IHANDLE - contains a list of protocol handles\r
+///\r
+typedef struct {\r
+  UINTN               Signature;\r
+  /// All handles list of IHANDLE\r
+  LIST_ENTRY          AllHandles;\r
+  /// List of PROTOCOL_INTERFACE's for this handle\r
+  LIST_ENTRY          Protocols;\r
+  UINTN               LocateRequest;\r
+} IHANDLE;\r
+\r
+#define ASSERT_IS_HANDLE(a)  ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)\r
+\r
+#define PROTOCOL_ENTRY_SIGNATURE        SIGNATURE_32('p','r','t','e')\r
+\r
+///\r
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol\r
+/// database.  Each handler that supports this protocol is listed, along\r
+/// with a list of registered notifies.\r
+///\r
+typedef struct {\r
+  UINTN               Signature;\r
+  /// Link Entry inserted to mProtocolDatabase\r
+  LIST_ENTRY          AllEntries;\r
+  /// ID of the protocol\r
+  EFI_GUID            ProtocolID;\r
+  /// All protocol interfaces\r
+  LIST_ENTRY          Protocols;\r
+  /// Registerd notification handlers\r
+  LIST_ENTRY          Notify;\r
+} PROTOCOL_ENTRY;\r
+\r
+#define PROTOCOL_INTERFACE_SIGNATURE  SIGNATURE_32('p','i','f','c')\r
+\r
+///\r
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked\r
+/// with a protocol interface structure\r
+///\r
+typedef struct {\r
+  UINTN                       Signature;\r
+  /// Link on IHANDLE.Protocols\r
+  LIST_ENTRY                  Link;\r
+  /// Back pointer\r
+  IHANDLE                     *Handle;\r
+  /// Link on PROTOCOL_ENTRY.Protocols\r
+  LIST_ENTRY                  ByProtocol;\r
+  /// The protocol ID\r
+  PROTOCOL_ENTRY              *Protocol;\r
+  /// The interface value\r
+  VOID                        *Interface;\r
+} PROTOCOL_INTERFACE;\r
+\r
+#define PROTOCOL_NOTIFY_SIGNATURE       SIGNATURE_32('p','r','t','n')\r
+\r
+///\r
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol\r
+///\r
+typedef struct {\r
+  UINTN               Signature;\r
+  PROTOCOL_ENTRY      *Protocol;\r
+  /// All notifications for this protocol\r
+  LIST_ENTRY          Link;\r
+  /// Notification function\r
+  EFI_SMM_NOTIFY_FN   Function;\r
+  /// Last position notified\r
+  LIST_ENTRY          *Position;\r
+} PROTOCOL_NOTIFY;\r
+\r
+//\r
+// SMM Core Global Variables\r
+//\r
+extern SMM_CORE_PRIVATE_DATA  *gSmmCorePrivate;\r
+extern EFI_SMM_SYSTEM_TABLE2  gSmmCoreSmst;\r
+extern LIST_ENTRY             gHandleList;\r
+\r
+/**\r
+  Called to initialize the memory service.\r
+\r
+  @param   SmramRangeCount       Number of SMRAM Regions\r
+  @param   SmramRanges           Pointer to SMRAM Descriptors\r
+\r
+**/\r
+VOID\r
+SmmInitializeMemoryServices (\r
+  IN UINTN                 SmramRangeCount,\r
+  IN EFI_SMRAM_DESCRIPTOR  *SmramRanges\r
+  );\r
+\r
+/**\r
+  The SmmInstallConfigurationTable() function is used to maintain the list\r
+  of configuration tables that are stored in the System Management System\r
+  Table.  The list is stored as an array of (GUID, Pointer) pairs.  The list\r
+  must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.\r
+\r
+  @param  SystemTable      A pointer to the SMM System Table (SMST).\r
+  @param  Guid             A pointer to the GUID for the entry to add, update, or remove.\r
+  @param  Table            A pointer to the buffer of the table to add.\r
+  @param  TableSize        The size of the table to install.\r
+\r
+  @retval EFI_SUCCESS           The (Guid, Table) pair was added, updated, or removed.\r
+  @retval EFI_INVALID_PARAMETER Guid is not valid.\r
+  @retval EFI_NOT_FOUND         An attempt was made to delete a non-existent entry.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough memory available to complete the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallConfigurationTable (\r
+  IN  CONST EFI_SMM_SYSTEM_TABLE2  *SystemTable,\r
+  IN  CONST EFI_GUID              *Guid,\r
+  IN  VOID                        *Table,\r
+  IN  UINTN                       TableSize\r
+  );\r
+\r
+/**\r
+  Wrapper function to SmmInstallProtocolInterfaceNotify.  This is the public API which\r
+  Calls the private one which contains a BOOLEAN parameter for notifications\r
+\r
+  @param  UserHandle             The handle to install the protocol handler on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  Protocol               The protocol to add to the handle\r
+  @param  InterfaceType          Indicates whether Interface is supplied in\r
+                                 native form.\r
+  @param  Interface              The interface for the protocol being added\r
+\r
+  @return Status code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallProtocolInterface (\r
+  IN OUT EFI_HANDLE     *UserHandle,\r
+  IN EFI_GUID           *Protocol,\r
+  IN EFI_INTERFACE_TYPE InterfaceType,\r
+  IN VOID               *Interface\r
+  );\r
+\r
+/**\r
+  Allocates pages from the memory map.\r
+\r
+  @param  Type                   The type of allocation to perform\r
+  @param  MemoryType             The type of memory to turn the allocated pages\r
+                                 into\r
+  @param  NumberOfPages          The number of pages to allocate\r
+  @param  Memory                 A pointer to receive the base allocated memory\r
+                                 address\r
+\r
+  @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in spec.\r
+  @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.\r
+  @retval EFI_SUCCESS            Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePages (\r
+  IN      EFI_ALLOCATE_TYPE         Type,\r
+  IN      EFI_MEMORY_TYPE           MemoryType,\r
+  IN      UINTN                     NumberOfPages,\r
+  OUT     EFI_PHYSICAL_ADDRESS      *Memory\r
+  );\r
+\r
+/**\r
+  Frees previous allocated pages.\r
+\r
+  @param  Memory                 Base address of memory being freed\r
+  @param  NumberOfPages          The number of pages to free\r
+\r
+  @retval EFI_NOT_FOUND          Could not find the entry that covers the range\r
+  @retval EFI_INVALID_PARAMETER  Address not aligned\r
+  @return EFI_SUCCESS            Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePages (\r
+  IN      EFI_PHYSICAL_ADDRESS      Memory,\r
+  IN      UINTN                     NumberOfPages\r
+  );\r
+\r
+/**\r
+  Allocate pool of a particular type.\r
+\r
+  @param  PoolType               Type of pool to allocate\r
+  @param  Size                   The amount of pool to allocate\r
+  @param  Buffer                 The address to return a pointer to the allocated\r
+                                 pool\r
+\r
+  @retval EFI_INVALID_PARAMETER  PoolType not valid\r
+  @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.\r
+  @retval EFI_SUCCESS            Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePool (\r
+  IN      EFI_MEMORY_TYPE           PoolType,\r
+  IN      UINTN                     Size,\r
+  OUT     VOID                      **Buffer\r
+  );\r
+\r
+/**\r
+  Frees pool.\r
+\r
+  @param  Buffer                 The allocated pool entry to free\r
+\r
+  @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.\r
+  @retval EFI_SUCCESS            Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePool (\r
+  IN      VOID                      *Buffer\r
+  );\r
+\r
+/**\r
+  Installs a protocol interface into the boot services environment.\r
+\r
+  @param  UserHandle             The handle to install the protocol handler on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  Protocol               The protocol to add to the handle\r
+  @param  InterfaceType          Indicates whether Interface is supplied in\r
+                                 native form.\r
+  @param  Interface              The interface for the protocol being added\r
+  @param  Notify                 indicates whether notify the notification list\r
+                                 for this protocol\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate\r
+  @retval EFI_SUCCESS            Protocol interface successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+SmmInstallProtocolInterfaceNotify (\r
+  IN OUT EFI_HANDLE     *UserHandle,\r
+  IN EFI_GUID           *Protocol,\r
+  IN EFI_INTERFACE_TYPE InterfaceType,\r
+  IN VOID               *Interface,\r
+  IN BOOLEAN            Notify\r
+  );\r
+\r
+/**\r
+  Uninstalls all instances of a protocol:interfacer from a handle.\r
+  If the last protocol interface is remove from the handle, the\r
+  handle is freed.\r
+\r
+  @param  UserHandle             The handle to remove the protocol handler from\r
+  @param  Protocol               The protocol, of protocol:interface, to remove\r
+  @param  Interface              The interface, of protocol:interface, to remove\r
+\r
+  @retval EFI_INVALID_PARAMETER  Protocol is NULL.\r
+  @retval EFI_SUCCESS            Protocol interface successfully uninstalled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmUninstallProtocolInterface (\r
+  IN EFI_HANDLE       UserHandle,\r
+  IN EFI_GUID         *Protocol,\r
+  IN VOID             *Interface\r
+  );\r
+\r
+/**\r
+  Queries a handle to determine if it supports a specified protocol.\r
+\r
+  @param  UserHandle             The handle being queried.\r
+  @param  Protocol               The published unique identifier of the protocol.\r
+  @param  Interface              Supplies the address where a pointer to the\r
+                                 corresponding Protocol Interface is returned.\r
+\r
+  @return The requested protocol interface for the handle\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmHandleProtocol (\r
+  IN EFI_HANDLE       UserHandle,\r
+  IN EFI_GUID         *Protocol,\r
+  OUT VOID            **Interface\r
+  );\r
+\r
+/**\r
+  Add a new protocol notification record for the request protocol.\r
+\r
+  @param  Protocol               The requested protocol to add the notify\r
+                                 registration\r
+  @param  Function               Points to the notification function\r
+  @param  Registration           Returns the registration record\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_SUCCESS            Successfully returned the registration record\r
+                                 that has been added\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmRegisterProtocolNotify (\r
+  IN  CONST EFI_GUID              *Protocol,\r
+  IN  EFI_SMM_NOTIFY_FN           Function,\r
+  OUT VOID                        **Registration\r
+  );\r
+\r
+/**\r
+  Locates the requested handle(s) and returns them in Buffer.\r
+\r
+  @param  SearchType             The type of search to perform to locate the\r
+                                 handles\r
+  @param  Protocol               The protocol to search for\r
+  @param  SearchKey              Dependant on SearchType\r
+  @param  BufferSize             On input the size of Buffer.  On output the\r
+                                 size of data returned.\r
+  @param  Buffer                 The buffer to return the results in\r
+\r
+  @retval EFI_BUFFER_TOO_SMALL   Buffer too small, required buffer size is\r
+                                 returned in BufferSize.\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_SUCCESS            Successfully found the requested handle(s) and\r
+                                 returns them in Buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateHandle (\r
+  IN EFI_LOCATE_SEARCH_TYPE   SearchType,\r
+  IN EFI_GUID                 *Protocol   OPTIONAL,\r
+  IN VOID                     *SearchKey  OPTIONAL,\r
+  IN OUT UINTN                *BufferSize,\r
+  OUT EFI_HANDLE              *Buffer\r
+  );\r
+\r
+/**\r
+  Return the first Protocol Interface that matches the Protocol GUID. If\r
+  Registration is pasased in return a Protocol Instance that was just add\r
+  to the system. If Retistration is NULL return the first Protocol Interface\r
+  you find.\r
+\r
+  @param  Protocol               The protocol to search for\r
+  @param  Registration           Optional Registration Key returned from\r
+                                 RegisterProtocolNotify()\r
+  @param  Interface              Return the Protocol interface (instance).\r
+\r
+  @retval EFI_SUCCESS            If a valid Interface is returned\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_NOT_FOUND          Protocol interface not found\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateProtocol (\r
+  IN  EFI_GUID  *Protocol,\r
+  IN  VOID      *Registration OPTIONAL,\r
+  OUT VOID      **Interface\r
+  );\r
+\r
+/**\r
+  Manage SMI of a particular type.\r
+\r
+  @param  HandlerType    Points to the handler type or NULL for root SMI handlers.\r
+  @param  Context        Points to an optional context buffer.\r
+  @param  CommBuffer     Points to the optional communication buffer.\r
+  @param  CommBufferSize Points to the size of the optional communication buffer.\r
+\r
+  @retval EFI_SUCCESS                        Interrupt source was processed successfully but not quiesced.\r
+  @retval EFI_INTERRUPT_PENDING              One or more SMI sources could not be quiesced.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING  Interrupt source was not handled or quiesced.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiManage (\r
+  IN     CONST EFI_GUID           *HandlerType,\r
+  IN     CONST VOID               *Context         OPTIONAL,\r
+  IN OUT VOID                     *CommBuffer      OPTIONAL,\r
+  IN OUT UINTN                    *CommBufferSize  OPTIONAL\r
+  );\r
+\r
+/**\r
+  Registers a handler to execute within SMM.\r
+\r
+  @param  Handler        Handler service funtion pointer.\r
+  @param  HandlerType    Points to the handler type or NULL for root SMI handlers.\r
+  @param  DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.\r
+\r
+  @retval EFI_SUCCESS           Handler register success.\r
+  @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerRegister (\r
+  IN   EFI_SMM_HANDLER_ENTRY_POINT2   Handler,\r
+  IN   CONST EFI_GUID                 *HandlerType  OPTIONAL,\r
+  OUT  EFI_HANDLE                     *DispatchHandle\r
+  );\r
+\r
+/**\r
+  Unregister a handler in SMM.\r
+\r
+  @param  DispatchHandle  The handle that was specified when the handler was registered.\r
+\r
+  @retval EFI_SUCCESS           Handler function was successfully unregistered.\r
+  @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerUnRegister (\r
+  IN  EFI_HANDLE                      DispatchHandle\r
+  );\r
+\r
+/**\r
+  This function is the main entry point for an SMM handler dispatch\r
+  or communicate-based callback.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-SMM environment into an SMM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmDriverDispatchHandler (\r
+  IN     EFI_HANDLE               DispatchHandle,\r
+  IN     CONST VOID               *Context,        OPTIONAL\r
+  IN OUT VOID                     *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN                    *CommBufferSize  OPTIONAL\r
+  );\r
+\r
+/**\r
+  This function is the main entry point for an SMM handler dispatch\r
+  or communicate-based callback.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-SMM environment into an SMM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLegacyBootHandler (\r
+  IN     EFI_HANDLE               DispatchHandle,\r
+  IN     CONST VOID               *Context,        OPTIONAL\r
+  IN OUT VOID                     *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN                    *CommBufferSize  OPTIONAL\r
+  );\r
+\r
+/**\r
+  This function is the main entry point for an SMM handler dispatch\r
+  or communicate-based callback.\r
+\r
+  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
+  @param  CommBuffer      A pointer to a collection of data in memory that will\r
+                          be conveyed from a non-SMM environment into an SMM environment.\r
+  @param  CommBufferSize  The size of the CommBuffer.\r
+\r
+  @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmReadyToLockHandler (\r
+  IN     EFI_HANDLE               DispatchHandle,\r
+  IN     CONST VOID               *Context,        OPTIONAL\r
+  IN OUT VOID                     *CommBuffer,     OPTIONAL\r
+  IN OUT UINTN                    *CommBufferSize  OPTIONAL\r
+  );\r
+\r
+/**\r
+  Place holder function until all the SMM System Table Service are available.\r
+\r
+  @param  Arg1                   Undefined\r
+  @param  Arg2                   Undefined\r
+  @param  Arg3                   Undefined\r
+  @param  Arg4                   Undefined\r
+  @param  Arg5                   Undefined\r
+\r
+  @return EFI_NOT_AVAILABLE_YET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEfiNotAvailableYetArg5 (\r
+  UINTN Arg1,\r
+  UINTN Arg2,\r
+  UINTN Arg3,\r
+  UINTN Arg4,\r
+  UINTN Arg5\r
+  );\r
+\r
+//\r
+//Functions used during debug buils\r
+//\r
+\r
+/**\r
+  Traverse the discovered list for any drivers that were discovered but not loaded\r
+  because the dependency experessions evaluated to false.\r
+\r
+**/\r
+VOID\r
+SmmDisplayDiscoveredNotDispatched (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Add free SMRAM region for use by memory service.\r
+\r
+  @param  MemBase                Base address of memory region.\r
+  @param  MemLength              Length of the memory region.\r
+  @param  Type                   Memory type.\r
+  @param  Attributes             Memory region state.\r
+\r
+**/\r
+VOID\r
+SmmAddMemoryRegion (\r
+  IN      EFI_PHYSICAL_ADDRESS      MemBase,\r
+  IN      UINT64                    MemLength,\r
+  IN      EFI_MEMORY_TYPE           Type,\r
+  IN      UINT64                    Attributes\r
+  );\r
+\r
+/**\r
+  Finds the protocol entry for the requested protocol.\r
+\r
+  @param  Protocol               The ID of the protocol\r
+  @param  Create                 Create a new entry if not found\r
+\r
+  @return Protocol entry\r
+\r
+**/\r
+PROTOCOL_ENTRY  *\r
+SmmFindProtocolEntry (\r
+  IN EFI_GUID   *Protocol,\r
+  IN BOOLEAN    Create\r
+  );\r
+\r
+/**\r
+  Signal event for every protocol in protocol entry.\r
+\r
+  @param  Prot                   Protocol interface\r
+\r
+**/\r
+VOID\r
+SmmNotifyProtocol (\r
+  IN PROTOCOL_INTERFACE   *Prot\r
+  );\r
+\r
+/**\r
+  Finds the protocol instance for the requested handle and protocol.\r
+  Note: This function doesn't do parameters checking, it's caller's responsibility\r
+  to pass in valid parameters.\r
+\r
+  @param  Handle                 The handle to search the protocol on\r
+  @param  Protocol               GUID of the protocol\r
+  @param  Interface              The interface for the protocol being searched\r
+\r
+  @return Protocol instance (NULL: Not found)\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmFindProtocolInterface (\r
+  IN IHANDLE        *Handle,\r
+  IN EFI_GUID       *Protocol,\r
+  IN VOID           *Interface\r
+  );\r
+\r
+/**\r
+  Removes Protocol from the protocol list (but not the handle list).\r
+\r
+  @param  Handle                 The handle to remove protocol on.\r
+  @param  Protocol               GUID of the protocol to be moved\r
+  @param  Interface              The interface of the protocol\r
+\r
+  @return Protocol Entry\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmRemoveInterfaceFromProtocol (\r
+  IN IHANDLE        *Handle,\r
+  IN EFI_GUID       *Protocol,\r
+  IN VOID           *Interface\r
+  );\r
+\r
+/**\r
+  This is the POSTFIX version of the dependency evaluator.  This code does\r
+  not need to handle Before or After, as it is not valid to call this\r
+  routine in this case. The SOR is just ignored and is a nop in the grammer.\r
+  POSTFIX means all the math is done on top of the stack.\r
+\r
+  @param  DriverEntry           DriverEntry element to update.\r
+\r
+  @retval TRUE                  If driver is ready to run.\r
+  @retval FALSE                 If driver is not ready to run or some fatal error\r
+                                was found.\r
+\r
+**/\r
+BOOLEAN\r
+SmmIsSchedulable (\r
+  IN  EFI_SMM_DRIVER_ENTRY   *DriverEntry\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
new file mode 100644 (file)
index 0000000..5f38065
--- /dev/null
@@ -0,0 +1,68 @@
+## @file\r
+# This module provide an SMM CIS compliant implementation of SMM Core.\r
+#\r
+# Copyright (c) 2009 - 2010, Intel Corporation\r
+#\r
+# All rights reserved. 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
+# 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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PiSmmCore\r
+  FILE_GUID                      = E94F54CD-81EB-47ed-AEC3-856F5DC157A9\r
+  MODULE_TYPE                    = SMM_CORE\r
+  VERSION_STRING                 = 1.0\r
+  PI_SPECIFICATION_VERSION       = 0x0001000A\r
+  ENTRY_POINT                    = SmmMain\r
+\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+\r
+[Sources]\r
+  PiSmmCore.c\r
+  PiSmmCore.h\r
+  PiSmmCorePrivateData.h\r
+  Page.c\r
+  Pool.c\r
+  Handle.c\r
+  Locate.c\r
+  Notify.c\r
+  Dependency.c\r
+  Dispatcher.c\r
+  Smi.c\r
+  InstallConfigurationTable.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  \r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  BaseLib\r
+  BaseMemoryLib\r
+  PeCoffLib\r
+  CacheMaintenanceLib  \r
+  DebugLib\r
+  ReportStatusCodeLib\r
+  DevicePathLib               \r
+  UefiLib                     \r
+  UefiBootServicesTableLib    \r
+  MemoryAllocationLib\r
+  \r
+[Protocols]\r
+  gEfiDxeSmmReadyToLockProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSmmReadyToLockProtocolGuid                # PROTOCOL ALWAYS_PRODUCED\r
+  gEfiSmmCpuIo2ProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiFirmwareVolume2ProtocolGuid               # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSecurityArchProtocolGuid                  # PROTOCOL SIMETIMES_CONSUMED\r
+  gEfiLoadedImageProtocolGuid                   # PROTOCOL SOMETIMES_PRODUCED\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL SOMETIMES_CONSUMED\r
+\r
+[Guids]\r
+  gAprioriGuid                                  # ALWAYS_CONSUMED\r
+  gEfiEventDxeDispatchGuid                      # ALWAYS_CONSUMED\r
+  gEfiEventLegacyBootGuid                       # ALWAYS_CONSUMED\r
diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h
new file mode 100644 (file)
index 0000000..ce00701
--- /dev/null
@@ -0,0 +1,105 @@
+/** @file\r
+  The internal header file that declared a data structure that is shared\r
+  between the SMM IPL and the SMM Core.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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
+#ifndef _PI_SMM_CORE_PRIVATE_DATA_H_\r
+#define _PI_SMM_CORE_PRIVATE_DATA_H_\r
+\r
+///\r
+/// Signature for the private structure shared between the SMM IPL and the SMM Core\r
+///\r
+#define SMM_CORE_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('s', 'm', 'm', 'c')\r
+\r
+///\r
+/// Private structure that is used to share information between the SMM IPL and \r
+/// the SMM Core.  This structure is allocated from memory of type EfiRuntimeServicesData.\r
+/// Since runtime memory types are converted to available memory when a legacy boot \r
+/// is performed, the SMM Core must access any fields of this structure if a legacy \r
+/// boot is performed.  As a result, the SMM IPL must create an event notification \r
+/// for the Legacy Boot event and notify the SMM Core that a legacy boot is being \r
+/// performed.  The SMM Core can then use this information to filter accesses to \r
+/// thos structure.\r
+///\r
+typedef struct {\r
+  UINTN                           Signature;\r
+\r
+  ///\r
+  /// The ImageHandle passed into the entry point of the SMM IPL.  This ImageHandle\r
+  /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded\r
+  /// Image Protocol for each SMM Driver that is dispatched by the SMM Core.\r
+  ///\r
+  EFI_HANDLE                      SmmIplImageHandle;\r
+\r
+  ///\r
+  /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core.  The SMM\r
+  /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.\r
+  ///\r
+  UINTN                           SmramRangeCount;\r
+\r
+  ///\r
+  /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core.  The SMM\r
+  /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.\r
+  ///\r
+  EFI_SMRAM_DESCRIPTOR            *SmramRanges;\r
+\r
+  ///\r
+  /// The SMM Foundation Entry Point.  The SMM Core fills in this field when the \r
+  /// SMM Core is initialized.  The SMM IPL is responsbile for registering this entry \r
+  /// point with the SMM Configuration Protocol.  The SMM Configuration Protocol may \r
+  /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL\r
+  /// sets up a protocol notification on the SMM Configuration Protocol and registers \r
+  /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is \r
+  /// available.\r
+  ///\r
+  EFI_SMM_ENTRY_POINT             SmmEntryPoint;\r
+  \r
+  ///\r
+  /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.\r
+  /// \r
+  BOOLEAN                         SmmEntryPointRegistered;\r
+\r
+  ///\r
+  /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.\r
+  /// \r
+  BOOLEAN                         InSmm;\r
+\r
+  ///\r
+  /// This field is set by the SMM Core then the SMM Core is initialized.  This field is\r
+  /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in\r
+  /// the SMM IPL.  \r
+  ///\r
+  EFI_SMM_SYSTEM_TABLE2           *Smst;\r
+\r
+  ///\r
+  /// This field is used by the SMM Communicatioon Protocol to pass a buffer into \r
+  /// a software SMI handler and for the software SMI handler to pass a buffer back to\r
+  /// the caller of the SMM Communication Protocol.  \r
+  ///\r
+  VOID                            *CommunicationBuffer;\r
+\r
+  ///\r
+  /// This field is used by the SMM Communicatioon Protocol to pass the size of a buffer,\r
+  /// in bytes, into a software SMI handler and for the software SMI handler to pass the \r
+  /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol.\r
+  ///\r
+  UINTN                           *BufferSize;\r
+\r
+  ///\r
+  /// This field is used by the SMM Communication Protocol to pass the return status from\r
+  /// a software SMI handler back to the caller of the SMM Communication Protocol.\r
+  ///\r
+  EFI_STATUS                      ReturnStatus;\r
+} SMM_CORE_PRIVATE_DATA;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
new file mode 100644 (file)
index 0000000..c3c2afa
--- /dev/null
@@ -0,0 +1,1041 @@
+/** @file\r
+  SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 <PiDxe.h>\r
+\r
+#include <Protocol/SmmBase2.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmAccess2.h>\r
+#include <Protocol/SmmConfiguration.h>\r
+#include <Protocol/SmmControl2.h>\r
+#include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/EventLegacyBios.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+\r
+#include "PiSmmCorePrivateData.h"\r
+\r
+//\r
+// Function prototypes from produced protocols\r
+//\r
+\r
+/**\r
+  Indicate whether the driver is currently executing in the SMM Initialization phase.\r
+\r
+  @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.\r
+  @param   InSmram                 Pointer to a Boolean which, on return, indicates that the driver is currently executing\r
+                                   inside of SMRAM (TRUE) or outside of SMRAM (FALSE).\r
+\r
+  @retval  EFI_INVALID_PARAMETER   InSmram was NULL.\r
+  @retval  EFI_SUCCESS             The call returned successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2InSmram (\r
+  IN CONST EFI_SMM_BASE2_PROTOCOL  *This,\r
+  OUT      BOOLEAN                 *InSmram\r
+  );\r
+\r
+/**\r
+  Retrieves the location of the System Management System Table (SMST).\r
+\r
+  @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.\r
+  @param   Smst                    On return, points to a pointer to the System Management Service Table (SMST).\r
+\r
+  @retval  EFI_INVALID_PARAMETER   Smst or This was invalid.\r
+  @retval  EFI_SUCCESS             The memory was returned to the system.\r
+  @retval  EFI_UNSUPPORTED         Not in SMM.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2GetSmstLocation (\r
+  IN CONST EFI_SMM_BASE2_PROTOCOL  *This,\r
+  OUT      EFI_SMM_SYSTEM_TABLE2   **Smst\r
+  );\r
+\r
+/**\r
+  Communicates with a registered handler.\r
+  \r
+  This function provides a service to send and receive messages from a registered \r
+  UEFI service.  This function is part of the SMM Communication Protocol that may \r
+  be called in physical mode prior to SetVirtualAddressMap() and in virtual mode \r
+  after SetVirtualAddressMap().\r
+\r
+  @param[in]     This                The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
+  @param[in out] CommBuffer          A pointer to the buffer to convey into SMRAM.\r
+  @param[in out] CommSize            The size of the data buffer being passed in.On exit, the size of data\r
+                                     being returned. Zero if the handler does not wish to reply with any data.\r
+\r
+  @retval EFI_SUCCESS                The message was successfully posted.\r
+  @retval EFI_INVALID_PARAMETER      The CommBuffer was NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCommunicationCommunicate (\r
+  IN CONST EFI_SMM_COMMUNICATION_PROTOCOL  *This,\r
+  IN OUT VOID                              *CommBuffer,\r
+  IN OUT UINTN                             *CommSize\r
+  );\r
+\r
+/**\r
+  Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSmmConfigurationEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+/**\r
+  Event notification that is fired every time a DxeSmmReadyToLock protocol is added\r
+  or if gEfiEventReadyToBootGuid is signalled.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplReadyToLockEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+/**\r
+  Event notification that is fired when DxeDispatch Event Group is signaled.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplGuidedEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSetVirtualAddressNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+//\r
+// Data structure used to declare a table of protocol notifications and event \r
+// notifications required by the SMM IPL\r
+//\r
+typedef struct {\r
+  BOOLEAN           Protocol;\r
+  BOOLEAN           CloseOnLock;\r
+  EFI_GUID          *Guid;\r
+  EFI_EVENT_NOTIFY  NotifyFunction;\r
+  VOID              *NotifyContext;\r
+  EFI_EVENT         Event;\r
+} SMM_IPL_EVENT_NOTIFICATION;\r
+\r
+//\r
+// Handle to install the SMM Base2 Protocol and the SMM Communication Protocol\r
+//\r
+EFI_HANDLE  mSmmIplHandle = NULL;\r
+\r
+//\r
+// SMM Base 2 Protocol instance\r
+//\r
+EFI_SMM_BASE2_PROTOCOL  mSmmBase2 = {\r
+  SmmBase2InSmram,\r
+  SmmBase2GetSmstLocation\r
+};\r
+\r
+//\r
+// SMM Communication Protocol instance\r
+//\r
+EFI_SMM_COMMUNICATION_PROTOCOL  mSmmCommunication = {\r
+  SmmCommunicationCommunicate\r
+};\r
+\r
+//\r
+// SMM Core Private Data structure that contains the data shared between\r
+// the SMM IPL and the SMM Core.\r
+//\r
+SMM_CORE_PRIVATE_DATA  mSmmCorePrivateData = {\r
+  SMM_CORE_PRIVATE_DATA_SIGNATURE,    // Signature\r
+  NULL,                               // SmmIplImageHandle\r
+  0,                                  // SmramRangeCount\r
+  NULL,                               // SmramRanges\r
+  NULL,                               // SmmEntryPoint\r
+  FALSE,                              // SmmEntryPointRegistered\r
+  FALSE,                              // InSmm\r
+  NULL,                               // Smst\r
+  0,                                  // BufferSize\r
+  NULL,                               // CommunicationBuffer\r
+  EFI_SUCCESS                         // ReturnStatus\r
+};\r
+\r
+//\r
+// Global pointer used to access mSmmCorePrivateData from outside and inside SMM\r
+//\r
+SMM_CORE_PRIVATE_DATA  *gSmmCorePrivate = &mSmmCorePrivateData;\r
+\r
+//\r
+// SMM IPL global variables\r
+//\r
+EFI_SMM_CONTROL2_PROTOCOL  *mSmmControl2;\r
+EFI_SMM_ACCESS2_PROTOCOL   *mSmmAccess;\r
+EFI_SMRAM_DESCRIPTOR       *mCurrentSmramRange;\r
+BOOLEAN                    mSmmLocked = FALSE;\r
+\r
+//\r
+// Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires\r
+//\r
+SMM_IPL_EVENT_NOTIFICATION  mSmmIplEvents[] = {\r
+  //\r
+  // Declare protocol notification on the SMM Configuration protocol.  When this notification is etablished, \r
+  // the associated event is immediately signalled, so the notification function will be executed and the \r
+  // SMM Configuration Protocol will be found if it is already in the handle database.\r
+  //\r
+  { TRUE,  FALSE, &gEfiSmmConfigurationProtocolGuid,  SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid,  NULL },\r
+  //\r
+  // Declare protocl notification on DxeSmmReadyToLock protocols.  When this notification is etablished, \r
+  // the associated event is immediately signalled, so the notification function will be executed and the \r
+  // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.\r
+  //\r
+  { TRUE,  TRUE,  &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify,      &gEfiDxeSmmReadyToLockProtocolGuid, NULL },\r
+  //\r
+  // Declare event notification on the DXE Dispatch Event Group.  This event is signaled by the DXE Core\r
+  // each time the DXE Core dispatcher has completed its work.  When this event is signalled, the SMM Core\r
+  // if notified, so the SMM Core can dispatch SMM drivers.\r
+  //\r
+  { FALSE, TRUE,  &gEfiEventDxeDispatchGuid,          SmmIplGuidedEventNotify,           &gEfiEventDxeDispatchGuid,          NULL },\r
+  //\r
+  // Declare event notification on Ready To Boot Event Group.  This is an extra event notification that is\r
+  // used to make sure SMRAM is locked before any boot options are processed.\r
+  //\r
+  { FALSE, TRUE,  &gEfiEventReadyToBootGuid,          SmmIplReadyToLockEventNotify,      &gEfiEventReadyToBootGuid,          NULL },\r
+  //\r
+  // Declare event notification on Legacy Boot Event Group.  This is used to inform the SMM Core that the platform \r
+  // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core \r
+  // must guarantee that it does not access any UEFI related structures outside of SMRAM.\r
+  //\r
+  { FALSE, FALSE, &gEfiEventLegacyBootGuid,           SmmIplGuidedEventNotify,           &gEfiEventLegacyBootGuid,           NULL },\r
+  //\r
+  // Declare event notification on SetVirtualAddressMap() Event Group.  This is used to convert gSmmCorePrivate \r
+  // and mSmmControl2 from physical addresses to virtual addresses.\r
+  //\r
+  { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify,     NULL,                               NULL },\r
+  //\r
+  // Terminate the table of event notifications\r
+  //\r
+  { FALSE, FALSE, NULL,                               NULL,                              NULL,                               NULL }\r
+};\r
+\r
+/**\r
+  Indicate whether the driver is currently executing in the SMM Initialization phase.\r
+\r
+  @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.\r
+  @param   InSmram                 Pointer to a Boolean which, on return, indicates that the driver is currently executing\r
+                                   inside of SMRAM (TRUE) or outside of SMRAM (FALSE).\r
+\r
+  @retval  EFI_INVALID_PARAMETER   InSmram was NULL.\r
+  @retval  EFI_SUCCESS             The call returned successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2InSmram (\r
+  IN CONST EFI_SMM_BASE2_PROTOCOL  *This,\r
+  OUT      BOOLEAN                 *InSmram\r
+  )\r
+{\r
+  if (InSmram == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *InSmram = gSmmCorePrivate->InSmm;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Retrieves the location of the System Management System Table (SMST).\r
+\r
+  @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.\r
+  @param   Smst                    On return, points to a pointer to the System Management Service Table (SMST).\r
+\r
+  @retval  EFI_INVALID_PARAMETER   Smst or This was invalid.\r
+  @retval  EFI_SUCCESS             The memory was returned to the system.\r
+  @retval  EFI_UNSUPPORTED         Not in SMM.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2GetSmstLocation (\r
+  IN CONST EFI_SMM_BASE2_PROTOCOL  *This,\r
+  OUT      EFI_SMM_SYSTEM_TABLE2   **Smst\r
+  )\r
+{\r
+  if ((This == NULL) ||(Smst == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if (!gSmmCorePrivate->InSmm) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  *Smst = gSmmCorePrivate->Smst;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Communicates with a registered handler.\r
+  \r
+  This function provides a service to send and receive messages from a registered \r
+  UEFI service.  This function is part of the SMM Communication Protocol that may \r
+  be called in physical mode prior to SetVirtualAddressMap() and in virtual mode \r
+  after SetVirtualAddressMap().\r
+\r
+  @param[in] This                The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
+  @param[in out] CommBuffer          A pointer to the buffer to convey into SMRAM.\r
+  @param[in out] CommSize            The size of the data buffer being passed in.On exit, the size of data\r
+                                 being returned. Zero if the handler does not wish to reply with any data.\r
+\r
+  @retval EFI_SUCCESS            The message was successfully posted.\r
+  @retval EFI_INVALID_PARAMETER  The CommBuffer was NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCommunicationCommunicate (\r
+  IN CONST EFI_SMM_COMMUNICATION_PROTOCOL  *This,\r
+  IN OUT VOID                              *CommBuffer,\r
+  IN OUT UINTN                             *CommSize\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SMM_COMMUNICATE_HEADER  *CommunicateHeader;\r
+  BOOLEAN                     OldInSmm;\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if ((CommBuffer == NULL) || (CommSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If not already in SMM, then generate a Software SMI\r
+  //\r
+  if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {\r
+    //\r
+    // Put arguments for Software SMI in gSmmCorePrivate\r
+    //\r
+    gSmmCorePrivate->CommunicationBuffer = CommBuffer;\r
+    gSmmCorePrivate->BufferSize          = CommSize;\r
+\r
+    //\r
+    // Generate Software SMI\r
+    //\r
+    Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    //\r
+    // Return status from software SMI \r
+    //\r
+    return gSmmCorePrivate->ReturnStatus;\r
+  }\r
+\r
+  //\r
+  // If we are in SMM, then the execution mode must be physical, which means that\r
+  // OS established virtual addresses can not be used.  If SetVirtualAddressMap()\r
+  // has been called, then a direct invocation of the Software SMI is not \r
+  // not allowed so return EFI_INVALID_PARAMETER.\r
+  //\r
+  if (EfiGoneVirtual()) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Save current InSmm state and set InSmm state to TRUE\r
+  //\r
+  OldInSmm = gSmmCorePrivate->InSmm;\r
+  gSmmCorePrivate->InSmm = TRUE;\r
+\r
+  //\r
+  // Already in SMM and before SetVirtualAddressMap(), so call SmiManage() directly.\r
+  //\r
+  CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;\r
+  *CommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+  Status = gSmmCorePrivate->Smst->SmiManage (\r
+                                    &CommunicateHeader->HeaderGuid, \r
+                                    NULL, \r
+                                    CommunicateHeader->Data, \r
+                                    CommSize\r
+                                    );\r
+\r
+  //\r
+  // Update CommunicationBuffer, BufferSize and ReturnStatus\r
+  // Communicate service finished, reset the pointer to CommBuffer to NULL\r
+  //\r
+  *CommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+\r
+  //\r
+  // Restore original InSmm state\r
+  //\r
+  gSmmCorePrivate->InSmm = OldInSmm;\r
+\r
+  return (Status == EFI_WARN_INTERRUPT_SOURCE_QUIESCED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Event notification that is fired when DxeDispatch Event Group is signaled.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplGuidedEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_SMM_COMMUNICATE_HEADER  CommunicateHeader;\r
+  UINTN                       Size;\r
+\r
+  //\r
+  // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure \r
+  //\r
+  CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
+  CommunicateHeader.MessageLength = 1;\r
+  CommunicateHeader.Data[0] = 0;\r
+\r
+  //\r
+  // Generate the Software SMI and return the result\r
+  //\r
+  Size = sizeof (CommunicateHeader);\r
+  SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);\r
+}\r
+\r
+/**\r
+  Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSmmConfigurationEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_SMM_CONFIGURATION_PROTOCOL  *SmmConfiguration;\r
+\r
+  //\r
+  // Make sure this notification is for this handler\r
+  //\r
+  Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Register the SMM Entry Point provided by the SMM Core with the SMM COnfiguration protocol\r
+  //\r
+  Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Set flag to indicate that the SM< Entry Point has been registered which \r
+  // means that SMIs are now fully operational.\r
+  //\r
+  gSmmCorePrivate->SmmEntryPointRegistered = TRUE;\r
+\r
+  //\r
+  // Print debug message showing SMM Core entry point address.\r
+  //\r
+  DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));\r
+\r
+  //\r
+  // Attempt to reset SMRAM cacheability to UC\r
+  //\r
+  Status = gDS->SetMemorySpaceAttributes(\r
+                  mCurrentSmramRange->CpuStart, \r
+                  mCurrentSmramRange->PhysicalSize,\r
+                  EFI_MEMORY_UC\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+  }  \r
+\r
+  //\r
+  // Close all SMRAM ranges to protect SMRAM\r
+  //\r
+  Status = mSmmAccess->Close (mSmmAccess);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Print debug message that the SMRAM window is now closed.\r
+  //\r
+  DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
+}\r
+\r
+/**\r
+  Event notification that is fired every time a DxeSmmReadyToLock protocol is added\r
+  or if gEfiEventReadyToBootGuid is signalled.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplReadyToLockEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  VOID        *Interface;\r
+  UINTN       Index;\r
+\r
+  //\r
+  // See if we are already locked\r
+  //\r
+  if (mSmmLocked) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Make sure this notification is for this handler\r
+  //\r
+  if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) {\r
+    Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);\r
+    if (EFI_ERROR (Status)) {\r
+      return;\r
+    }\r
+  } else {\r
+    //\r
+    // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being \r
+    // signalled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.\r
+    // Print a warning on debug builds.\r
+    //\r
+    DEBUG ((DEBUG_WARN, "SMM IPL!  DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));\r
+  }\r
+\r
+  //\r
+  // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)\r
+  //\r
+  mSmmAccess->Lock (mSmmAccess);\r
+\r
+  //\r
+  // Close protocol and event notification events that do not apply after the \r
+  // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot \r
+  // event has been signalled.\r
+  //\r
+  for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {\r
+    if (mSmmIplEvents[Index].CloseOnLock) {\r
+      gBS->CloseEvent (mSmmIplEvents[Index].Event);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Inform SMM Core that the DxeSmmReadyToLock protocol was installed\r
+  //\r
+  SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid);\r
+\r
+  //\r
+  // Print debug message that the SMRAM window is now locked.\r
+  //\r
+  DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));\r
+  \r
+  //\r
+  // Set flag so this operation will not be performed again\r
+  //\r
+  mSmmLocked = TRUE;\r
+}\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSetVirtualAddressNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EfiConvertPointer (0x0, (VOID **)&mSmmControl2);\r
+}\r
+\r
+/**\r
+  Searches all Firmware Volumes for the first file matching FileType and SectionType and returns the section data.\r
+\r
+  @param   FileType                FileType to search for within any of the firmware volumes in the platform.\r
+  @param   SectionType             SectionType to search for within any of the matching FileTypes in the firmware volumes in the platform.\r
+  @param   SourceSize              Return the size of the returned section data..\r
+\r
+  @retval  != NULL                 Pointer to the allocated buffer containing the section data.\r
+  @retval  NULL                    Section data was not found.\r
+\r
+**/\r
+VOID *\r
+GetSectionInAnyFv (\r
+  IN  EFI_FV_FILETYPE   FileType,\r
+  IN  EFI_SECTION_TYPE  SectionType,\r
+  OUT UINTN             *SourceSize\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         HandleCount;\r
+  EFI_HANDLE                    *HandleBuffer;\r
+  UINTN                         Index;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+  UINTN                         Key;\r
+  EFI_GUID                      NameGuid;\r
+  EFI_FV_FILE_ATTRIBUTES        Attributes;\r
+  VOID                          *SourceBuffer;\r
+  UINT32                        AuthenticationStatus;\r
+\r
+  HandleBuffer = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolume2ProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareVolume2ProtocolGuid,\r
+                    (VOID **)&Fv\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Use Firmware Volume 2 Protocol to search for a file of type FileType\r
+    //\r
+    Key = 0;   \r
+    Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, SourceSize);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Use Firmware Volume 2 Protocol to read a section of type SectionType\r
+    //\r
+    SourceBuffer = NULL;\r
+    Status = Fv->ReadSection (Fv, &NameGuid, SectionType, 0, &SourceBuffer, SourceSize, &AuthenticationStatus);\r
+    if (!EFI_ERROR (Status)) {\r
+      FreePool (HandleBuffer);\r
+      return SourceBuffer;\r
+    }\r
+  }  \r
+\r
+  FreePool(HandleBuffer);\r
+  \r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.\r
+\r
+  @param[in] SmramRange  Descriptor for the range of SMRAM to reload the \r
+                         currently executing image.\r
+  @param[in] Context     Context to pass into SMM Core\r
+\r
+  @return  EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+ExecuteSmmCoreFromSmram (\r
+  IN EFI_SMRAM_DESCRIPTOR  *SmramRange,\r
+  IN VOID                  *Context\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  VOID                          *SourceBuffer;\r
+  UINTN                         SourceSize;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;\r
+  UINTN                         PageCount;\r
+  EFI_PHYSICAL_ADDRESS          DestinationBuffer;\r
+  EFI_IMAGE_ENTRY_POINT         EntryPoint;\r
+\r
+  //\r
+  // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE\r
+  //  \r
+  SourceBuffer = GetSectionInAnyFv (EFI_FV_FILETYPE_SMM_CORE, EFI_SECTION_PE32, &SourceSize);\r
+  if (SourceBuffer == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Initilize ImageContext\r
+  //\r
+  ImageContext.Handle    = SourceBuffer;\r
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+  //\r
+  // Get information about the image being loaded\r
+  //\r
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
+  // specified by SmramRange\r
+  //\r
+  PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+\r
+  ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
+  ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
+\r
+  SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
+  DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+\r
+  //\r
+  // Align buffer on section boundry\r
+  //\r
+  ImageContext.ImageAddress = DestinationBuffer;\r
+  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+  ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+  //\r
+  // Print debug message showing SMM Core load address.\r
+  //\r
+  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));\r
+\r
+  //\r
+  // Load the image to our new buffer\r
+  //\r
+  Status = PeCoffLoaderLoadImage (&ImageContext);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Relocate the image in our new buffer\r
+    //\r
+    Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Flush the instruction cache so the image data are written before we execute it\r
+      //\r
+      InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
+\r
+      //\r
+      // Print debug message showing SMM Core entry point address.\r
+      //\r
+      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));\r
+\r
+      //\r
+      // Execute image\r
+      //\r
+      EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;\r
+      Status = EntryPoint ((EFI_HANDLE)Context, gST);\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the load operation, relocate operation, or the image execution return an\r
+  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by \r
+  // SmramRange\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);\r
+  }\r
+\r
+  //\r
+  // Always free memory allocted by GetFileBufferByFilePath ()\r
+  //\r
+  FreePool (SourceBuffer);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The Entry Point for SMM IPL\r
+\r
+  Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install \r
+  SMM Base 2 Protocol and SMM Communication Protocol, and register for the \r
+  critical events required to coordinate between DXE and SMM environments.\r
+  \r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param  SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS    The entry point is executed successfully.\r
+  @retval Other          Some error occurred when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmIplEntry (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_SMM_CONFIGURATION_PROTOCOL  *SmmConfiguration;\r
+  UINTN                           Size;\r
+  UINTN                           Index;\r
+  EFI_SMM_RESERVED_SMRAM_REGION   *SmramResRegion;\r
+  UINT64                          MaxSize;\r
+  VOID                            *Registration;\r
+\r
+  //\r
+  // Fill in the image handle of the SMM IPL so the SMM Core can use this as the \r
+  // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded \r
+  // by the SMM Core\r
+  //\r
+  mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;\r
+\r
+  //\r
+  // Get SMM Access Protocol\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Get SMM Control2 Protocol\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Get SMM Configuration Protocol if it is present\r
+  //\r
+  SmmConfiguration = NULL;\r
+  Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);\r
+\r
+  //\r
+  // Get SMRAM information\r
+  //\r
+  Size = 0;\r
+  Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);\r
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  gSmmCorePrivate->SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);\r
+  ASSERT (gSmmCorePrivate->SmramRanges != NULL);\r
+\r
+  Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, gSmmCorePrivate->SmramRanges);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+  //\r
+  // Open all SMRAM ranges\r
+  //\r
+  Status = mSmmAccess->Open (mSmmAccess);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Print debug message that the SMRAM window is now open.\r
+  //\r
+  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));\r
+\r
+  //\r
+  // Subtract SMRAM any reserved SMRAM regions.\r
+  //\r
+  if (SmmConfiguration != NULL) {\r
+    SmramResRegion = SmmConfiguration->SmramReservedRegions;\r
+    while (SmramResRegion->SmramReservedSize != 0) {\r
+      for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index ++) {\r
+        if ((SmramResRegion->SmramReservedStart >= gSmmCorePrivate->SmramRanges[Index].CpuStart)  &&      \\r
+           ((SmramResRegion->SmramReservedStart + SmramResRegion->SmramReservedSize) <=   \\r
+           (gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize))) {\r
+          //\r
+          // This range has reserved area, calculate the left free size\r
+          //\r
+          gSmmCorePrivate->SmramRanges[Index].PhysicalSize = SmramResRegion->SmramReservedStart - gSmmCorePrivate->SmramRanges[Index].CpuStart;\r
+        }\r
+      }\r
+      SmramResRegion++;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Find the largest SMRAM range between 1MB and 4GB that is at least 1MB in size\r
+  //\r
+  mCurrentSmramRange = NULL;\r
+  for (Index = 0, MaxSize = SIZE_1MB; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+    if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {\r
+      if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
+        if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {\r
+          MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;\r
+          mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (mCurrentSmramRange != NULL) {\r
+    //\r
+    // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core\r
+    //\r
+    DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n", \r
+      (VOID *)(UINTN)mCurrentSmramRange->CpuStart, \r
+      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)\r
+      ));\r
+\r
+    //\r
+    // Attempt to set SMRAM cacheability to WB\r
+    //\r
+    Status = gDS->SetMemorySpaceAttributes(\r
+                    mCurrentSmramRange->CpuStart, \r
+                    mCurrentSmramRange->PhysicalSize,\r
+                    EFI_MEMORY_WB\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));\r
+    }  \r
+\r
+    //\r
+    // Load SMM Core into SMRAM and execute it from SMRAM\r
+    //\r
+    Status = ExecuteSmmCoreFromSmram (mCurrentSmramRange, gSmmCorePrivate);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Print error message that the SMM Core failed to be loaded and executed.\r
+      //\r
+      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));\r
+\r
+      //\r
+      // Attempt to reset SMRAM cacheability to UC\r
+      //\r
+      Status = gDS->SetMemorySpaceAttributes(\r
+                      mCurrentSmramRange->CpuStart, \r
+                      mCurrentSmramRange->PhysicalSize,\r
+                      EFI_MEMORY_UC\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+      }  \r
+    }\r
+  } else {\r
+    //\r
+    // Print error message that there are not enough SMRAM resources to load the SMM Core.\r
+    //\r
+    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));\r
+  }\r
+\r
+  //\r
+  // If the SMM Core could not be loaded then close SMRAM window, free allocated \r
+  // resources, and return an error so SMM IPL will be unloaded.\r
+  //\r
+  if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {\r
+    //\r
+    // Close all SMRAM ranges\r
+    //\r
+    Status = mSmmAccess->Close (mSmmAccess);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Print debug message that the SMRAM window is now closed.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
+\r
+    //\r
+    // Free all allocated resources\r
+    //\r
+    FreePool (gSmmCorePrivate->SmramRanges);\r
+    \r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  //\r
+  // Install SMM Base2 Protocol and SMM Communication Protocol\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &mSmmIplHandle,\r
+                  &gEfiSmmBase2ProtocolGuid,         &mSmmBase2,\r
+                  &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Create the set of protocol and event notififcations that the SMM IPL requires\r
+  //\r
+  for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {\r
+    if (mSmmIplEvents[Index].Protocol) {\r
+      mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (\r
+                                     mSmmIplEvents[Index].Guid,\r
+                                    TPL_CALLBACK,\r
+                                     mSmmIplEvents[Index].NotifyFunction,\r
+                                     mSmmIplEvents[Index].NotifyContext,\r
+                                    &Registration\r
+                                    );\r
+    } else {\r
+      Status = gBS->CreateEventEx (\r
+                      EVT_NOTIFY_SIGNAL,\r
+                      TPL_CALLBACK,\r
+                      mSmmIplEvents[Index].NotifyFunction,\r
+                      mSmmIplEvents[Index].NotifyContext,\r
+                      mSmmIplEvents[Index].Guid,\r
+                      &mSmmIplEvents[Index].Event\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
new file mode 100644 (file)
index 0000000..d724c49
--- /dev/null
@@ -0,0 +1,66 @@
+## @file\r
+#   This module provide an SMM CIS compliant implementation of SMM IPL.\r
+#\r
+# Copyright (c) 2009 - 2010, Intel Corporation\r
+#\r
+#  All rights reserved. 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
+#  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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PiSmmIpl\r
+  FILE_GUID                      = 2FA2A6DA-11D5-4dc3-999A-749648B03C56\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  PI_SPECIFICATION_VERSION       = 0x0001000A\r
+  ENTRY_POINT                    = SmmIplEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  PiSmmIpl.c\r
+  PiSmmCorePrivateData.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  \r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  BaseLib\r
+  BaseMemoryLib\r
+  PeCoffLib\r
+  CacheMaintenanceLib  \r
+  MemoryAllocationLib\r
+  DebugLib\r
+  UefiBootServicesTableLib\r
+  DxeServicesTableLib\r
+  UefiLib\r
+  UefiRuntimeLib\r
+  \r
+[Protocols]\r
+  gEfiSmmBase2ProtocolGuid                      # PROTOCOL ALWAYS_PRODUCED\r
+  gEfiSmmCommunicationProtocolGuid              # PROTOCOL ALWAYS_PRODUCED\r
+  gEfiSmmAccess2ProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSmmConfigurationProtocolGuid              # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSmmControl2ProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDxeSmmReadyToLockProtocolGuid             # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiFirmwareVolume2ProtocolGuid               # PROTOCOL ALWAYS_CONSUMED\r
+\r
+[Guids]\r
+  gEfiEventDxeDispatchGuid                      # ALWAYS_CONSUMED\r
+  gEfiEventReadyToBootGuid                      # ALWAYS_CONSUMED\r
+  gEfiEventLegacyBootGuid                       # ALWAYS_CONSUMED\r
+  gEfiEventVirtualAddressChangeGuid             # ALWAYS_CONSUMED\r
+  \r
+[Depex]\r
+  gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Pool.c b/MdeModulePkg/Core/PiSmmCore/Pool.c
new file mode 100644 (file)
index 0000000..9e86d93
--- /dev/null
@@ -0,0 +1,249 @@
+/** @file\r
+  SMM Memory pool management functions.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+//\r
+// MIN_POOL_SHIFT must not be less than 5\r
+//\r
+#define MIN_POOL_SHIFT  6\r
+#define MIN_POOL_SIZE   (1 << MIN_POOL_SHIFT)\r
+\r
+//\r
+// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1\r
+//\r
+#define MAX_POOL_SHIFT  (EFI_PAGE_SHIFT - 1)\r
+#define MAX_POOL_SIZE   (1 << MAX_POOL_SHIFT)\r
+\r
+//\r
+// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes\r
+//\r
+#define MAX_POOL_INDEX  (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)\r
+\r
+typedef struct {\r
+  UINTN        Size;\r
+  BOOLEAN      Available;\r
+} POOL_HEADER;\r
+\r
+typedef struct {\r
+  POOL_HEADER  Header;\r
+  LIST_ENTRY   Link;\r
+} FREE_POOL_HEADER;\r
+\r
+LIST_ENTRY  mSmmPoolLists[MAX_POOL_INDEX];\r
+\r
+/**\r
+  Called to initialize the memory service.\r
+\r
+  @param   SmramRangeCount       Number of SMRAM Regions\r
+  @param   SmramRanges           Pointer to SMRAM Descriptors\r
+\r
+**/\r
+VOID\r
+SmmInitializeMemoryServices (\r
+  IN UINTN                 SmramRangeCount,\r
+  IN EFI_SMRAM_DESCRIPTOR  *SmramRanges\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  //\r
+  // Initialize Pool list\r
+  //\r
+  for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
+    InitializeListHead (&mSmmPoolLists[--Index]);\r
+  }\r
+\r
+  //\r
+  // Initialize free SMRAM regions\r
+  //\r
+  for (Index = 0; Index < SmramRangeCount; Index++) {\r
+    SmmAddMemoryRegion (\r
+      SmramRanges[Index].CpuStart,\r
+      SmramRanges[Index].PhysicalSize,\r
+      EfiConventionalMemory,\r
+      SmramRanges[Index].RegionState\r
+      );\r
+  }\r
+}\r
+\r
+/**\r
+  Internal Function. Allocate a pool by specified PoolIndex.\r
+\r
+  @param  PoolIndex             Index which indicate the Pool size.\r
+  @param  FreePoolHdr           The returned Free pool.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Allocation failed.\r
+  @retval EFI_SUCCESS            Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalAllocPoolByIndex (\r
+  IN  UINTN             PoolIndex,\r
+  OUT FREE_POOL_HEADER  **FreePoolHdr\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  FREE_POOL_HEADER  *Hdr;\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (PoolIndex == MAX_POOL_INDEX) {\r
+    Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
+    if (Hdr == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
+    Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
+    RemoveEntryList (&Hdr->Link);\r
+  } else {\r
+    Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
+    if (!EFI_ERROR (Status)) {\r
+      Hdr->Header.Size >>= 1;\r
+      Hdr->Header.Available = TRUE;\r
+      InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
+      Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
+    Hdr->Header.Available = FALSE;\r
+  }\r
+\r
+  *FreePoolHdr = Hdr;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Internal Function. Free a pool by specified PoolIndex.\r
+\r
+  @param  FreePoolHdr           The pool to free.\r
+\r
+  @retval EFI_SUCCESS           Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalFreePoolByIndex (\r
+  IN FREE_POOL_HEADER  *FreePoolHdr\r
+  )\r
+{\r
+  UINTN  PoolIndex;\r
+\r
+  ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
+  ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
+  ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
+\r
+  PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;\r
+  FreePoolHdr->Header.Available = TRUE;\r
+  InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate pool of a particular type.\r
+\r
+  @param  PoolType               Type of pool to allocate.\r
+  @param  Size                   The amount of pool to allocate.\r
+  @param  Buffer                 The address to return a pointer to the allocated\r
+                                 pool.\r
+\r
+  @retval EFI_INVALID_PARAMETER  PoolType not valid.\r
+  @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.\r
+  @retval EFI_SUCCESS            Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePool (\r
+  IN   EFI_MEMORY_TYPE  PoolType,\r
+  IN   UINTN            Size,\r
+  OUT  VOID             **Buffer\r
+  )\r
+{\r
+  POOL_HEADER           *PoolHdr;\r
+  FREE_POOL_HEADER      *FreePoolHdr;\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  UINTN                 PoolIndex;\r
+\r
+  if (PoolType != EfiRuntimeServicesCode &&\r
+      PoolType != EfiRuntimeServicesData) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Size == 0) {\r
+    *Buffer = NULL;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Size += sizeof (*PoolHdr);\r
+  if (Size > MAX_POOL_SIZE) {\r
+    Size = EFI_SIZE_TO_PAGES (Size);\r
+    Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
+    PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
+    PoolHdr->Available = FALSE;\r
+    *Buffer = PoolHdr + 1;\r
+    return Status;\r
+  }\r
+\r
+  Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
+  PoolIndex = HighBitSet32 ((UINT32)Size);\r
+  if ((Size & (Size - 1)) != 0) {\r
+    PoolIndex++;\r
+  }\r
+\r
+  Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
+  *Buffer = &FreePoolHdr->Header + 1;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Frees pool.\r
+\r
+  @param  Buffer                 The allocated pool entry to free.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.\r
+  @retval EFI_SUCCESS            Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePool (\r
+  IN VOID  *Buffer\r
+  )\r
+{\r
+  FREE_POOL_HEADER  *FreePoolHdr;\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
+  ASSERT (!FreePoolHdr->Header.Available);\r
+\r
+  if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
+    ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
+    ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
+    return SmmFreePages (\r
+             (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
+             EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
+             );\r
+  }\r
+  return InternalFreePoolByIndex (FreePoolHdr);\r
+}\r
diff --git a/MdeModulePkg/Core/PiSmmCore/Smi.c b/MdeModulePkg/Core/PiSmmCore/Smi.c
new file mode 100644 (file)
index 0000000..ccf6c0d
--- /dev/null
@@ -0,0 +1,333 @@
+/** @file\r
+  SMI management.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  This program and the accompanying materials are licensed and made available \r
+  under the terms and conditions of the BSD License which accompanies this \r
+  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 "PiSmmCore.h"\r
+\r
+//\r
+// SMM_HANDLER - used for each SMM handler\r
+//\r
+\r
+#define SMI_ENTRY_SIGNATURE  SIGNATURE_32('s','m','i','e')\r
+\r
+ typedef struct {\r
+  UINTN       Signature;\r
+  LIST_ENTRY  AllEntries;  // All entries\r
+\r
+  EFI_GUID    HandlerType; // Type of interrupt\r
+  LIST_ENTRY  SmiHandlers; // All handlers\r
+} SMI_ENTRY;\r
+\r
+#define SMI_HANDLER_SIGNATURE  SIGNATURE_32('s','m','i','h')\r
+\r
+ typedef struct {\r
+  UINTN                         Signature;\r
+  LIST_ENTRY                    Link;        // Link on SMI_ENTRY.SmiHandlers\r
+  EFI_SMM_HANDLER_ENTRY_POINT2  Handler;     // The smm handler's entry point\r
+  SMI_ENTRY                     *SmiEntry;\r
+} SMI_HANDLER;\r
+\r
+LIST_ENTRY  mRootSmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiHandlerList);\r
+LIST_ENTRY  mSmiEntryList       = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);\r
+\r
+/**\r
+  Finds the SMI entry for the requested handler type.\r
+\r
+  @param  HandlerType            The type of the interrupt\r
+  @param  Create                 Create a new entry if not found\r
+\r
+  @return SMI entry\r
+\r
+**/\r
+SMI_ENTRY  *\r
+EFIAPI\r
+SmmCoreFindSmiEntry (\r
+  IN EFI_GUID  *HandlerType,\r
+  IN BOOLEAN   Create\r
+  )\r
+{\r
+  LIST_ENTRY  *Link;\r
+  SMI_ENTRY   *Item;\r
+  SMI_ENTRY   *SmiEntry;\r
+\r
+  //\r
+  // Search the SMI entry list for the matching GUID\r
+  //\r
+  SmiEntry = NULL;\r
+  for (Link = mSmiEntryList.ForwardLink;\r
+       Link != &mSmiEntryList;\r
+       Link = Link->ForwardLink) {\r
+\r
+    Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
+    if (CompareGuid (&Item->HandlerType, HandlerType)) {\r
+      //\r
+      // This is the SMI entry\r
+      //\r
+      SmiEntry = Item;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the protocol entry was not found and Create is TRUE, then\r
+  // allocate a new entry\r
+  //\r
+  if ((SmiEntry == NULL) && Create) {\r
+    SmiEntry = AllocatePool (sizeof(SMI_ENTRY));\r
+    if (SmiEntry != NULL) {\r
+      //\r
+      // Initialize new SMI entry structure\r
+      //\r
+      SmiEntry->Signature = SMI_ENTRY_SIGNATURE;\r
+      CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);\r
+      InitializeListHead (&SmiEntry->SmiHandlers);\r
+\r
+      //\r
+      // Add it to SMI entry list\r
+      //\r
+      InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries);\r
+    }\r
+  }\r
+  return SmiEntry;\r
+}\r
+\r
+/**\r
+  Manage SMI of a particular type.\r
+\r
+  @param  HandlerType    Points to the handler type or NULL for root SMI handlers.\r
+  @param  Context        Points to an optional context buffer.\r
+  @param  CommBuffer     Points to the optional communication buffer.\r
+  @param  CommBufferSize Points to the size of the optional communication buffer.\r
+\r
+  @retval EFI_SUCCESS                        Interrupt source was processed successfully but not quiesced.\r
+  @retval EFI_INTERRUPT_PENDING              One or more SMI sources could not be quiesced.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING  Interrupt source was not handled or quiesced.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiManage (\r
+  IN     CONST EFI_GUID  *HandlerType,\r
+  IN     CONST VOID      *Context         OPTIONAL,\r
+  IN OUT VOID            *CommBuffer      OPTIONAL,\r
+  IN OUT UINTN           *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  LIST_ENTRY   *Link;\r
+  LIST_ENTRY   *Head;\r
+  SMI_ENTRY    *SmiEntry;\r
+  SMI_HANDLER  *SmiHandler;\r
+  BOOLEAN      InterruptQuiesced;\r
+  EFI_STATUS   Status;\r
+  \r
+  if (HandlerType == NULL) {\r
+    //\r
+    // Root SMI handler\r
+    //\r
+    Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+\r
+    Head = &mRootSmiHandlerList;\r
+    for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+      SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
+\r
+      Status = SmiHandler->Handler (\r
+                 (EFI_HANDLE) SmiHandler,\r
+                 Context,\r
+                 CommBuffer,\r
+                 CommBufferSize\r
+                 );\r
+      if (Status == EFI_SUCCESS || Status == EFI_INTERRUPT_PENDING) {\r
+        return Status;\r
+      }\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Non-root SMI handler\r
+  //\r
+  SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, FALSE);\r
+  if (SmiEntry == NULL) {\r
+    //\r
+    // There is no handler registered for this interrupt source\r
+    //\r
+    return EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+  }\r
+\r
+  InterruptQuiesced = FALSE;\r
+  Head = &SmiEntry->SmiHandlers;\r
+  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+    SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
+\r
+    Status = SmiHandler->Handler (\r
+               (EFI_HANDLE) SmiHandler,\r
+               Context,\r
+               CommBuffer,\r
+               CommBufferSize\r
+               );\r
+\r
+    switch (Status) {\r
+    case EFI_INTERRUPT_PENDING:\r
+      //\r
+      // If a handler returns EFI_INTERRUPT_PENDING, the interrupt could not be\r
+      // quiesced, then no additional handlers will be processed,\r
+      // and EFI_INTERRUPT_PENDING will be returned\r
+      //\r
+      return EFI_INTERRUPT_PENDING;\r
+\r
+    case EFI_SUCCESS:\r
+      //\r
+      // If handler return EFI_SUCCESS, the interrupt was handled and quiesced,\r
+      // no other handlers should still be called,\r
+      // and EFI_WARN_INTERRUPT_SOURCE_QUIESCED will be returned\r
+      //\r
+      return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
+\r
+    case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:\r
+      //\r
+      // If at least one of the handlers report EFI_WARN_INTERRUPT_SOURCE_QUIESCED,\r
+      // then this function will return EFI_WARN_INTERRUPT_SOURCE_QUIESCED\r
+      //\r
+      InterruptQuiesced = TRUE;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (InterruptQuiesced) {\r
+    Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
+  } else {\r
+    //\r
+    // If no handler report EFI_WARN_INTERRUPT_SOURCE_QUIESCED, then this\r
+    // function will return EFI_INTERRUPT_PENDING\r
+    //\r
+    Status = EFI_INTERRUPT_PENDING;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Registers a handler to execute within SMM.\r
+\r
+  @param  Handler        Handler service funtion pointer.\r
+  @param  HandlerType    Points to the handler type or NULL for root SMI handlers.\r
+  @param  DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.\r
+\r
+  @retval EFI_SUCCESS           Handler register success.\r
+  @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerRegister (\r
+  IN  EFI_SMM_HANDLER_ENTRY_POINT2  Handler,\r
+  IN  CONST EFI_GUID                *HandlerType  OPTIONAL,\r
+  OUT EFI_HANDLE                    *DispatchHandle\r
+  )\r
+{\r
+  SMI_HANDLER  *SmiHandler;\r
+  SMI_ENTRY    *SmiEntry;\r
+  LIST_ENTRY   *List;\r
+\r
+  if (Handler == NULL || DispatchHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));\r
+  if (SmiHandler == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SmiHandler->Signature = SMI_HANDLER_SIGNATURE;\r
+  SmiHandler->Handler = Handler;\r
+\r
+  if (HandlerType == NULL) {\r
+    //\r
+    // This is root SMI handler\r
+    //\r
+    SmiEntry = NULL;\r
+    List = &mRootSmiHandlerList;\r
+  } else {\r
+    //\r
+    // None root SMI handler\r
+    //\r
+    SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, TRUE);\r
+    if (SmiEntry == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    List = &SmiEntry->SmiHandlers;\r
+  }\r
+\r
+  SmiHandler->SmiEntry = SmiEntry;\r
+  InsertTailList (List, &SmiHandler->Link);\r
+\r
+  *DispatchHandle = (EFI_HANDLE) SmiHandler;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Unregister a handler in SMM.\r
+\r
+  @param  DispatchHandle  The handle that was specified when the handler was registered.\r
+\r
+  @retval EFI_SUCCESS           Handler function was successfully unregistered.\r
+  @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerUnRegister (\r
+  IN EFI_HANDLE  DispatchHandle\r
+  )\r
+{\r
+  SMI_HANDLER  *SmiHandler;\r
+  SMI_ENTRY    *SmiEntry;\r
+\r
+  SmiHandler = (SMI_HANDLER *) DispatchHandle;\r
+\r
+  if (SmiHandler == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (SmiHandler->Signature != SMI_HANDLER_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SmiEntry = SmiHandler->SmiEntry;\r
+\r
+  RemoveEntryList (&SmiHandler->Link);\r
+  FreePool (SmiHandler);\r
+\r
+  if (SmiEntry == NULL) {\r
+    //\r
+    // This is root SMI handler\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (IsListEmpty (&SmiEntry->SmiHandlers)) {\r
+    //\r
+    // No handler registered for this interrupt now, remove the SMI_ENTRY\r
+    //\r
+    RemoveEntryList (&SmiEntry->AllEntries);\r
+\r
+    FreePool (SmiEntry);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r