4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PiSmmCore.h"
17 LIST_ENTRY mSmiEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList
);
19 SMI_ENTRY mRootSmiEntry
= {
21 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry
.AllEntries
),
23 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry
.SmiHandlers
),
27 Finds the SMI entry for the requested handler type.
29 @param HandlerType The type of the interrupt
30 @param Create Create a new entry if not found
38 IN EFI_GUID
*HandlerType
,
47 // Search the SMI entry list for the matching GUID
50 for (Link
= mSmiEntryList
.ForwardLink
;
51 Link
!= &mSmiEntryList
;
52 Link
= Link
->ForwardLink
) {
54 Item
= CR (Link
, SMI_ENTRY
, AllEntries
, SMI_ENTRY_SIGNATURE
);
55 if (CompareGuid (&Item
->HandlerType
, HandlerType
)) {
57 // This is the SMI entry
65 // If the protocol entry was not found and Create is TRUE, then
66 // allocate a new entry
68 if ((SmiEntry
== NULL
) && Create
) {
69 SmiEntry
= AllocatePool (sizeof(SMI_ENTRY
));
70 if (SmiEntry
!= NULL
) {
72 // Initialize new SMI entry structure
74 SmiEntry
->Signature
= SMI_ENTRY_SIGNATURE
;
75 CopyGuid ((VOID
*)&SmiEntry
->HandlerType
, HandlerType
);
76 InitializeListHead (&SmiEntry
->SmiHandlers
);
79 // Add it to SMI entry list
81 InsertTailList (&mSmiEntryList
, &SmiEntry
->AllEntries
);
88 Manage SMI of a particular type.
90 @param HandlerType Points to the handler type or NULL for root SMI handlers.
91 @param Context Points to an optional context buffer.
92 @param CommBuffer Points to the optional communication buffer.
93 @param CommBufferSize Points to the size of the optional communication buffer.
95 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
96 @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.
97 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
98 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
104 IN CONST EFI_GUID
*HandlerType
,
105 IN CONST VOID
*Context OPTIONAL
,
106 IN OUT VOID
*CommBuffer OPTIONAL
,
107 IN OUT UINTN
*CommBufferSize OPTIONAL
113 SMI_HANDLER
*SmiHandler
;
114 BOOLEAN SuccessReturn
;
117 Status
= EFI_NOT_FOUND
;
118 SuccessReturn
= FALSE
;
119 if (HandlerType
== NULL
) {
123 SmiEntry
= &mRootSmiEntry
;
126 // Non-root SMI handler
128 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, FALSE
);
129 if (SmiEntry
== NULL
) {
131 // There is no handler registered for this interrupt source
136 Head
= &SmiEntry
->SmiHandlers
;
138 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
139 SmiHandler
= CR (Link
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
141 Status
= SmiHandler
->Handler (
142 (EFI_HANDLE
) SmiHandler
,
149 case EFI_INTERRUPT_PENDING
:
151 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
152 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
154 if (HandlerType
!= NULL
) {
155 return EFI_INTERRUPT_PENDING
;
161 // If at least one of the handlers returns EFI_SUCCESS then the function will return
162 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
163 // additional handlers will be processed.
165 if (HandlerType
!= NULL
) {
168 SuccessReturn
= TRUE
;
171 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
173 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
174 // then the function will return EFI_SUCCESS.
176 SuccessReturn
= TRUE
;
179 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
181 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
182 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
188 // Unexpected status code returned.
196 Status
= EFI_SUCCESS
;
203 Registers a handler to execute within SMM.
205 @param Handler Handler service funtion pointer.
206 @param HandlerType Points to the handler type or NULL for root SMI handlers.
207 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
209 @retval EFI_SUCCESS Handler register success.
210 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
216 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler
,
217 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
218 OUT EFI_HANDLE
*DispatchHandle
221 SMI_HANDLER
*SmiHandler
;
225 if (Handler
== NULL
|| DispatchHandle
== NULL
) {
226 return EFI_INVALID_PARAMETER
;
229 SmiHandler
= AllocateZeroPool (sizeof (SMI_HANDLER
));
230 if (SmiHandler
== NULL
) {
231 return EFI_OUT_OF_RESOURCES
;
234 SmiHandler
->Signature
= SMI_HANDLER_SIGNATURE
;
235 SmiHandler
->Handler
= Handler
;
236 SmiHandler
->CallerAddr
= (UINTN
)RETURN_ADDRESS (0);
238 if (HandlerType
== NULL
) {
240 // This is root SMI handler
242 SmiEntry
= &mRootSmiEntry
;
245 // None root SMI handler
247 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, TRUE
);
248 if (SmiEntry
== NULL
) {
249 return EFI_OUT_OF_RESOURCES
;
252 List
= &SmiEntry
->SmiHandlers
;
254 SmiHandler
->SmiEntry
= SmiEntry
;
255 InsertTailList (List
, &SmiHandler
->Link
);
257 *DispatchHandle
= (EFI_HANDLE
) SmiHandler
;
263 Unregister a handler in SMM.
265 @param DispatchHandle The handle that was specified when the handler was registered.
267 @retval EFI_SUCCESS Handler function was successfully unregistered.
268 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
273 SmiHandlerUnRegister (
274 IN EFI_HANDLE DispatchHandle
277 SMI_HANDLER
*SmiHandler
;
280 SmiHandler
= (SMI_HANDLER
*) DispatchHandle
;
282 if (SmiHandler
== NULL
) {
283 return EFI_INVALID_PARAMETER
;
286 if (SmiHandler
->Signature
!= SMI_HANDLER_SIGNATURE
) {
287 return EFI_INVALID_PARAMETER
;
290 SmiEntry
= SmiHandler
->SmiEntry
;
292 RemoveEntryList (&SmiHandler
->Link
);
293 FreePool (SmiHandler
);
295 if (SmiEntry
== NULL
) {
297 // This is root SMI handler
302 if (IsListEmpty (&SmiEntry
->SmiHandlers
)) {
304 // No handler registered for this interrupt now, remove the SMI_ENTRY
306 RemoveEntryList (&SmiEntry
->AllEntries
);