--- /dev/null
+/** @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