4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "StandaloneMmCore.h"
13 // MM_HANDLER_STATE_NOTIFIER
17 // MM_HANDLER - used for each MM handler
20 #define MMI_ENTRY_SIGNATURE SIGNATURE_32('m','m','i','e')
24 LIST_ENTRY AllEntries
; // All entries
26 EFI_GUID HandlerType
; // Type of interrupt
27 LIST_ENTRY MmiHandlers
; // All handlers
30 #define MMI_HANDLER_SIGNATURE SIGNATURE_32('m','m','i','h')
34 LIST_ENTRY Link
; // Link on MMI_ENTRY.MmiHandlers
35 EFI_MM_HANDLER_ENTRY_POINT Handler
; // The mm handler's entry point
39 LIST_ENTRY mRootMmiHandlerList
= INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList
);
40 LIST_ENTRY mMmiEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList
);
43 Finds the MMI entry for the requested handler type.
45 @param HandlerType The type of the interrupt
46 @param Create Create a new entry if not found
54 IN EFI_GUID
*HandlerType
,
63 // Search the MMI entry list for the matching GUID
66 for (Link
= mMmiEntryList
.ForwardLink
;
67 Link
!= &mMmiEntryList
;
68 Link
= Link
->ForwardLink
) {
70 Item
= CR (Link
, MMI_ENTRY
, AllEntries
, MMI_ENTRY_SIGNATURE
);
71 if (CompareGuid (&Item
->HandlerType
, HandlerType
)) {
73 // This is the MMI entry
81 // If the protocol entry was not found and Create is TRUE, then
82 // allocate a new entry
84 if ((MmiEntry
== NULL
) && Create
) {
85 MmiEntry
= AllocatePool (sizeof (MMI_ENTRY
));
86 if (MmiEntry
!= NULL
) {
88 // Initialize new MMI entry structure
90 MmiEntry
->Signature
= MMI_ENTRY_SIGNATURE
;
91 CopyGuid ((VOID
*)&MmiEntry
->HandlerType
, HandlerType
);
92 InitializeListHead (&MmiEntry
->MmiHandlers
);
95 // Add it to MMI entry list
97 InsertTailList (&mMmiEntryList
, &MmiEntry
->AllEntries
);
104 Manage MMI of a particular type.
106 @param HandlerType Points to the handler type or NULL for root MMI handlers.
107 @param Context Points to an optional context buffer.
108 @param CommBuffer Points to the optional communication buffer.
109 @param CommBufferSize Points to the size of the optional communication buffer.
111 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
112 @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
113 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
114 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
120 IN CONST EFI_GUID
*HandlerType
,
121 IN CONST VOID
*Context OPTIONAL
,
122 IN OUT VOID
*CommBuffer OPTIONAL
,
123 IN OUT UINTN
*CommBufferSize OPTIONAL
129 MMI_HANDLER
*MmiHandler
;
130 BOOLEAN SuccessReturn
;
133 Status
= EFI_NOT_FOUND
;
134 SuccessReturn
= FALSE
;
135 if (HandlerType
== NULL
) {
140 Head
= &mRootMmiHandlerList
;
143 // Non-root MMI handler
145 MmiEntry
= MmCoreFindMmiEntry ((EFI_GUID
*) HandlerType
, FALSE
);
146 if (MmiEntry
== NULL
) {
148 // There is no handler registered for this interrupt source
153 Head
= &MmiEntry
->MmiHandlers
;
156 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
157 MmiHandler
= CR (Link
, MMI_HANDLER
, Link
, MMI_HANDLER_SIGNATURE
);
159 Status
= MmiHandler
->Handler (
160 (EFI_HANDLE
) MmiHandler
,
167 case EFI_INTERRUPT_PENDING
:
169 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
170 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
172 if (HandlerType
!= NULL
) {
173 return EFI_INTERRUPT_PENDING
;
179 // If at least one of the handlers returns EFI_SUCCESS then the function will return
180 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
181 // additional handlers will be processed.
183 if (HandlerType
!= NULL
) {
186 SuccessReturn
= TRUE
;
189 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
191 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
192 // then the function will return EFI_SUCCESS.
194 SuccessReturn
= TRUE
;
197 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
199 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
200 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
206 // Unexpected status code returned.
214 Status
= EFI_SUCCESS
;
221 Registers a handler to execute within MM.
223 @param Handler Handler service function pointer.
224 @param HandlerType Points to the handler type or NULL for root MMI handlers.
225 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
227 @retval EFI_SUCCESS Handler register success.
228 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
234 IN EFI_MM_HANDLER_ENTRY_POINT Handler
,
235 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
236 OUT EFI_HANDLE
*DispatchHandle
239 MMI_HANDLER
*MmiHandler
;
243 if (Handler
== NULL
|| DispatchHandle
== NULL
) {
244 return EFI_INVALID_PARAMETER
;
247 MmiHandler
= AllocateZeroPool (sizeof (MMI_HANDLER
));
248 if (MmiHandler
== NULL
) {
249 return EFI_OUT_OF_RESOURCES
;
252 MmiHandler
->Signature
= MMI_HANDLER_SIGNATURE
;
253 MmiHandler
->Handler
= Handler
;
255 if (HandlerType
== NULL
) {
257 // This is root MMI handler
260 List
= &mRootMmiHandlerList
;
263 // None root MMI handler
265 MmiEntry
= MmCoreFindMmiEntry ((EFI_GUID
*) HandlerType
, TRUE
);
266 if (MmiEntry
== NULL
) {
267 return EFI_OUT_OF_RESOURCES
;
270 List
= &MmiEntry
->MmiHandlers
;
273 MmiHandler
->MmiEntry
= MmiEntry
;
274 InsertTailList (List
, &MmiHandler
->Link
);
276 *DispatchHandle
= (EFI_HANDLE
) MmiHandler
;
282 Unregister a handler in MM.
284 @param DispatchHandle The handle that was specified when the handler was registered.
286 @retval EFI_SUCCESS Handler function was successfully unregistered.
287 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
292 MmiHandlerUnRegister (
293 IN EFI_HANDLE DispatchHandle
296 MMI_HANDLER
*MmiHandler
;
299 MmiHandler
= (MMI_HANDLER
*) DispatchHandle
;
301 if (MmiHandler
== NULL
) {
302 return EFI_INVALID_PARAMETER
;
305 if (MmiHandler
->Signature
!= MMI_HANDLER_SIGNATURE
) {
306 return EFI_INVALID_PARAMETER
;
309 MmiEntry
= MmiHandler
->MmiEntry
;
311 RemoveEntryList (&MmiHandler
->Link
);
312 FreePool (MmiHandler
);
314 if (MmiEntry
== NULL
) {
316 // This is root MMI handler
321 if (IsListEmpty (&MmiEntry
->MmiHandlers
)) {
323 // No handler registered for this interrupt now, remove the MMI_ENTRY
325 RemoveEntryList (&MmiEntry
->AllEntries
);