4 Copyright (c) 2009 - 2013, 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"
18 // SMM_HANDLER - used for each SMM handler
21 #define SMI_ENTRY_SIGNATURE SIGNATURE_32('s','m','i','e')
25 LIST_ENTRY AllEntries
; // All entries
27 EFI_GUID HandlerType
; // Type of interrupt
28 LIST_ENTRY SmiHandlers
; // All handlers
31 #define SMI_HANDLER_SIGNATURE SIGNATURE_32('s','m','i','h')
35 LIST_ENTRY Link
; // Link on SMI_ENTRY.SmiHandlers
36 EFI_SMM_HANDLER_ENTRY_POINT2 Handler
; // The smm handler's entry point
40 LIST_ENTRY mRootSmiHandlerList
= INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiHandlerList
);
41 LIST_ENTRY mSmiEntryList
= INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList
);
44 Finds the SMI entry for the requested handler type.
46 @param HandlerType The type of the interrupt
47 @param Create Create a new entry if not found
55 IN EFI_GUID
*HandlerType
,
64 // Search the SMI entry list for the matching GUID
67 for (Link
= mSmiEntryList
.ForwardLink
;
68 Link
!= &mSmiEntryList
;
69 Link
= Link
->ForwardLink
) {
71 Item
= CR (Link
, SMI_ENTRY
, AllEntries
, SMI_ENTRY_SIGNATURE
);
72 if (CompareGuid (&Item
->HandlerType
, HandlerType
)) {
74 // This is the SMI entry
82 // If the protocol entry was not found and Create is TRUE, then
83 // allocate a new entry
85 if ((SmiEntry
== NULL
) && Create
) {
86 SmiEntry
= AllocatePool (sizeof(SMI_ENTRY
));
87 if (SmiEntry
!= NULL
) {
89 // Initialize new SMI entry structure
91 SmiEntry
->Signature
= SMI_ENTRY_SIGNATURE
;
92 CopyGuid ((VOID
*)&SmiEntry
->HandlerType
, HandlerType
);
93 InitializeListHead (&SmiEntry
->SmiHandlers
);
96 // Add it to SMI entry list
98 InsertTailList (&mSmiEntryList
, &SmiEntry
->AllEntries
);
105 Manage SMI of a particular type.
107 @param HandlerType Points to the handler type or NULL for root SMI 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 SMI 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 SMI_HANDLER
*SmiHandler
;
131 BOOLEAN SuccessReturn
;
134 Status
= EFI_NOT_FOUND
;
135 SuccessReturn
= FALSE
;
136 if (HandlerType
== NULL
) {
141 Head
= &mRootSmiHandlerList
;
144 // Non-root SMI handler
146 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, FALSE
);
147 if (SmiEntry
== NULL
) {
149 // There is no handler registered for this interrupt source
154 Head
= &SmiEntry
->SmiHandlers
;
157 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
158 SmiHandler
= CR (Link
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
160 Status
= SmiHandler
->Handler (
161 (EFI_HANDLE
) SmiHandler
,
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
;
180 // If at least one of the handlers returns EFI_SUCCESS then the function will return
181 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
182 // additional handlers will be processed.
184 if (HandlerType
!= NULL
) {
187 SuccessReturn
= TRUE
;
190 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
192 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
193 // then the function will return EFI_SUCCESS.
195 SuccessReturn
= TRUE
;
198 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
200 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
201 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
207 // Unexpected status code returned.
215 Status
= EFI_SUCCESS
;
222 Registers a handler to execute within SMM.
224 @param Handler Handler service funtion pointer.
225 @param HandlerType Points to the handler type or NULL for root SMI handlers.
226 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
228 @retval EFI_SUCCESS Handler register success.
229 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
235 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler
,
236 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
237 OUT EFI_HANDLE
*DispatchHandle
240 SMI_HANDLER
*SmiHandler
;
244 if (Handler
== NULL
|| DispatchHandle
== NULL
) {
245 return EFI_INVALID_PARAMETER
;
248 SmiHandler
= AllocateZeroPool (sizeof (SMI_HANDLER
));
249 if (SmiHandler
== NULL
) {
250 return EFI_OUT_OF_RESOURCES
;
253 SmiHandler
->Signature
= SMI_HANDLER_SIGNATURE
;
254 SmiHandler
->Handler
= Handler
;
256 if (HandlerType
== NULL
) {
258 // This is root SMI handler
261 List
= &mRootSmiHandlerList
;
264 // None root SMI handler
266 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, TRUE
);
267 if (SmiEntry
== NULL
) {
268 return EFI_OUT_OF_RESOURCES
;
271 List
= &SmiEntry
->SmiHandlers
;
274 SmiHandler
->SmiEntry
= SmiEntry
;
275 InsertTailList (List
, &SmiHandler
->Link
);
277 *DispatchHandle
= (EFI_HANDLE
) SmiHandler
;
283 Unregister a handler in SMM.
285 @param DispatchHandle The handle that was specified when the handler was registered.
287 @retval EFI_SUCCESS Handler function was successfully unregistered.
288 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
293 SmiHandlerUnRegister (
294 IN EFI_HANDLE DispatchHandle
297 SMI_HANDLER
*SmiHandler
;
300 SmiHandler
= (SMI_HANDLER
*) DispatchHandle
;
302 if (SmiHandler
== NULL
) {
303 return EFI_INVALID_PARAMETER
;
306 if (SmiHandler
->Signature
!= SMI_HANDLER_SIGNATURE
) {
307 return EFI_INVALID_PARAMETER
;
310 SmiEntry
= SmiHandler
->SmiEntry
;
312 RemoveEntryList (&SmiHandler
->Link
);
313 FreePool (SmiHandler
);
315 if (SmiEntry
== NULL
) {
317 // This is root SMI handler
322 if (IsListEmpty (&SmiEntry
->SmiHandlers
)) {
324 // No handler registered for this interrupt now, remove the SMI_ENTRY
326 RemoveEntryList (&SmiEntry
->AllEntries
);