]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StandaloneMmPkg/Core/Mmi.c
StandaloneMmPkg/Core: Implementation of Standalone MM Core Module.
[mirror_edk2.git] / StandaloneMmPkg / Core / Mmi.c
diff --git a/StandaloneMmPkg/Core/Mmi.c b/StandaloneMmPkg/Core/Mmi.c
new file mode 100644 (file)
index 0000000..7193ebc
--- /dev/null
@@ -0,0 +1,337 @@
+/** @file\r
+  MMI management.\r
+\r
+  Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2018, ARM Limited. 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 "StandaloneMmCore.h"\r
+\r
+//\r
+// MM_HANDLER_STATE_NOTIFIER\r
+//\r
+\r
+//\r
+// MM_HANDLER - used for each MM handler\r
+//\r
+\r
+#define MMI_ENTRY_SIGNATURE  SIGNATURE_32('m','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  MmiHandlers; // All handlers\r
+} MMI_ENTRY;\r
+\r
+#define MMI_HANDLER_SIGNATURE  SIGNATURE_32('m','m','i','h')\r
+\r
+typedef struct {\r
+  UINTN                         Signature;\r
+  LIST_ENTRY                    Link;        // Link on MMI_ENTRY.MmiHandlers\r
+  EFI_MM_HANDLER_ENTRY_POINT    Handler;     // The mm handler's entry point\r
+  MMI_ENTRY                     *MmiEntry;\r
+} MMI_HANDLER;\r
+\r
+LIST_ENTRY  mRootMmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList);\r
+LIST_ENTRY  mMmiEntryList       = INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList);\r
+\r
+/**\r
+  Finds the MMI 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 MMI entry\r
+\r
+**/\r
+MMI_ENTRY  *\r
+EFIAPI\r
+MmCoreFindMmiEntry (\r
+  IN EFI_GUID  *HandlerType,\r
+  IN BOOLEAN   Create\r
+  )\r
+{\r
+  LIST_ENTRY  *Link;\r
+  MMI_ENTRY   *Item;\r
+  MMI_ENTRY   *MmiEntry;\r
+\r
+  //\r
+  // Search the MMI entry list for the matching GUID\r
+  //\r
+  MmiEntry = NULL;\r
+  for (Link = mMmiEntryList.ForwardLink;\r
+       Link != &mMmiEntryList;\r
+       Link = Link->ForwardLink) {\r
+\r
+    Item = CR (Link, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE);\r
+    if (CompareGuid (&Item->HandlerType, HandlerType)) {\r
+      //\r
+      // This is the MMI entry\r
+      //\r
+      MmiEntry = 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 ((MmiEntry == NULL) && Create) {\r
+    MmiEntry = AllocatePool (sizeof (MMI_ENTRY));\r
+    if (MmiEntry != NULL) {\r
+      //\r
+      // Initialize new MMI entry structure\r
+      //\r
+      MmiEntry->Signature = MMI_ENTRY_SIGNATURE;\r
+      CopyGuid ((VOID *)&MmiEntry->HandlerType, HandlerType);\r
+      InitializeListHead (&MmiEntry->MmiHandlers);\r
+\r
+      //\r
+      // Add it to MMI entry list\r
+      //\r
+      InsertTailList (&mMmiEntryList, &MmiEntry->AllEntries);\r
+    }\r
+  }\r
+  return MmiEntry;\r
+}\r
+\r
+/**\r
+  Manage MMI of a particular type.\r
+\r
+  @param  HandlerType    Points to the handler type or NULL for root MMI 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_WARN_INTERRUPT_SOURCE_PENDING  Interrupt source was processed successfully but not quiesced.\r
+  @retval EFI_INTERRUPT_PENDING              One or more MMI sources could not be quiesced.\r
+  @retval EFI_NOT_FOUND                      Interrupt source was not handled or quiesced.\r
+  @retval EFI_SUCCESS                        Interrupt source was handled and quiesced.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmiManage (\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
+  MMI_ENTRY    *MmiEntry;\r
+  MMI_HANDLER  *MmiHandler;\r
+  BOOLEAN      SuccessReturn;\r
+  EFI_STATUS   Status;\r
+\r
+  Status = EFI_NOT_FOUND;\r
+  SuccessReturn = FALSE;\r
+  if (HandlerType == NULL) {\r
+    //\r
+    // Root MMI handler\r
+    //\r
+\r
+    Head = &mRootMmiHandlerList;\r
+  } else {\r
+    //\r
+    // Non-root MMI handler\r
+    //\r
+    MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, FALSE);\r
+    if (MmiEntry == NULL) {\r
+      //\r
+      // There is no handler registered for this interrupt source\r
+      //\r
+      return Status;\r
+    }\r
+\r
+    Head = &MmiEntry->MmiHandlers;\r
+  }\r
+\r
+  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+    MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);\r
+\r
+    Status = MmiHandler->Handler (\r
+               (EFI_HANDLE) MmiHandler,\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 and HandlerType is not NULL then\r
+      // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.\r
+      //\r
+      if (HandlerType != NULL) {\r
+        return EFI_INTERRUPT_PENDING;\r
+      }\r
+      break;\r
+\r
+    case EFI_SUCCESS:\r
+      //\r
+      // If at least one of the handlers returns EFI_SUCCESS then the function will return\r
+      // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no\r
+      // additional handlers will be processed.\r
+      //\r
+      if (HandlerType != NULL) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      SuccessReturn = TRUE;\r
+      break;\r
+\r
+    case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:\r
+      //\r
+      // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED\r
+      // then the function will return EFI_SUCCESS.\r
+      //\r
+      SuccessReturn = TRUE;\r
+      break;\r
+\r
+    case EFI_WARN_INTERRUPT_SOURCE_PENDING:\r
+      //\r
+      // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING\r
+      // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.\r
+      //\r
+      break;\r
+\r
+    default:\r
+      //\r
+      // Unexpected status code returned.\r
+      //\r
+      ASSERT (FALSE);\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (SuccessReturn) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Registers a handler to execute within MM.\r
+\r
+  @param  Handler        Handler service funtion pointer.\r
+  @param  HandlerType    Points to the handler type or NULL for root MMI 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
+MmiHandlerRegister (\r
+  IN  EFI_MM_HANDLER_ENTRY_POINT    Handler,\r
+  IN  CONST EFI_GUID                *HandlerType  OPTIONAL,\r
+  OUT EFI_HANDLE                    *DispatchHandle\r
+  )\r
+{\r
+  MMI_HANDLER  *MmiHandler;\r
+  MMI_ENTRY    *MmiEntry;\r
+  LIST_ENTRY   *List;\r
+\r
+  if (Handler == NULL || DispatchHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER));\r
+  if (MmiHandler == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  MmiHandler->Signature = MMI_HANDLER_SIGNATURE;\r
+  MmiHandler->Handler = Handler;\r
+\r
+  if (HandlerType == NULL) {\r
+    //\r
+    // This is root MMI handler\r
+    //\r
+    MmiEntry = NULL;\r
+    List = &mRootMmiHandlerList;\r
+  } else {\r
+    //\r
+    // None root MMI handler\r
+    //\r
+    MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, TRUE);\r
+    if (MmiEntry == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    List = &MmiEntry->MmiHandlers;\r
+  }\r
+\r
+  MmiHandler->MmiEntry = MmiEntry;\r
+  InsertTailList (List, &MmiHandler->Link);\r
+\r
+  *DispatchHandle = (EFI_HANDLE) MmiHandler;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Unregister a handler in MM.\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
+MmiHandlerUnRegister (\r
+  IN EFI_HANDLE  DispatchHandle\r
+  )\r
+{\r
+  MMI_HANDLER  *MmiHandler;\r
+  MMI_ENTRY    *MmiEntry;\r
+\r
+  MmiHandler = (MMI_HANDLER *) DispatchHandle;\r
+\r
+  if (MmiHandler == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MmiEntry = MmiHandler->MmiEntry;\r
+\r
+  RemoveEntryList (&MmiHandler->Link);\r
+  FreePool (MmiHandler);\r
+\r
+  if (MmiEntry == NULL) {\r
+    //\r
+    // This is root MMI handler\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (IsListEmpty (&MmiEntry->MmiHandlers)) {\r
+    //\r
+    // No handler registered for this interrupt now, remove the MMI_ENTRY\r
+    //\r
+    RemoveEntryList (&MmiEntry->AllEntries);\r
+\r
+    FreePool (MmiEntry);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r