diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Core/PiSmmCore/Smi.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Core/PiSmmCore/Smi.c')
| -rw-r--r-- | MdeModulePkg/Core/PiSmmCore/Smi.c | 920 |
1 files changed, 460 insertions, 460 deletions
diff --git a/MdeModulePkg/Core/PiSmmCore/Smi.c b/MdeModulePkg/Core/PiSmmCore/Smi.c index 6b56fa5f69..f3ab4bbd92 100644 --- a/MdeModulePkg/Core/PiSmmCore/Smi.c +++ b/MdeModulePkg/Core/PiSmmCore/Smi.c @@ -1,460 +1,460 @@ -/** @file
- SMI management.
-
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PiSmmCore.h"
-
-//
-// mSmiManageCallingDepth is used to track the depth of recursive calls of SmiManage.
-//
-UINTN mSmiManageCallingDepth = 0;
-
-LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);
-
-SMI_ENTRY mRootSmiEntry = {
- SMI_ENTRY_SIGNATURE,
- INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries),
- { 0 },
- INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.SmiHandlers),
-};
-
-/**
- Finds the SMI entry for the requested handler type.
-
- @param HandlerType The type of the interrupt
- @param Create Create a new entry if not found
-
- @return SMI entry
-
-**/
-SMI_ENTRY *
-EFIAPI
-SmmCoreFindSmiEntry (
- IN EFI_GUID *HandlerType,
- IN BOOLEAN Create
- )
-{
- LIST_ENTRY *Link;
- SMI_ENTRY *Item;
- SMI_ENTRY *SmiEntry;
-
- //
- // Search the SMI entry list for the matching GUID
- //
- SmiEntry = NULL;
- for (Link = mSmiEntryList.ForwardLink;
- Link != &mSmiEntryList;
- Link = Link->ForwardLink)
- {
- Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- if (CompareGuid (&Item->HandlerType, HandlerType)) {
- //
- // This is the SMI entry
- //
- SmiEntry = Item;
- break;
- }
- }
-
- //
- // If the protocol entry was not found and Create is TRUE, then
- // allocate a new entry
- //
- if ((SmiEntry == NULL) && Create) {
- SmiEntry = AllocatePool (sizeof (SMI_ENTRY));
- if (SmiEntry != NULL) {
- //
- // Initialize new SMI entry structure
- //
- SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
- CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
- InitializeListHead (&SmiEntry->SmiHandlers);
-
- //
- // Add it to SMI entry list
- //
- InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries);
- }
- }
-
- return SmiEntry;
-}
-
-/**
- Remove SmiHandler and free the memory it used.
- If SmiEntry is empty, remove SmiEntry and free the memory it used.
-
- @param SmiHandler Points to SMI handler.
- @param SmiEntry Points to SMI Entry or NULL for root SMI handlers.
-
- @retval TRUE SmiEntry is removed.
- @retval FALSE SmiEntry is not removed.
-**/
-BOOLEAN
-RemoveSmiHandler (
- IN SMI_HANDLER *SmiHandler,
- IN SMI_ENTRY *SmiEntry
- )
-{
- ASSERT (SmiHandler->ToRemove);
- RemoveEntryList (&SmiHandler->Link);
- FreePool (SmiHandler);
-
- //
- // Remove the SMI_ENTRY if all handlers have been removed.
- //
- if (SmiEntry != NULL) {
- if (IsListEmpty (&SmiEntry->SmiHandlers)) {
- RemoveEntryList (&SmiEntry->AllEntries);
- FreePool (SmiEntry);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Manage SMI of a particular type.
-
- @param HandlerType Points to the handler type or NULL for root SMI handlers.
- @param Context Points to an optional context buffer.
- @param CommBuffer Points to the optional communication buffer.
- @param CommBufferSize Points to the size of the optional communication buffer.
-
- @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
- @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.
- @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
- @retval EFI_SUCCESS Interrupt source was handled and quiesced.
-
-**/
-EFI_STATUS
-EFIAPI
-SmiManage (
- IN CONST EFI_GUID *HandlerType,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- LIST_ENTRY *Link;
- LIST_ENTRY *Head;
- LIST_ENTRY *EntryLink;
- SMI_ENTRY *SmiEntry;
- SMI_HANDLER *SmiHandler;
- EFI_STATUS ReturnStatus;
- BOOLEAN WillReturn;
- EFI_STATUS Status;
-
- PERF_FUNCTION_BEGIN ();
- mSmiManageCallingDepth++;
- WillReturn = FALSE;
- Status = EFI_NOT_FOUND;
- ReturnStatus = Status;
- if (HandlerType == NULL) {
- //
- // Root SMI handler
- //
- SmiEntry = &mRootSmiEntry;
- } else {
- //
- // Non-root SMI handler
- //
- SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, FALSE);
- if (SmiEntry == NULL) {
- //
- // There is no handler registered for this interrupt source
- //
- PERF_FUNCTION_END ();
- return Status;
- }
- }
-
- Head = &SmiEntry->SmiHandlers;
-
- for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
-
- Status = SmiHandler->Handler (
- (EFI_HANDLE)SmiHandler,
- Context,
- CommBuffer,
- CommBufferSize
- );
-
- switch (Status) {
- case EFI_INTERRUPT_PENDING:
- //
- // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
- // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
- //
- if (HandlerType != NULL) {
- PERF_FUNCTION_END ();
- ReturnStatus = EFI_INTERRUPT_PENDING;
- WillReturn = TRUE;
- } else {
- //
- // If any other handler's result sets ReturnStatus as EFI_SUCCESS, the return status
- // will be EFI_SUCCESS.
- //
- if (ReturnStatus != EFI_SUCCESS) {
- ReturnStatus = Status;
- }
- }
-
- break;
-
- case EFI_SUCCESS:
- //
- // If at least one of the handlers returns EFI_SUCCESS then the function will return
- // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
- // additional handlers will be processed.
- //
- if (HandlerType != NULL) {
- PERF_FUNCTION_END ();
- WillReturn = TRUE;
- }
-
- ReturnStatus = EFI_SUCCESS;
- break;
-
- case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
- //
- // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
- // then the function will return EFI_SUCCESS.
- //
- ReturnStatus = EFI_SUCCESS;
- break;
-
- case EFI_WARN_INTERRUPT_SOURCE_PENDING:
- //
- // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
- // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
- //
- if (ReturnStatus != EFI_SUCCESS) {
- ReturnStatus = Status;
- }
-
- break;
-
- default:
- //
- // Unexpected status code returned.
- //
- ASSERT (FALSE);
- break;
- }
-
- if (WillReturn) {
- break;
- }
- }
-
- ASSERT (mSmiManageCallingDepth > 0);
- mSmiManageCallingDepth--;
-
- //
- // SmiHandlerUnRegister() calls from SMI handlers are deferred till this point.
- // Before returned from SmiManage, delete the SmiHandler which is
- // marked as ToRemove.
- // Note that SmiManage can be called recursively.
- //
- if (mSmiManageCallingDepth == 0) {
- //
- // Go through all SmiHandler in root SMI handlers
- //
- for ( Link = GetFirstNode (&mRootSmiEntry.SmiHandlers)
- ; !IsNull (&mRootSmiEntry.SmiHandlers, Link);
- )
- {
- //
- // SmiHandler might be removed in below, so cache the next link in Link
- //
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- Link = GetNextNode (&mRootSmiEntry.SmiHandlers, Link);
- if (SmiHandler->ToRemove) {
- //
- // Remove SmiHandler if the ToRemove is set.
- //
- RemoveSmiHandler (SmiHandler, NULL);
- }
- }
-
- //
- // Go through all SmiHandler in non-root SMI handlers
- //
- for ( EntryLink = GetFirstNode (&mSmiEntryList)
- ; !IsNull (&mSmiEntryList, EntryLink);
- )
- {
- //
- // SmiEntry might be removed in below, so cache the next link in EntryLink
- //
- SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- EntryLink = GetNextNode (&mSmiEntryList, EntryLink);
- for ( Link = GetFirstNode (&SmiEntry->SmiHandlers)
- ; !IsNull (&SmiEntry->SmiHandlers, Link);
- )
- {
- //
- // SmiHandler might be removed in below, so cache the next link in Link
- //
- SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- Link = GetNextNode (&SmiEntry->SmiHandlers, Link);
- if (SmiHandler->ToRemove) {
- if (RemoveSmiHandler (SmiHandler, SmiEntry)) {
- break;
- }
- }
- }
- }
- }
-
- PERF_FUNCTION_END ();
- return ReturnStatus;
-}
-
-/**
- Registers a handler to execute within SMM.
-
- @param Handler Handler service function pointer.
- @param HandlerType Points to the handler type or NULL for root SMI handlers.
- @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
-
- @retval EFI_SUCCESS Handler register success.
- @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerRegister (
- IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
- IN CONST EFI_GUID *HandlerType OPTIONAL,
- OUT EFI_HANDLE *DispatchHandle
- )
-{
- SMI_HANDLER *SmiHandler;
- SMI_ENTRY *SmiEntry;
- LIST_ENTRY *List;
-
- if ((Handler == NULL) || (DispatchHandle == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
- if (SmiHandler == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
- SmiHandler->Handler = Handler;
- SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0);
- SmiHandler->ToRemove = FALSE;
-
- if (HandlerType == NULL) {
- //
- // This is root SMI handler
- //
- SmiEntry = &mRootSmiEntry;
- } else {
- //
- // None root SMI handler
- //
- SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, TRUE);
- if (SmiEntry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- List = &SmiEntry->SmiHandlers;
-
- SmiHandler->SmiEntry = SmiEntry;
- InsertTailList (List, &SmiHandler->Link);
-
- *DispatchHandle = (EFI_HANDLE)SmiHandler;
-
- return EFI_SUCCESS;
-}
-
-/**
- Unregister a handler in SMM.
-
- @param DispatchHandle The handle that was specified when the handler was registered.
-
- @retval EFI_SUCCESS Handler function was successfully unregistered.
- @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
-
-**/
-EFI_STATUS
-EFIAPI
-SmiHandlerUnRegister (
- IN EFI_HANDLE DispatchHandle
- )
-{
- SMI_HANDLER *SmiHandler;
- SMI_ENTRY *SmiEntry;
- LIST_ENTRY *EntryLink;
- LIST_ENTRY *HandlerLink;
-
- if (DispatchHandle == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Look for it in root SMI handlers
- //
- SmiHandler = NULL;
- for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers)
- ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
- ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink)
- )
- {
- SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- }
-
- //
- // Look for it in non-root SMI handlers
- //
- for ( EntryLink = GetFirstNode (&mSmiEntryList)
- ; !IsNull (&mSmiEntryList, EntryLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
- ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink)
- )
- {
- SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
- for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers)
- ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
- ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink)
- )
- {
- SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
- }
- }
-
- if (SmiHandler == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ASSERT ((EFI_HANDLE)SmiHandler == DispatchHandle);
- SmiHandler->ToRemove = TRUE;
-
- if (mSmiManageCallingDepth > 0) {
- //
- // This function is called from SmiManage()
- // Do not delete or remove SmiHandler or SmiEntry now.
- // SmiManage will handle it later
- //
- return EFI_SUCCESS;
- }
-
- SmiEntry = SmiHandler->SmiEntry;
-
- //
- // For root SMI handler, use NULL for SmiEntry
- //
- RemoveSmiHandler (SmiHandler, (SmiEntry == &mRootSmiEntry) ? NULL : SmiEntry);
- return EFI_SUCCESS;
-}
+/** @file + SMI management. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +// +// mSmiManageCallingDepth is used to track the depth of recursive calls of SmiManage. +// +UINTN mSmiManageCallingDepth = 0; + +LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList); + +SMI_ENTRY mRootSmiEntry = { + SMI_ENTRY_SIGNATURE, + INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries), + { 0 }, + INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.SmiHandlers), +}; + +/** + Finds the SMI entry for the requested handler type. + + @param HandlerType The type of the interrupt + @param Create Create a new entry if not found + + @return SMI entry + +**/ +SMI_ENTRY * +EFIAPI +SmmCoreFindSmiEntry ( + IN EFI_GUID *HandlerType, + IN BOOLEAN Create + ) +{ + LIST_ENTRY *Link; + SMI_ENTRY *Item; + SMI_ENTRY *SmiEntry; + + // + // Search the SMI entry list for the matching GUID + // + SmiEntry = NULL; + for (Link = mSmiEntryList.ForwardLink; + Link != &mSmiEntryList; + Link = Link->ForwardLink) + { + Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + if (CompareGuid (&Item->HandlerType, HandlerType)) { + // + // This is the SMI entry + // + SmiEntry = Item; + break; + } + } + + // + // If the protocol entry was not found and Create is TRUE, then + // allocate a new entry + // + if ((SmiEntry == NULL) && Create) { + SmiEntry = AllocatePool (sizeof (SMI_ENTRY)); + if (SmiEntry != NULL) { + // + // Initialize new SMI entry structure + // + SmiEntry->Signature = SMI_ENTRY_SIGNATURE; + CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType); + InitializeListHead (&SmiEntry->SmiHandlers); + + // + // Add it to SMI entry list + // + InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries); + } + } + + return SmiEntry; +} + +/** + Remove SmiHandler and free the memory it used. + If SmiEntry is empty, remove SmiEntry and free the memory it used. + + @param SmiHandler Points to SMI handler. + @param SmiEntry Points to SMI Entry or NULL for root SMI handlers. + + @retval TRUE SmiEntry is removed. + @retval FALSE SmiEntry is not removed. +**/ +BOOLEAN +RemoveSmiHandler ( + IN SMI_HANDLER *SmiHandler, + IN SMI_ENTRY *SmiEntry + ) +{ + ASSERT (SmiHandler->ToRemove); + RemoveEntryList (&SmiHandler->Link); + FreePool (SmiHandler); + + // + // Remove the SMI_ENTRY if all handlers have been removed. + // + if (SmiEntry != NULL) { + if (IsListEmpty (&SmiEntry->SmiHandlers)) { + RemoveEntryList (&SmiEntry->AllEntries); + FreePool (SmiEntry); + return TRUE; + } + } + + return FALSE; +} + +/** + Manage SMI of a particular type. + + @param HandlerType Points to the handler type or NULL for root SMI handlers. + @param Context Points to an optional context buffer. + @param CommBuffer Points to the optional communication buffer. + @param CommBufferSize Points to the size of the optional communication buffer. + + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced. + @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced. + @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced. + @retval EFI_SUCCESS Interrupt source was handled and quiesced. + +**/ +EFI_STATUS +EFIAPI +SmiManage ( + IN CONST EFI_GUID *HandlerType, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *Head; + LIST_ENTRY *EntryLink; + SMI_ENTRY *SmiEntry; + SMI_HANDLER *SmiHandler; + EFI_STATUS ReturnStatus; + BOOLEAN WillReturn; + EFI_STATUS Status; + + PERF_FUNCTION_BEGIN (); + mSmiManageCallingDepth++; + WillReturn = FALSE; + Status = EFI_NOT_FOUND; + ReturnStatus = Status; + if (HandlerType == NULL) { + // + // Root SMI handler + // + SmiEntry = &mRootSmiEntry; + } else { + // + // Non-root SMI handler + // + SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, FALSE); + if (SmiEntry == NULL) { + // + // There is no handler registered for this interrupt source + // + PERF_FUNCTION_END (); + return Status; + } + } + + Head = &SmiEntry->SmiHandlers; + + for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + + Status = SmiHandler->Handler ( + (EFI_HANDLE)SmiHandler, + Context, + CommBuffer, + CommBufferSize + ); + + switch (Status) { + case EFI_INTERRUPT_PENDING: + // + // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then + // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned. + // + if (HandlerType != NULL) { + PERF_FUNCTION_END (); + ReturnStatus = EFI_INTERRUPT_PENDING; + WillReturn = TRUE; + } else { + // + // If any other handler's result sets ReturnStatus as EFI_SUCCESS, the return status + // will be EFI_SUCCESS. + // + if (ReturnStatus != EFI_SUCCESS) { + ReturnStatus = Status; + } + } + + break; + + case EFI_SUCCESS: + // + // If at least one of the handlers returns EFI_SUCCESS then the function will return + // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no + // additional handlers will be processed. + // + if (HandlerType != NULL) { + PERF_FUNCTION_END (); + WillReturn = TRUE; + } + + ReturnStatus = EFI_SUCCESS; + break; + + case EFI_WARN_INTERRUPT_SOURCE_QUIESCED: + // + // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED + // then the function will return EFI_SUCCESS. + // + ReturnStatus = EFI_SUCCESS; + break; + + case EFI_WARN_INTERRUPT_SOURCE_PENDING: + // + // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING + // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned. + // + if (ReturnStatus != EFI_SUCCESS) { + ReturnStatus = Status; + } + + break; + + default: + // + // Unexpected status code returned. + // + ASSERT (FALSE); + break; + } + + if (WillReturn) { + break; + } + } + + ASSERT (mSmiManageCallingDepth > 0); + mSmiManageCallingDepth--; + + // + // SmiHandlerUnRegister() calls from SMI handlers are deferred till this point. + // Before returned from SmiManage, delete the SmiHandler which is + // marked as ToRemove. + // Note that SmiManage can be called recursively. + // + if (mSmiManageCallingDepth == 0) { + // + // Go through all SmiHandler in root SMI handlers + // + for ( Link = GetFirstNode (&mRootSmiEntry.SmiHandlers) + ; !IsNull (&mRootSmiEntry.SmiHandlers, Link); + ) + { + // + // SmiHandler might be removed in below, so cache the next link in Link + // + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + Link = GetNextNode (&mRootSmiEntry.SmiHandlers, Link); + if (SmiHandler->ToRemove) { + // + // Remove SmiHandler if the ToRemove is set. + // + RemoveSmiHandler (SmiHandler, NULL); + } + } + + // + // Go through all SmiHandler in non-root SMI handlers + // + for ( EntryLink = GetFirstNode (&mSmiEntryList) + ; !IsNull (&mSmiEntryList, EntryLink); + ) + { + // + // SmiEntry might be removed in below, so cache the next link in EntryLink + // + SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + EntryLink = GetNextNode (&mSmiEntryList, EntryLink); + for ( Link = GetFirstNode (&SmiEntry->SmiHandlers) + ; !IsNull (&SmiEntry->SmiHandlers, Link); + ) + { + // + // SmiHandler might be removed in below, so cache the next link in Link + // + SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + Link = GetNextNode (&SmiEntry->SmiHandlers, Link); + if (SmiHandler->ToRemove) { + if (RemoveSmiHandler (SmiHandler, SmiEntry)) { + break; + } + } + } + } + } + + PERF_FUNCTION_END (); + return ReturnStatus; +} + +/** + Registers a handler to execute within SMM. + + @param Handler Handler service function pointer. + @param HandlerType Points to the handler type or NULL for root SMI handlers. + @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function. + + @retval EFI_SUCCESS Handler register success. + @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL. + +**/ +EFI_STATUS +EFIAPI +SmiHandlerRegister ( + IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, + IN CONST EFI_GUID *HandlerType OPTIONAL, + OUT EFI_HANDLE *DispatchHandle + ) +{ + SMI_HANDLER *SmiHandler; + SMI_ENTRY *SmiEntry; + LIST_ENTRY *List; + + if ((Handler == NULL) || (DispatchHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER)); + if (SmiHandler == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SmiHandler->Signature = SMI_HANDLER_SIGNATURE; + SmiHandler->Handler = Handler; + SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0); + SmiHandler->ToRemove = FALSE; + + if (HandlerType == NULL) { + // + // This is root SMI handler + // + SmiEntry = &mRootSmiEntry; + } else { + // + // None root SMI handler + // + SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, TRUE); + if (SmiEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + List = &SmiEntry->SmiHandlers; + + SmiHandler->SmiEntry = SmiEntry; + InsertTailList (List, &SmiHandler->Link); + + *DispatchHandle = (EFI_HANDLE)SmiHandler; + + return EFI_SUCCESS; +} + +/** + Unregister a handler in SMM. + + @param DispatchHandle The handle that was specified when the handler was registered. + + @retval EFI_SUCCESS Handler function was successfully unregistered. + @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle. + +**/ +EFI_STATUS +EFIAPI +SmiHandlerUnRegister ( + IN EFI_HANDLE DispatchHandle + ) +{ + SMI_HANDLER *SmiHandler; + SMI_ENTRY *SmiEntry; + LIST_ENTRY *EntryLink; + LIST_ENTRY *HandlerLink; + + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Look for it in root SMI handlers + // + SmiHandler = NULL; + for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers) + ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle) + ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink) + ) + { + SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + } + + // + // Look for it in non-root SMI handlers + // + for ( EntryLink = GetFirstNode (&mSmiEntryList) + ; !IsNull (&mSmiEntryList, EntryLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle) + ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink) + ) + { + SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); + for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers) + ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle) + ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink) + ) + { + SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE); + } + } + + if (SmiHandler == NULL) { + return EFI_INVALID_PARAMETER; + } + + ASSERT ((EFI_HANDLE)SmiHandler == DispatchHandle); + SmiHandler->ToRemove = TRUE; + + if (mSmiManageCallingDepth > 0) { + // + // This function is called from SmiManage() + // Do not delete or remove SmiHandler or SmiEntry now. + // SmiManage will handle it later + // + return EFI_SUCCESS; + } + + SmiEntry = SmiHandler->SmiEntry; + + // + // For root SMI handler, use NULL for SmiEntry + // + RemoveSmiHandler (SmiHandler, (SmiEntry == &mRootSmiEntry) ? NULL : SmiEntry); + return EFI_SUCCESS; +} |
