4 Copyright (c) 2009 - 2012, 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 InterruptQuiesced
;
134 Status
= EFI_NOT_FOUND
;
135 InterruptQuiesced
= 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 then no additional handlers
171 // will be processed and EFI_INTERRUPT_PENDING will be returned.
173 if (HandlerType
!= NULL
) {
174 return EFI_INTERRUPT_PENDING
;
180 // If a handler returns EFI_SUCCESS then no additional handlers will be processed.
181 // then the function will return EFI_SUCCESS.
183 if (HandlerType
!= NULL
) {
188 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
190 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
191 // then the function will return EFI_SUCCESS.
193 InterruptQuiesced
= TRUE
;
196 case EFI_WARN_INTERRUPT_SOURCE_PENDING
:
198 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
199 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
205 // Unexpected status code returned.
212 if (InterruptQuiesced
) {
213 Status
= EFI_SUCCESS
;
220 Registers a handler to execute within SMM.
222 @param Handler Handler service funtion pointer.
223 @param HandlerType Points to the handler type or NULL for root SMI handlers.
224 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
226 @retval EFI_SUCCESS Handler register success.
227 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
233 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler
,
234 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
235 OUT EFI_HANDLE
*DispatchHandle
238 SMI_HANDLER
*SmiHandler
;
242 if (Handler
== NULL
|| DispatchHandle
== NULL
) {
243 return EFI_INVALID_PARAMETER
;
246 SmiHandler
= AllocateZeroPool (sizeof (SMI_HANDLER
));
247 if (SmiHandler
== NULL
) {
248 return EFI_OUT_OF_RESOURCES
;
251 SmiHandler
->Signature
= SMI_HANDLER_SIGNATURE
;
252 SmiHandler
->Handler
= Handler
;
254 if (HandlerType
== NULL
) {
256 // This is root SMI handler
259 List
= &mRootSmiHandlerList
;
262 // None root SMI handler
264 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, TRUE
);
265 if (SmiEntry
== NULL
) {
266 return EFI_OUT_OF_RESOURCES
;
269 List
= &SmiEntry
->SmiHandlers
;
272 SmiHandler
->SmiEntry
= SmiEntry
;
273 InsertTailList (List
, &SmiHandler
->Link
);
275 *DispatchHandle
= (EFI_HANDLE
) SmiHandler
;
281 Unregister a handler in SMM.
283 @param DispatchHandle The handle that was specified when the handler was registered.
285 @retval EFI_SUCCESS Handler function was successfully unregistered.
286 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
291 SmiHandlerUnRegister (
292 IN EFI_HANDLE DispatchHandle
295 SMI_HANDLER
*SmiHandler
;
298 SmiHandler
= (SMI_HANDLER
*) DispatchHandle
;
300 if (SmiHandler
== NULL
) {
301 return EFI_INVALID_PARAMETER
;
304 if (SmiHandler
->Signature
!= SMI_HANDLER_SIGNATURE
) {
305 return EFI_INVALID_PARAMETER
;
308 SmiEntry
= SmiHandler
->SmiEntry
;
310 RemoveEntryList (&SmiHandler
->Link
);
311 FreePool (SmiHandler
);
313 if (SmiEntry
== NULL
) {
315 // This is root SMI handler
320 if (IsListEmpty (&SmiEntry
->SmiHandlers
)) {
322 // No handler registered for this interrupt now, remove the SMI_ENTRY
324 RemoveEntryList (&SmiEntry
->AllEntries
);