TianoCore EDK2 master
Loading...
Searching...
No Matches
Smi.c
Go to the documentation of this file.
1
9#include "PiSmmCore.h"
10
11//
12// mSmiManageCallingDepth is used to track the depth of recursive calls of SmiManage.
13//
14UINTN mSmiManageCallingDepth = 0;
15
16LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);
17
18SMI_ENTRY mRootSmiEntry = {
19 SMI_ENTRY_SIGNATURE,
20 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries),
21 { 0 },
22 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.SmiHandlers),
23};
24
35EFIAPI
37 IN EFI_GUID *HandlerType,
38 IN BOOLEAN Create
39 )
40{
41 LIST_ENTRY *Link;
42 SMI_ENTRY *Item;
43 SMI_ENTRY *SmiEntry;
44
45 //
46 // Search the SMI entry list for the matching GUID
47 //
48 SmiEntry = NULL;
49 for (Link = mSmiEntryList.ForwardLink;
50 Link != &mSmiEntryList;
51 Link = Link->ForwardLink)
52 {
53 Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
54 if (CompareGuid (&Item->HandlerType, HandlerType)) {
55 //
56 // This is the SMI entry
57 //
58 SmiEntry = Item;
59 break;
60 }
61 }
62
63 //
64 // If the protocol entry was not found and Create is TRUE, then
65 // allocate a new entry
66 //
67 if ((SmiEntry == NULL) && Create) {
68 SmiEntry = AllocatePool (sizeof (SMI_ENTRY));
69 if (SmiEntry != NULL) {
70 //
71 // Initialize new SMI entry structure
72 //
73 SmiEntry->Signature = SMI_ENTRY_SIGNATURE;
74 CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);
75 InitializeListHead (&SmiEntry->SmiHandlers);
76
77 //
78 // Add it to SMI entry list
79 //
80 InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries);
81 }
82 }
83
84 return SmiEntry;
85}
86
97BOOLEAN
99 IN SMI_HANDLER *SmiHandler,
100 IN SMI_ENTRY *SmiEntry
101 )
102{
103 ASSERT (SmiHandler->ToRemove);
104 RemoveEntryList (&SmiHandler->Link);
105 FreePool (SmiHandler);
106
107 //
108 // Remove the SMI_ENTRY if all handlers have been removed.
109 //
110 if (SmiEntry != NULL) {
111 if (IsListEmpty (&SmiEntry->SmiHandlers)) {
112 RemoveEntryList (&SmiEntry->AllEntries);
113 FreePool (SmiEntry);
114 return TRUE;
115 }
116 }
117
118 return FALSE;
119}
120
136EFIAPI
138 IN CONST EFI_GUID *HandlerType,
139 IN CONST VOID *Context OPTIONAL,
140 IN OUT VOID *CommBuffer OPTIONAL,
141 IN OUT UINTN *CommBufferSize OPTIONAL
142 )
143{
144 LIST_ENTRY *Link;
145 LIST_ENTRY *Head;
146 LIST_ENTRY *EntryLink;
147 SMI_ENTRY *SmiEntry;
148 SMI_HANDLER *SmiHandler;
149 EFI_STATUS ReturnStatus;
150 BOOLEAN WillReturn;
151 EFI_STATUS Status;
152
154 mSmiManageCallingDepth++;
155 WillReturn = FALSE;
156 Status = EFI_NOT_FOUND;
157 ReturnStatus = Status;
158 if (HandlerType == NULL) {
159 //
160 // Root SMI handler
161 //
162 SmiEntry = &mRootSmiEntry;
163 } else {
164 //
165 // Non-root SMI handler
166 //
167 SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, FALSE);
168 if (SmiEntry == NULL) {
169 //
170 // There is no handler registered for this interrupt source
171 //
173 return Status;
174 }
175 }
176
177 Head = &SmiEntry->SmiHandlers;
178
179 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
180 SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
181
182 Status = SmiHandler->Handler (
183 (EFI_HANDLE)SmiHandler,
184 Context,
185 CommBuffer,
186 CommBufferSize
187 );
188
189 switch (Status) {
191 //
192 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
193 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
194 //
195 if (HandlerType != NULL) {
197 ReturnStatus = EFI_INTERRUPT_PENDING;
198 WillReturn = TRUE;
199 } else {
200 //
201 // If any other handler's result sets ReturnStatus as EFI_SUCCESS, the return status
202 // will be EFI_SUCCESS.
203 //
204 if (ReturnStatus != EFI_SUCCESS) {
205 ReturnStatus = Status;
206 }
207 }
208
209 break;
210
211 case EFI_SUCCESS:
212 //
213 // If at least one of the handlers returns EFI_SUCCESS then the function will return
214 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
215 // additional handlers will be processed.
216 //
217 if (HandlerType != NULL) {
219 WillReturn = TRUE;
220 }
221
222 ReturnStatus = EFI_SUCCESS;
223 break;
224
225 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
226 //
227 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
228 // then the function will return EFI_SUCCESS.
229 //
230 ReturnStatus = EFI_SUCCESS;
231 break;
232
233 case EFI_WARN_INTERRUPT_SOURCE_PENDING:
234 //
235 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
236 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
237 //
238 if (ReturnStatus != EFI_SUCCESS) {
239 ReturnStatus = Status;
240 }
241
242 break;
243
244 default:
245 //
246 // Unexpected status code returned.
247 //
248 ASSERT (FALSE);
249 break;
250 }
251
252 if (WillReturn) {
253 break;
254 }
255 }
256
257 ASSERT (mSmiManageCallingDepth > 0);
258 mSmiManageCallingDepth--;
259
260 //
261 // SmiHandlerUnRegister() calls from SMI handlers are deferred till this point.
262 // Before returned from SmiManage, delete the SmiHandler which is
263 // marked as ToRemove.
264 // Note that SmiManage can be called recursively.
265 //
266 if (mSmiManageCallingDepth == 0) {
267 //
268 // Go through all SmiHandler in root SMI handlers
269 //
270 for ( Link = GetFirstNode (&mRootSmiEntry.SmiHandlers)
271 ; !IsNull (&mRootSmiEntry.SmiHandlers, Link);
272 )
273 {
274 //
275 // SmiHandler might be removed in below, so cache the next link in Link
276 //
277 SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
278 Link = GetNextNode (&mRootSmiEntry.SmiHandlers, Link);
279 if (SmiHandler->ToRemove) {
280 //
281 // Remove SmiHandler if the ToRemove is set.
282 //
283 RemoveSmiHandler (SmiHandler, NULL);
284 }
285 }
286
287 //
288 // Go through all SmiHandler in non-root SMI handlers
289 //
290 for ( EntryLink = GetFirstNode (&mSmiEntryList)
291 ; !IsNull (&mSmiEntryList, EntryLink);
292 )
293 {
294 //
295 // SmiEntry might be removed in below, so cache the next link in EntryLink
296 //
297 SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
298 EntryLink = GetNextNode (&mSmiEntryList, EntryLink);
299 for ( Link = GetFirstNode (&SmiEntry->SmiHandlers)
300 ; !IsNull (&SmiEntry->SmiHandlers, Link);
301 )
302 {
303 //
304 // SmiHandler might be removed in below, so cache the next link in Link
305 //
306 SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
307 Link = GetNextNode (&SmiEntry->SmiHandlers, Link);
308 if (SmiHandler->ToRemove) {
309 if (RemoveSmiHandler (SmiHandler, SmiEntry)) {
310 break;
311 }
312 }
313 }
314 }
315 }
316
318 return ReturnStatus;
319}
320
333EFIAPI
335 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,
336 IN CONST EFI_GUID *HandlerType OPTIONAL,
337 OUT EFI_HANDLE *DispatchHandle
338 )
339{
340 SMI_HANDLER *SmiHandler;
341 SMI_ENTRY *SmiEntry;
342 LIST_ENTRY *List;
343
344 if ((Handler == NULL) || (DispatchHandle == NULL)) {
345 return EFI_INVALID_PARAMETER;
346 }
347
348 SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));
349 if (SmiHandler == NULL) {
350 return EFI_OUT_OF_RESOURCES;
351 }
352
353 SmiHandler->Signature = SMI_HANDLER_SIGNATURE;
354 SmiHandler->Handler = Handler;
355 SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0);
356 SmiHandler->ToRemove = FALSE;
357
358 if (HandlerType == NULL) {
359 //
360 // This is root SMI handler
361 //
362 SmiEntry = &mRootSmiEntry;
363 } else {
364 //
365 // None root SMI handler
366 //
367 SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *)HandlerType, TRUE);
368 if (SmiEntry == NULL) {
369 return EFI_OUT_OF_RESOURCES;
370 }
371 }
372
373 List = &SmiEntry->SmiHandlers;
374
375 SmiHandler->SmiEntry = SmiEntry;
376 InsertTailList (List, &SmiHandler->Link);
377
378 *DispatchHandle = (EFI_HANDLE)SmiHandler;
379
380 return EFI_SUCCESS;
381}
382
393EFIAPI
395 IN EFI_HANDLE DispatchHandle
396 )
397{
398 SMI_HANDLER *SmiHandler;
399 SMI_ENTRY *SmiEntry;
400 LIST_ENTRY *EntryLink;
401 LIST_ENTRY *HandlerLink;
402
403 if (DispatchHandle == NULL) {
404 return EFI_INVALID_PARAMETER;
405 }
406
407 //
408 // Look for it in root SMI handlers
409 //
410 SmiHandler = NULL;
411 for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers)
412 ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
413 ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink)
414 )
415 {
416 SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
417 }
418
419 //
420 // Look for it in non-root SMI handlers
421 //
422 for ( EntryLink = GetFirstNode (&mSmiEntryList)
423 ; !IsNull (&mSmiEntryList, EntryLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
424 ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink)
425 )
426 {
427 SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);
428 for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers)
429 ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && ((EFI_HANDLE)SmiHandler != DispatchHandle)
430 ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink)
431 )
432 {
433 SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);
434 }
435 }
436
437 if (SmiHandler == NULL) {
438 return EFI_INVALID_PARAMETER;
439 }
440
441 ASSERT ((EFI_HANDLE)SmiHandler == DispatchHandle);
442 SmiHandler->ToRemove = TRUE;
443
444 if (mSmiManageCallingDepth > 0) {
445 //
446 // This function is called from SmiManage()
447 // Do not delete or remove SmiHandler or SmiEntry now.
448 // SmiManage will handle it later
449 //
450 return EFI_SUCCESS;
451 }
452
453 SmiEntry = SmiHandler->SmiEntry;
454
455 //
456 // For root SMI handler, use NULL for SmiEntry
457 //
458 RemoveSmiHandler (SmiHandler, (SmiEntry == &mRootSmiEntry) ? NULL : SmiEntry);
459 return EFI_SUCCESS;
460}
UINT64 UINTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define RETURN_ADDRESS(L)
Definition: Base.h:1379
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define CR(Record, TYPE, Field, TestSignature)
Definition: DebugLib.h:659
#define PERF_FUNCTION_END()
#define PERF_FUNCTION_BEGIN()
#define EFI_INTERRUPT_PENDING
Definition: PiMultiPhase.h:73
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_STATUS EFIAPI SmiManage(IN CONST EFI_GUID *HandlerType, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL)
Definition: Smi.c:137
SMI_ENTRY *EFIAPI SmmCoreFindSmiEntry(IN EFI_GUID *HandlerType, IN BOOLEAN Create)
Definition: Smi.c:36
EFI_STATUS EFIAPI SmiHandlerUnRegister(IN EFI_HANDLE DispatchHandle)
Definition: Smi.c:394
BOOLEAN RemoveSmiHandler(IN SMI_HANDLER *SmiHandler, IN SMI_ENTRY *SmiEntry)
Definition: Smi.c:98
EFI_STATUS EFIAPI SmiHandlerRegister(IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, IN CONST EFI_GUID *HandlerType OPTIONAL, OUT EFI_HANDLE *DispatchHandle)
Definition: Smi.c:334
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
Definition: Base.h:213