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
);
105 Manage MMI of a particular type.
107 @param HandlerType Points to the handler type or NULL for root MMI handlers.
108 @param Context Points to an optional context buffer.
109 @param CommBuffer Points to the optional communication buffer.
110 @param CommBufferSize Points to the size of the optional communication buffer.
112 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
113 @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
114 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
115 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
121 IN CONST EFI_GUID
*HandlerType
,
122 IN CONST VOID
*Context OPTIONAL
,
123 IN OUT VOID
*CommBuffer OPTIONAL
,
124 IN OUT UINTN
*CommBufferSize OPTIONAL
130 MMI_HANDLER
*MmiHandler
;
131 BOOLEAN SuccessReturn
;
134 Status
= EFI_NOT_FOUND
;
135 SuccessReturn
= FALSE
;
136 if (HandlerType
== NULL
) {
141 Head
= &mRootMmiHandlerList
;
144 // Non-root MMI handler
146 MmiEntry
= MmCoreFindMmiEntry ((EFI_GUID
*)HandlerType
, FALSE
);
147 if (MmiEntry
== NULL
) {
149 // There is no handler registered for this interrupt source
154 Head
= &MmiEntry
->MmiHandlers
;
157 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
158 MmiHandler
= CR (Link
, MMI_HANDLER
, Link
, MMI_HANDLER_SIGNATURE
);
160 Status
= MmiHandler
->Handler (
161 (EFI_HANDLE
)MmiHandler
,
168 case EFI_INTERRUPT_PENDING
:
170 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
171 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
173 if (HandlerType
!= NULL
) {
174 return EFI_INTERRUPT_PENDING
;
181 // If at least one of the handlers returns EFI_SUCCESS then the function will return
182 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
183 // additional handlers will be processed.
185 if (HandlerType
!= NULL
) {
189 SuccessReturn
= TRUE
;
192 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
194 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
195 // then the function will return EFI_SUCCESS.
197 SuccessReturn
= TRUE
;
200 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
202 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
203 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
209 // Unexpected status code returned.
217 Status
= EFI_SUCCESS
;
224 Registers a handler to execute within MM.
226 @param Handler Handler service function pointer.
227 @param HandlerType Points to the handler type or NULL for root MMI handlers.
228 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
230 @retval EFI_SUCCESS Handler register success.
231 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
237 IN EFI_MM_HANDLER_ENTRY_POINT Handler
,
238 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
239 OUT EFI_HANDLE
*DispatchHandle
242 MMI_HANDLER
*MmiHandler
;
246 if ((Handler
== NULL
) || (DispatchHandle
== NULL
)) {
247 return EFI_INVALID_PARAMETER
;
250 MmiHandler
= AllocateZeroPool (sizeof (MMI_HANDLER
));
251 if (MmiHandler
== NULL
) {
252 return EFI_OUT_OF_RESOURCES
;
255 MmiHandler
->Signature
= MMI_HANDLER_SIGNATURE
;
256 MmiHandler
->Handler
= Handler
;
258 if (HandlerType
== NULL
) {
260 // This is root MMI handler
263 List
= &mRootMmiHandlerList
;
266 // None root MMI handler
268 MmiEntry
= MmCoreFindMmiEntry ((EFI_GUID
*)HandlerType
, TRUE
);
269 if (MmiEntry
== NULL
) {
270 return EFI_OUT_OF_RESOURCES
;
273 List
= &MmiEntry
->MmiHandlers
;
276 MmiHandler
->MmiEntry
= MmiEntry
;
277 InsertTailList (List
, &MmiHandler
->Link
);
279 *DispatchHandle
= (EFI_HANDLE
)MmiHandler
;
285 Unregister a handler in MM.
287 @param DispatchHandle The handle that was specified when the handler was registered.
289 @retval EFI_SUCCESS Handler function was successfully unregistered.
290 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
295 MmiHandlerUnRegister (
296 IN EFI_HANDLE DispatchHandle
299 MMI_HANDLER
*MmiHandler
;
302 MmiHandler
= (MMI_HANDLER
*)DispatchHandle
;
304 if (MmiHandler
== NULL
) {
305 return EFI_INVALID_PARAMETER
;
308 if (MmiHandler
->Signature
!= MMI_HANDLER_SIGNATURE
) {
309 return EFI_INVALID_PARAMETER
;
312 MmiEntry
= MmiHandler
->MmiEntry
;
314 RemoveEntryList (&MmiHandler
->Link
);
315 FreePool (MmiHandler
);
317 if (MmiEntry
== NULL
) {
319 // This is root MMI handler
324 if (IsListEmpty (&MmiEntry
->MmiHandlers
)) {
326 // No handler registered for this interrupt now, remove the MMI_ENTRY
328 RemoveEntryList (&MmiEntry
->AllEntries
);