4 Copyright (c) 2009 - 2010, 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_SUCCESS 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_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced.
115 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED 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 if (HandlerType
== NULL
) {
138 Status
= EFI_WARN_INTERRUPT_SOURCE_PENDING
;
140 Head
= &mRootSmiHandlerList
;
141 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
142 SmiHandler
= CR (Link
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
144 Status
= SmiHandler
->Handler (
145 (EFI_HANDLE
) SmiHandler
,
150 if (Status
== EFI_SUCCESS
|| Status
== EFI_INTERRUPT_PENDING
) {
158 // Non-root SMI handler
160 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, FALSE
);
161 if (SmiEntry
== NULL
) {
163 // There is no handler registered for this interrupt source
165 return EFI_WARN_INTERRUPT_SOURCE_PENDING
;
168 InterruptQuiesced
= FALSE
;
169 Head
= &SmiEntry
->SmiHandlers
;
170 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
171 SmiHandler
= CR (Link
, SMI_HANDLER
, Link
, SMI_HANDLER_SIGNATURE
);
173 Status
= SmiHandler
->Handler (
174 (EFI_HANDLE
) SmiHandler
,
181 case EFI_INTERRUPT_PENDING
:
183 // If a handler returns EFI_INTERRUPT_PENDING, the interrupt could not be
184 // quiesced, then no additional handlers will be processed,
185 // and EFI_INTERRUPT_PENDING will be returned
187 return EFI_INTERRUPT_PENDING
;
191 // If handler return EFI_SUCCESS, the interrupt was handled and quiesced,
192 // no other handlers should still be called,
193 // and EFI_WARN_INTERRUPT_SOURCE_QUIESCED will be returned
195 return EFI_WARN_INTERRUPT_SOURCE_QUIESCED
;
197 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED
:
199 // If at least one of the handlers report EFI_WARN_INTERRUPT_SOURCE_QUIESCED,
200 // then this function will return EFI_WARN_INTERRUPT_SOURCE_QUIESCED
202 InterruptQuiesced
= TRUE
;
210 if (InterruptQuiesced
) {
211 Status
= EFI_WARN_INTERRUPT_SOURCE_QUIESCED
;
214 // If no handler report EFI_WARN_INTERRUPT_SOURCE_QUIESCED, then this
215 // function will return EFI_INTERRUPT_PENDING
217 Status
= EFI_INTERRUPT_PENDING
;
223 Registers a handler to execute within SMM.
225 @param Handler Handler service funtion pointer.
226 @param HandlerType Points to the handler type or NULL for root SMI handlers.
227 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
229 @retval EFI_SUCCESS Handler register success.
230 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
236 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler
,
237 IN CONST EFI_GUID
*HandlerType OPTIONAL
,
238 OUT EFI_HANDLE
*DispatchHandle
241 SMI_HANDLER
*SmiHandler
;
245 if (Handler
== NULL
|| DispatchHandle
== NULL
) {
246 return EFI_INVALID_PARAMETER
;
249 SmiHandler
= AllocateZeroPool (sizeof (SMI_HANDLER
));
250 if (SmiHandler
== NULL
) {
251 return EFI_OUT_OF_RESOURCES
;
254 SmiHandler
->Signature
= SMI_HANDLER_SIGNATURE
;
255 SmiHandler
->Handler
= Handler
;
257 if (HandlerType
== NULL
) {
259 // This is root SMI handler
262 List
= &mRootSmiHandlerList
;
265 // None root SMI handler
267 SmiEntry
= SmmCoreFindSmiEntry ((EFI_GUID
*) HandlerType
, TRUE
);
268 if (SmiEntry
== NULL
) {
269 return EFI_OUT_OF_RESOURCES
;
272 List
= &SmiEntry
->SmiHandlers
;
275 SmiHandler
->SmiEntry
= SmiEntry
;
276 InsertTailList (List
, &SmiHandler
->Link
);
278 *DispatchHandle
= (EFI_HANDLE
) SmiHandler
;
284 Unregister a handler in SMM.
286 @param DispatchHandle The handle that was specified when the handler was registered.
288 @retval EFI_SUCCESS Handler function was successfully unregistered.
289 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
294 SmiHandlerUnRegister (
295 IN EFI_HANDLE DispatchHandle
298 SMI_HANDLER
*SmiHandler
;
301 SmiHandler
= (SMI_HANDLER
*) DispatchHandle
;
303 if (SmiHandler
== NULL
) {
304 return EFI_INVALID_PARAMETER
;
307 if (SmiHandler
->Signature
!= SMI_HANDLER_SIGNATURE
) {
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
);