]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
QuarkSocPkg/QncSmmDispatcher: Fix use after free issue
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Smm / DxeSmm / QncSmmDispatcher / QNCSmmCore.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2This driver is responsible for the registration of child drivers\r
3and the abstraction of the QNC SMI sources.\r
4\r
29f169d1 5Copyright (c) 2013-2016 Intel Corporation.\r
9b6bbcdb
MK
6\r
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15\r
16**/\r
17\r
18//\r
19// Include common header file for this module.\r
20//\r
21#include "CommonHeader.h"\r
22\r
23#include "QNCSmm.h"\r
24#include "QNCSmmHelpers.h"\r
25\r
26//\r
27// /////////////////////////////////////////////////////////////////////////////\r
28// MODULE / GLOBAL DATA\r
29//\r
30// Module variables used by the both the main dispatcher and the source dispatchers\r
31// Declared in QNCSmmSources.h\r
32//\r
33UINT32 mPciData;\r
34UINT32 mPciAddress;\r
35\r
36PRIVATE_DATA mPrivateData = { // for the structure\r
37 {\r
38 NULL\r
39 }, // CallbackDataBase linked list head\r
40 NULL, // Handler returned whan calling SmiHandlerRegister\r
41 NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces\r
42 { // protocol arrays\r
43 // elements within the array\r
44 //\r
45 {\r
46 PROTOCOL_SIGNATURE,\r
47 SxType,\r
48 &gEfiSmmSxDispatch2ProtocolGuid,\r
49 {\r
50 {\r
51 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
52 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
53 }\r
54 }\r
55 },\r
56 {\r
57 PROTOCOL_SIGNATURE,\r
58 SwType,\r
59 &gEfiSmmSwDispatch2ProtocolGuid,\r
60 {\r
61 {\r
62 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
63 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
64 (UINTN) MAXIMUM_SWI_VALUE\r
65 }\r
66 }\r
67 },\r
68 {\r
69 PROTOCOL_SIGNATURE,\r
70 GpiType,\r
71 &gEfiSmmGpiDispatch2ProtocolGuid,\r
72 {\r
73 {\r
74 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
75 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
76 (UINTN) 1\r
77 }\r
78 }\r
79 },\r
80 {\r
81 PROTOCOL_SIGNATURE,\r
82 QNCnType,\r
83 &gEfiSmmIchnDispatch2ProtocolGuid,\r
84 {\r
85 {\r
86 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
87 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
88 }\r
89 }\r
90 },\r
91 {\r
92 PROTOCOL_SIGNATURE,\r
93 PowerButtonType,\r
94 &gEfiSmmPowerButtonDispatch2ProtocolGuid,\r
95 {\r
96 {\r
97 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
98 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
99 }\r
100 }\r
101 },\r
102 {\r
103 PROTOCOL_SIGNATURE,\r
104 PeriodicTimerType,\r
105 &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,\r
106 {\r
107 {\r
108 (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
109 (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
110 (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval\r
111 }\r
112 }\r
113 },\r
114 }\r
115};\r
116\r
117CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = {\r
118 {\r
119 SxGetContext,\r
120 SxCmpContext,\r
121 NULL\r
122 },\r
123 {\r
124 SwGetContext,\r
125 SwCmpContext,\r
126 SwGetBuffer\r
127 },\r
128 {\r
129 NULL,\r
130 NULL,\r
131 NULL\r
132 },\r
133 {\r
134 NULL,\r
135 NULL,\r
136 NULL\r
137 },\r
138 {\r
139 NULL,\r
140 NULL,\r
141 NULL\r
142 },\r
143 {\r
144 PeriodicTimerGetContext,\r
145 PeriodicTimerCmpContext,\r
146 PeriodicTimerGetBuffer,\r
147 },\r
148};\r
149\r
150//\r
151// /////////////////////////////////////////////////////////////////////////////\r
152// PROTOTYPES\r
153//\r
154// Functions use only in this file\r
155//\r
156EFI_STATUS\r
157QNCSmmCoreDispatcher (\r
158 IN EFI_HANDLE DispatchHandle,\r
159 IN CONST VOID *Context, OPTIONAL\r
160 IN OUT VOID *CommBuffer, OPTIONAL\r
161 IN OUT UINTN *CommBufferSize OPTIONAL\r
162 );\r
163\r
164\r
165UINTN\r
166DevicePathSize (\r
167 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
168 );\r
169\r
170//\r
171// /////////////////////////////////////////////////////////////////////////////\r
172// FUNCTIONS\r
173//\r
174// Driver entry point\r
175//\r
176EFI_STATUS\r
177EFIAPI\r
178InitializeQNCSmmDispatcher (\r
179 IN EFI_HANDLE ImageHandle,\r
180 IN EFI_SYSTEM_TABLE *SystemTable\r
181 )\r
182/*++\r
183\r
184Routine Description:\r
185\r
186 Initializes the QNC SMM Dispatcher\r
187\r
188Arguments:\r
189\r
190 ImageHandle - Pointer to the loaded image protocol for this driver\r
191 SystemTable - Pointer to the EFI System Table\r
192\r
193Returns:\r
194 Status - EFI_SUCCESS\r
195\r
196--*/\r
197{\r
198 EFI_STATUS Status;\r
199\r
200 QNCSmmPublishDispatchProtocols ();\r
201\r
202 //\r
203 // Register a callback function to handle subsequent SMIs. This callback\r
204 // will be called by SmmCoreDispatcher.\r
205 //\r
206 Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);\r
207 ASSERT_EFI_ERROR (Status);\r
208\r
209 //\r
210 // Initialize Callback DataBase\r
211 //\r
212 InitializeListHead (&mPrivateData.CallbackDataBase);\r
213\r
214 //\r
215 // Enable SMIs on the QNC now that we have a callback\r
216 //\r
217 QNCSmmInitHardware ();\r
218\r
219 return EFI_SUCCESS;\r
220}\r
221\r
222EFI_STATUS\r
223SaveState (\r
224 VOID\r
225 )\r
226/*++\r
227\r
228Routine Description:\r
229\r
230 Save Index registers to avoid corrupting the foreground environment\r
231\r
232Arguments:\r
233 None\r
234\r
235Returns:\r
236 Status - EFI_SUCCESS\r
237\r
238--*/\r
239{\r
240 mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);\r
241 return EFI_SUCCESS;\r
242}\r
243\r
244EFI_STATUS\r
245RestoreState (\r
246 VOID\r
247 )\r
248/*++\r
249\r
250Routine Description:\r
251\r
252 Restore Index registers to avoid corrupting the foreground environment\r
253\r
254Arguments:\r
255 None\r
256\r
257Returns:\r
258 Status - EFI_SUCCESS\r
259\r
260--*/\r
261{\r
262 IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);\r
263 return EFI_SUCCESS;\r
264}\r
265\r
266EFI_STATUS\r
267SmiInputValueDuplicateCheck (\r
268 UINTN FedSwSmiInputValue\r
269 )\r
270/*++\r
271\r
272Routine Description:\r
273\r
274 Check the Fed SwSmiInputValue to see if there is a duplicated one in the database\r
275\r
276Arguments:\r
277 None\r
278\r
279Returns:\r
280 Status - EFI_SUCCESS, EFI_INVALID_PARAMETER\r
281\r
282--*/\r
283// GC_TODO: FedSwSmiInputValue - add argument and description to function comment\r
284{\r
285\r
286 DATABASE_RECORD *RecordInDb;\r
287 LIST_ENTRY *LinkInDb;\r
288\r
289 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
290 while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
291 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
292\r
293 if (RecordInDb->ProtocolType == SwType) {\r
294 if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {\r
295 return EFI_INVALID_PARAMETER;\r
296 }\r
297 }\r
298\r
299 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
300 }\r
301\r
302 return EFI_SUCCESS;\r
303}\r
304\r
305EFI_STATUS\r
306QNCSmmCoreRegister (\r
307 IN QNC_SMM_GENERIC_PROTOCOL *This,\r
308 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,\r
309 IN QNC_SMM_CONTEXT *RegisterContext,\r
310 OUT EFI_HANDLE *DispatchHandle\r
311 )\r
312/*++\r
313\r
314Routine Description:\r
315\r
316Arguments:\r
317\r
318Returns:\r
319\r
320--*/\r
321// GC_TODO: This - add argument and description to function comment\r
322// GC_TODO: DispatchFunction - add argument and description to function comment\r
323// GC_TODO: RegisterContext - add argument and description to function comment\r
324// GC_TODO: DispatchHandle - add argument and description to function comment\r
325// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
326// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
327// GC_TODO: EFI_SUCCESS - add return value to function comment\r
328// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
329{\r
330 EFI_STATUS Status;\r
331 DATABASE_RECORD *Record;\r
332 QNC_SMM_QUALIFIED_PROTOCOL *Qualified;\r
333 INTN Index;\r
334\r
335 //\r
336 // Check for invalid parameter\r
337 //\r
338 if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {\r
339 return EFI_INVALID_PARAMETER;\r
340 }\r
341\r
342 //\r
343 // Create database record and add to database\r
344 //\r
345 Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));\r
346 if (Record == NULL) {\r
347 return EFI_OUT_OF_RESOURCES;\r
348 }\r
349\r
350 //\r
351 // Gather information about the registration request\r
352 //\r
353 Record->Callback = DispatchFunction;\r
29f169d1
MK
354 Record->CallbackContext = RegisterContext;\r
355 CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));\r
9b6bbcdb
MK
356\r
357 Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);\r
358\r
359 Record->ProtocolType = Qualified->Type;\r
360\r
361 CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));\r
362 //\r
363 // Perform linked list housekeeping\r
364 //\r
365 Record->Signature = DATABASE_RECORD_SIGNATURE;\r
366\r
367 switch (Qualified->Type) {\r
368 //\r
369 // By the end of this switch statement, we'll know the\r
370 // source description the child is registering for\r
371 //\r
372 case SxType:\r
373 //\r
374 // Check the validity of Context Type and Phase\r
375 //\r
376 if ((Record->ChildContext.Sx.Type < SxS0) ||\r
377 (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||\r
378 (Record->ChildContext.Sx.Phase < SxEntry) ||\r
379 (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)\r
380 ) {\r
381 goto Error;\r
382 }\r
383\r
384 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
385 CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));\r
386 //\r
387 // use default clear source function\r
388 //\r
389 break;\r
390\r
391 case SwType:\r
392 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
393 //\r
394 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.\r
395 //\r
396 Status = EFI_NOT_FOUND;\r
397 for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {\r
398 Status = SmiInputValueDuplicateCheck (Index);\r
399 if (!EFI_ERROR (Status)) {\r
400 RegisterContext->Sw.SwSmiInputValue = Index;\r
401 break;\r
402 }\r
403 }\r
404 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
405 Status = gSmst->SmmFreePool (Record);\r
406 return EFI_OUT_OF_RESOURCES;\r
407 }\r
408 //\r
409 // Update ChildContext again as SwSmiInputValue has been changed\r
410 //\r
29f169d1 411 CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));\r
9b6bbcdb
MK
412 }\r
413\r
414 //\r
415 // Check the validity of Context Value\r
416 //\r
417 if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {\r
418 goto Error;\r
419 }\r
420\r
421 if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {\r
422 goto Error;\r
423 }\r
424\r
425 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
426 CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));\r
427 Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);\r
428 //\r
429 // use default clear source function\r
430 //\r
431 break;\r
432\r
433 case GpiType:\r
434\r
435 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
436 CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));\r
437 //\r
438 // use default clear source function\r
439 //\r
440 break;\r
441\r
442 case QNCnType:\r
443 //\r
444 // Check the validity of Context Type\r
445 //\r
446 if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {\r
447 goto Error;\r
448 }\r
449\r
450 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
451 CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));\r
452 Record->ClearSource = QNCSmmQNCnClearSource;\r
453 break;\r
454\r
455 case PeriodicTimerType:\r
456\r
457 Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));\r
458 if (EFI_ERROR (Status)) {\r
459 goto Error;\r
460 }\r
461\r
462 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
463 Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);\r
464 Record->ClearSource = QNCSmmPeriodicTimerClearSource;\r
465 break;\r
466\r
467 default:\r
468 goto Error;\r
469 break;\r
470 };\r
471\r
472 if (Record->ClearSource == NULL) {\r
473 //\r
474 // Clear the SMI associated w/ the source using the default function\r
475 //\r
476 QNCSmmClearSource (&Record->SrcDesc);\r
477 } else {\r
478 //\r
479 // This source requires special handling to clear\r
480 //\r
481 Record->ClearSource (&Record->SrcDesc);\r
482 }\r
483\r
484 QNCSmmEnableSource (&Record->SrcDesc);\r
485\r
486 //\r
487 // Child's handle will be the address linked list link in the record\r
488 //\r
489 *DispatchHandle = (EFI_HANDLE) (&Record->Link);\r
490\r
491 return EFI_SUCCESS;\r
492\r
493Error:\r
494 FreePool (Record);\r
495 //\r
496 // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));\r
497 //\r
498 return EFI_INVALID_PARAMETER;\r
499}\r
500\r
501EFI_STATUS\r
502QNCSmmCoreUnRegister (\r
503 IN QNC_SMM_GENERIC_PROTOCOL *This,\r
504 IN EFI_HANDLE DispatchHandle\r
505 )\r
506/*++\r
507\r
508Routine Description:\r
509\r
510Arguments:\r
511\r
512Returns:\r
513\r
514--*/\r
515// GC_TODO: This - add argument and description to function comment\r
516// GC_TODO: DispatchHandle - add argument and description to function comment\r
517// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
518// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
519// GC_TODO: EFI_SUCCESS - add return value to function comment\r
520{\r
521 BOOLEAN SafeToDisable;\r
522 DATABASE_RECORD *RecordToDelete;\r
523 DATABASE_RECORD *RecordInDb;\r
524 LIST_ENTRY *LinkInDb;\r
525\r
526 if (DispatchHandle == NULL) {\r
527 return EFI_INVALID_PARAMETER;\r
528 }\r
529\r
530 if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {\r
531 return EFI_INVALID_PARAMETER;\r
532 }\r
533\r
534 RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);\r
535\r
536 RemoveEntryList (&RecordToDelete->Link);\r
537 RecordToDelete->Signature = 0;\r
538\r
539 //\r
540 // See if we can disable the source, reserved for future use since this might\r
541 // not be the only criteria to disable\r
542 //\r
543 SafeToDisable = TRUE;\r
544 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
545 while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
546 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
547 if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {\r
548 SafeToDisable = FALSE;\r
549 break;\r
550 }\r
551 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
552 }\r
553 if (SafeToDisable) {\r
554 QNCSmmDisableSource( &RecordToDelete->SrcDesc );\r
555}\r
556\r
557 FreePool (RecordToDelete);\r
558\r
559 return EFI_SUCCESS;\r
560}\r
561\r
562/**\r
563 This function is the main entry point for an SMM handler dispatch\r
564 or communicate-based callback.\r
565\r
566 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
567 @param RegisterContext Points to an optional handler context which was specified when the handler was registered.\r
568 @param CommBuffer A pointer to a collection of data in memory that will\r
569 be conveyed from a non-SMM environment into an SMM environment.\r
570 @param CommBufferSize The size of the CommBuffer.\r
571\r
572 @return Status Code\r
573\r
574**/\r
575EFI_STATUS\r
576QNCSmmCoreDispatcher (\r
577 IN EFI_HANDLE DispatchHandle,\r
578 IN CONST VOID *RegisterContext,\r
579 IN OUT VOID *CommBuffer,\r
580 IN OUT UINTN *CommBufferSize\r
581 )\r
582{\r
583 //\r
584 // Used to prevent infinite loops\r
585 //\r
586 UINTN EscapeCount;\r
587\r
588 BOOLEAN ContextsMatch;\r
589 BOOLEAN ResetListSearch;\r
590 BOOLEAN EosSet;\r
591 BOOLEAN SxChildWasDispatched;\r
592 BOOLEAN ChildWasDispatched;\r
593\r
594 DATABASE_RECORD *RecordInDb;\r
5f82e02a 595 DATABASE_RECORD ActiveRecordInDb;\r
9b6bbcdb
MK
596 LIST_ENTRY *LinkInDb;\r
597 DATABASE_RECORD *RecordToExhaust;\r
598 LIST_ENTRY *LinkToExhaust;\r
599\r
600 QNC_SMM_CONTEXT Context;\r
601 VOID *CommunicationBuffer;\r
602 UINTN BufferSize;\r
603\r
604 EFI_STATUS Status;\r
605 UINT32 NewValue;\r
606\r
607 QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;\r
608\r
609 EscapeCount = 100;\r
610 ContextsMatch = FALSE;\r
611 ResetListSearch = FALSE;\r
612 EosSet = FALSE;\r
613 SxChildWasDispatched = FALSE;\r
614 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
615 ChildWasDispatched = FALSE;\r
616\r
5f82e02a
MK
617 //\r
618 // Mark all child handlers as not processed\r
619 //\r
620 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
621 while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
622 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
623 RecordInDb->Processed = FALSE;\r
624 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);\r
625 }\r
626\r
9b6bbcdb
MK
627 //\r
628 // Preserve Index registers\r
629 //\r
630 SaveState ();\r
631\r
632 if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {\r
633 //\r
634 // We have children registered w/ us -- continue\r
635 //\r
636 while ((!EosSet) && (EscapeCount > 0)) {\r
637 EscapeCount--;\r
638\r
639 //\r
640 // Reset this flag in order to be able to process multiple SMI Sources in one loop.\r
641 //\r
642 ResetListSearch = FALSE;\r
643\r
644 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
645\r
646 while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {\r
647 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
5f82e02a
MK
648 //\r
649 // Make a copy of the record that contains an active SMI source,\r
650 // because un-register maybe invoked in callback function and\r
651 // RecordInDb maybe released\r
652 //\r
653 CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb));\r
9b6bbcdb
MK
654\r
655 //\r
656 // look for the first active source\r
657 //\r
658 if (!SourceIsActive (&RecordInDb->SrcDesc)) {\r
659 //\r
660 // Didn't find the source yet, keep looking\r
661 //\r
662 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
663\r
664 } else {\r
665 //\r
666 // We found a source. If this is a sleep type, we have to go to\r
667 // appropriate sleep state anyway.No matter there is sleep child or not\r
668 //\r
669 if (RecordInDb->ProtocolType == SxType) {\r
670 SxChildWasDispatched = TRUE;\r
671 }\r
672 //\r
673 // "cache" the source description and don't query I/O anymore\r
674 //\r
675 CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));\r
676 LinkToExhaust = LinkInDb;\r
677\r
678 //\r
679 // exhaust the rest of the queue looking for the same source\r
680 //\r
681 while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {\r
682 RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);\r
5f82e02a
MK
683 LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust);\r
684 if (RecordToExhaust->Processed) {\r
685 //\r
686 // Record has already been processed. Continue with next child handler.\r
687 //\r
688 continue;\r
689 }\r
9b6bbcdb
MK
690\r
691 if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {\r
692 //\r
693 // These source descriptions are equal, so this callback should be\r
694 // dispatched.\r
695 //\r
696 if (RecordToExhaust->ContextFunctions.GetContext != NULL) {\r
697 //\r
698 // This child requires that we get a calling context from\r
699 // hardware and compare that context to the one supplied\r
700 // by the child.\r
701 //\r
702 ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);\r
703\r
704 //\r
705 // Make sure contexts match before dispatching event to child\r
706 //\r
707 RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);\r
708 ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);\r
709\r
710 } else {\r
711 //\r
712 // This child doesn't require any more calling context beyond what\r
713 // it supplied in registration. Simply pass back what it gave us.\r
714 //\r
715 ASSERT (RecordToExhaust->Callback != NULL);\r
9b6bbcdb
MK
716 ContextsMatch = TRUE;\r
717 }\r
718\r
5f82e02a
MK
719 //\r
720 // Mark this child handler so it will not be processed again\r
721 //\r
722 RecordToExhaust->Processed = TRUE;\r
723\r
9b6bbcdb
MK
724 if (ContextsMatch) {\r
725\r
726 if (RecordToExhaust->BufferSize != 0) {\r
727 ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);\r
728\r
729 RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);\r
730\r
731 CommunicationBuffer = &RecordToExhaust->CommBuffer;\r
732 BufferSize = RecordToExhaust->BufferSize;\r
733 } else {\r
734 CommunicationBuffer = NULL;\r
735 BufferSize = 0;\r
736 }\r
737\r
738 ASSERT (RecordToExhaust->Callback != NULL);\r
739\r
740 RecordToExhaust->Callback (\r
741 (EFI_HANDLE) & RecordToExhaust->Link,\r
29f169d1 742 RecordToExhaust->CallbackContext,\r
9b6bbcdb
MK
743 CommunicationBuffer,\r
744 &BufferSize\r
745 );\r
746\r
747 ChildWasDispatched = TRUE;\r
748 if (RecordToExhaust->ProtocolType == SxType) {\r
749 SxChildWasDispatched = TRUE;\r
750 }\r
751 }\r
5f82e02a
MK
752 //\r
753 // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb\r
754 // Restart processing of SMI handlers from the begining of the linked list because the\r
755 // state of the linked listed may have been modified due to unregister actions in the Callback.\r
756 //\r
757 LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase);\r
9b6bbcdb 758 }\r
9b6bbcdb
MK
759 }\r
760\r
761 if (RecordInDb->ClearSource == NULL) {\r
762 //\r
763 // Clear the SMI associated w/ the source using the default function\r
764 //\r
765 QNCSmmClearSource (&ActiveSource);\r
766 } else {\r
767 //\r
768 // This source requires special handling to clear\r
769 //\r
5f82e02a 770 ActiveRecordInDb.ClearSource (&ActiveSource);\r
9b6bbcdb
MK
771 }\r
772\r
773 if (ChildWasDispatched) {\r
774 //\r
775 // The interrupt was handled and quiesced\r
776 //\r
777 Status = EFI_SUCCESS;\r
778 } else {\r
779 //\r
780 // The interrupt was not handled but quiesced\r
781 //\r
782 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
783 }\r
784\r
785 //\r
786 // Queue is empty, reset the search\r
787 //\r
788 ResetListSearch = TRUE;\r
789\r
790 }\r
791 }\r
792 EosSet = QNCSmmSetAndCheckEos ();\r
793 }\r
794 }\r
795 //\r
796 // If you arrive here, there are two possible reasons:\r
797 // (1) you've got problems with clearing the SMI status bits in the\r
798 // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the\r
799 // EOS bit. If this happens too many times, the loop exits.\r
800 // (2) there was a SMM communicate for callback messages that was received prior\r
801 // to this driver.\r
802 // If there is an asynchronous SMI that occurs while processing the Callback, let\r
803 // all of the drivers (including this one) have an opportunity to scan for the SMI\r
804 // and handle it.\r
805 // If not, we don't want to exit and have the foreground app. clear EOS without letting\r
806 // these other sources get serviced.\r
807 //\r
808 ASSERT (EscapeCount > 0);\r
809\r
810 //\r
811 // Restore Index registers\r
812 //\r
813 RestoreState ();\r
814\r
815 if (SxChildWasDispatched) {\r
816 //\r
817 // A child of the SmmSxDispatch protocol was dispatched during this call;\r
818 // put the system to sleep.\r
819 //\r
820 QNCSmmSxGoToSleep ();\r
821 }\r
822\r
823 //\r
824 // Ensure that SMI signal pin indicator is clear at the end of SMM handling.\r
825 //\r
826 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);\r
827 NewValue &= ~(HLEGACY_SMI_PIN_VALUE);\r
828 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);\r
829\r
830 return Status;\r
831}\r