4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 LIST_ENTRY mSmiEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList
);
13 SMI_ENTRY mRootSmiEntry
= {
15 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry
.AllEntries
),
17 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry
.SmiHandlers
),
21 Finds the SMI entry for the requested handler type.
23 @param HandlerType The type of the interrupt
24 @param Create Create a new entry if not found
32 IN EFI_GUID
*HandlerType
,
41 // Search the SMI entry list for the matching GUID
44 for (Link
= mSmiEntryList
.ForwardLink
;
45 Link
!= &mSmiEntryList
;
46 Link
= Link
->ForwardLink
) {
48 Item
= CR (Link
, SMI_ENTRY
, AllEntries
, SMI_ENTRY_SIGNATURE
);
49 if (CompareGuid (&Item
->HandlerType
, HandlerType
)) {
51 // This is the SMI entry
59 // If the protocol entry was not found and Create is TRUE, then
60 // allocate a new entry
62 if ((SmiEntry
== NULL
) && Create
) {
63 SmiEntry
= AllocatePool (sizeof(SMI_ENTRY
));
64 if (SmiEntry
!= NULL
) {
66 // Initialize new SMI entry structure
68 SmiEntry
->Signature
= SMI_ENTRY_SIGNATURE
;
69 CopyGuid ((VOID
*)&SmiEntry
->HandlerType
, HandlerType
);
70 InitializeListHead (&SmiEntry
->SmiHandlers
);
73 // Add it to SMI entry list
75 InsertTailList (&mSmiEntryList
, &SmiEntry
->AllEntries
);
82 Manage SMI of a particular type.
84 @param HandlerType Points to the handler type or NULL for root SMI handlers.
85 @param Context Points to an optional context buffer.
86 @param CommBuffer Points to the optional communication buffer.
87 @param CommBufferSize Points to the size of the optional communication buffer.
89 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
90 @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.
91 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
92 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
98 IN CONST EFI_GUID
*HandlerType
,
99 IN CONST VOID
*Context OPTIONAL
,
100 IN OUT VOID
*CommBuffer OPTIONAL
,
101 IN OUT UINTN
*CommBufferSize OPTIONAL
107 SMI_HANDLER
*SmiHandler
;
108 BOOLEAN SuccessReturn
;
111 Status
= EFI_NOT_FOUND
;
112 SuccessReturn
= FALSE
;
113 if (HandlerType
== NULL
) {
117 SmiEntry
= &mRootSmiEntry
;
120 // Non-root SMI handler
122 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, FALSE
);
123 if (SmiEntry
== NULL
) {
125 // There is no handler registered for this interrupt source
130 Head
= &SmiEntry
->SmiHandlers
;
132 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
133 SmiHandler
= CR (Link
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
135 Status
= SmiHandler
->Handler (
136 (EFI_HANDLE
) SmiHandler
,
143 case EFI_INTERRUPT_PENDING
:
145 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
146 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
148 if (HandlerType
!= NULL
) {
149 return EFI_INTERRUPT_PENDING
;
155 // If at least one of the handlers returns EFI_SUCCESS then the function will return
156 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
157 // additional handlers will be processed.
159 if (HandlerType
!= NULL
) {
162 SuccessReturn
= TRUE
;
165 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
167 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
168 // then the function will return EFI_SUCCESS.
170 SuccessReturn
= TRUE
;
173 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
175 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
176 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
182 // Unexpected status code returned.
190 Status
= EFI_SUCCESS
;
197 Registers a handler to execute within SMM.
199 @param Handler Handler service funtion pointer.
200 @param HandlerType Points to the handler type or NULL for root SMI handlers.
201 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
203 @retval EFI_SUCCESS Handler register success.
204 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
210 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler
,
211 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
212 OUT EFI_HANDLE
*DispatchHandle
215 SMI_HANDLER
*SmiHandler
;
219 if (Handler
== NULL
|| DispatchHandle
== NULL
) {
220 return EFI_INVALID_PARAMETER
;
223 SmiHandler
= AllocateZeroPool (sizeof (SMI_HANDLER
));
224 if (SmiHandler
== NULL
) {
225 return EFI_OUT_OF_RESOURCES
;
228 SmiHandler
->Signature
= SMI_HANDLER_SIGNATURE
;
229 SmiHandler
->Handler
= Handler
;
230 SmiHandler
->CallerAddr
= (UINTN
)RETURN_ADDRESS (0);
232 if (HandlerType
== NULL
) {
234 // This is root SMI handler
236 SmiEntry
= &mRootSmiEntry
;
239 // None root SMI handler
241 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, TRUE
);
242 if (SmiEntry
== NULL
) {
243 return EFI_OUT_OF_RESOURCES
;
246 List
= &SmiEntry
->SmiHandlers
;
248 SmiHandler
->SmiEntry
= SmiEntry
;
249 InsertTailList (List
, &SmiHandler
->Link
);
251 *DispatchHandle
= (EFI_HANDLE
) SmiHandler
;
257 Unregister a handler in SMM.
259 @param DispatchHandle The handle that was specified when the handler was registered.
261 @retval EFI_SUCCESS Handler function was successfully unregistered.
262 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
267 SmiHandlerUnRegister (
268 IN EFI_HANDLE DispatchHandle
271 SMI_HANDLER
*SmiHandler
;
273 LIST_ENTRY
*EntryLink
;
274 LIST_ENTRY
*HandlerLink
;
276 if (DispatchHandle
== NULL
) {
277 return EFI_INVALID_PARAMETER
;
281 // Look for it in root SMI handlers
284 for ( HandlerLink
= GetFirstNode (&mRootSmiEntry
.SmiHandlers
)
285 ; !IsNull (&mRootSmiEntry
.SmiHandlers
, HandlerLink
) && ((EFI_HANDLE
) SmiHandler
!= DispatchHandle
)
286 ; HandlerLink
= GetNextNode (&mRootSmiEntry
.SmiHandlers
, HandlerLink
)
288 SmiHandler
= CR (HandlerLink
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
292 // Look for it in non-root SMI handlers
294 for ( EntryLink
= GetFirstNode (&mSmiEntryList
)
295 ; !IsNull (&mSmiEntryList
, EntryLink
) && ((EFI_HANDLE
) SmiHandler
!= DispatchHandle
)
296 ; EntryLink
= GetNextNode (&mSmiEntryList
, EntryLink
)
298 SmiEntry
= CR (EntryLink
, SMI_ENTRY
, AllEntries
, SMI_ENTRY_SIGNATURE
);
299 for ( HandlerLink
= GetFirstNode (&SmiEntry
->SmiHandlers
)
300 ; !IsNull (&SmiEntry
->SmiHandlers
, HandlerLink
) && ((EFI_HANDLE
) SmiHandler
!= DispatchHandle
)
301 ; HandlerLink
= GetNextNode (&SmiEntry
->SmiHandlers
, HandlerLink
)
303 SmiHandler
= CR (HandlerLink
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
307 if ((EFI_HANDLE
) SmiHandler
!= DispatchHandle
) {
308 return EFI_INVALID_PARAMETER
;
311 SmiEntry
= SmiHandler
->SmiEntry
;
313 RemoveEntryList (&SmiHandler
->Link
);
314 FreePool (SmiHandler
);
316 if (SmiEntry
== NULL
) {
318 // This is root SMI handler
323 if (IsListEmpty (&SmiEntry
->SmiHandlers
)) {
325 // No handler registered for this interrupt now, remove the SMI_ENTRY
327 RemoveEntryList (&SmiEntry
->AllEntries
);