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