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