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
);
83 Manage SMI of a particular type.
85 @param HandlerType Points to the handler type or NULL for root SMI handlers.
86 @param Context Points to an optional context buffer.
87 @param CommBuffer Points to the optional communication buffer.
88 @param CommBufferSize Points to the size of the optional communication buffer.
90 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
91 @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.
92 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
93 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
99 IN CONST EFI_GUID
*HandlerType
,
100 IN CONST VOID
*Context OPTIONAL
,
101 IN OUT VOID
*CommBuffer OPTIONAL
,
102 IN OUT UINTN
*CommBufferSize OPTIONAL
108 SMI_HANDLER
*SmiHandler
;
109 BOOLEAN SuccessReturn
;
112 Status
= EFI_NOT_FOUND
;
113 SuccessReturn
= FALSE
;
114 if (HandlerType
== NULL
) {
118 SmiEntry
= &mRootSmiEntry
;
121 // Non-root SMI handler
123 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*)HandlerType
, FALSE
);
124 if (SmiEntry
== NULL
) {
126 // There is no handler registered for this interrupt source
132 Head
= &SmiEntry
->SmiHandlers
;
134 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
135 SmiHandler
= CR (Link
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
137 Status
= SmiHandler
->Handler (
138 (EFI_HANDLE
)SmiHandler
,
145 case EFI_INTERRUPT_PENDING
:
147 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
148 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
150 if (HandlerType
!= NULL
) {
151 return EFI_INTERRUPT_PENDING
;
158 // If at least one of the handlers returns EFI_SUCCESS then the function will return
159 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
160 // additional handlers will be processed.
162 if (HandlerType
!= NULL
) {
166 SuccessReturn
= TRUE
;
169 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
171 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
172 // then the function will return EFI_SUCCESS.
174 SuccessReturn
= TRUE
;
177 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
179 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
180 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
186 // Unexpected status code returned.
194 Status
= EFI_SUCCESS
;
201 Registers a handler to execute within SMM.
203 @param Handler Handler service function pointer.
204 @param HandlerType Points to the handler type or NULL for root SMI handlers.
205 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
207 @retval EFI_SUCCESS Handler register success.
208 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
214 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler
,
215 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
216 OUT EFI_HANDLE
*DispatchHandle
219 SMI_HANDLER
*SmiHandler
;
223 if ((Handler
== NULL
) || (DispatchHandle
== NULL
)) {
224 return EFI_INVALID_PARAMETER
;
227 SmiHandler
= AllocateZeroPool (sizeof (SMI_HANDLER
));
228 if (SmiHandler
== NULL
) {
229 return EFI_OUT_OF_RESOURCES
;
232 SmiHandler
->Signature
= SMI_HANDLER_SIGNATURE
;
233 SmiHandler
->Handler
= Handler
;
234 SmiHandler
->CallerAddr
= (UINTN
)RETURN_ADDRESS (0);
236 if (HandlerType
== NULL
) {
238 // This is root SMI handler
240 SmiEntry
= &mRootSmiEntry
;
243 // None root SMI handler
245 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*)HandlerType
, TRUE
);
246 if (SmiEntry
== NULL
) {
247 return EFI_OUT_OF_RESOURCES
;
251 List
= &SmiEntry
->SmiHandlers
;
253 SmiHandler
->SmiEntry
= SmiEntry
;
254 InsertTailList (List
, &SmiHandler
->Link
);
256 *DispatchHandle
= (EFI_HANDLE
)SmiHandler
;
262 Unregister a handler in SMM.
264 @param DispatchHandle The handle that was specified when the handler was registered.
266 @retval EFI_SUCCESS Handler function was successfully unregistered.
267 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
272 SmiHandlerUnRegister (
273 IN EFI_HANDLE DispatchHandle
276 SMI_HANDLER
*SmiHandler
;
278 LIST_ENTRY
*EntryLink
;
279 LIST_ENTRY
*HandlerLink
;
281 if (DispatchHandle
== NULL
) {
282 return EFI_INVALID_PARAMETER
;
286 // Look for it in root SMI handlers
289 for ( HandlerLink
= GetFirstNode (&mRootSmiEntry
.SmiHandlers
)
290 ; !IsNull (&mRootSmiEntry
.SmiHandlers
, HandlerLink
) && ((EFI_HANDLE
)SmiHandler
!= DispatchHandle
)
291 ; HandlerLink
= GetNextNode (&mRootSmiEntry
.SmiHandlers
, HandlerLink
)
294 SmiHandler
= CR (HandlerLink
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
298 // Look for it in non-root SMI handlers
300 for ( EntryLink
= GetFirstNode (&mSmiEntryList
)
301 ; !IsNull (&mSmiEntryList
, EntryLink
) && ((EFI_HANDLE
)SmiHandler
!= DispatchHandle
)
302 ; EntryLink
= GetNextNode (&mSmiEntryList
, EntryLink
)
305 SmiEntry
= CR (EntryLink
, SMI_ENTRY
, AllEntries
, SMI_ENTRY_SIGNATURE
);
306 for ( HandlerLink
= GetFirstNode (&SmiEntry
->SmiHandlers
)
307 ; !IsNull (&SmiEntry
->SmiHandlers
, HandlerLink
) && ((EFI_HANDLE
)SmiHandler
!= DispatchHandle
)
308 ; HandlerLink
= GetNextNode (&SmiEntry
->SmiHandlers
, HandlerLink
)
311 SmiHandler
= CR (HandlerLink
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
315 if ((EFI_HANDLE
)SmiHandler
!= DispatchHandle
) {
316 return EFI_INVALID_PARAMETER
;
319 SmiEntry
= SmiHandler
->SmiEntry
;
321 RemoveEntryList (&SmiHandler
->Link
);
322 FreePool (SmiHandler
);
324 if (SmiEntry
== NULL
) {
326 // This is root SMI handler
331 if (IsListEmpty (&SmiEntry
->SmiHandlers
)) {
333 // No handler registered for this interrupt now, remove the SMI_ENTRY
335 RemoveEntryList (&SmiEntry
->AllEntries
);