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-2015 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->ChildContext = *RegisterContext; 355 356 Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); 357 358 Record->ProtocolType = Qualified->Type; 359 360 CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions)); 361 // 362 // Perform linked list housekeeping 363 // 364 Record->Signature = DATABASE_RECORD_SIGNATURE; 365 366 switch (Qualified->Type) { 367 // 368 // By the end of this switch statement, we'll know the 369 // source description the child is registering for 370 // 371 case SxType: 372 // 373 // Check the validity of Context Type and Phase 374 // 375 if ((Record->ChildContext.Sx.Type < SxS0) || 376 (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) || 377 (Record->ChildContext.Sx.Phase < SxEntry) || 378 (Record->ChildContext.Sx.Phase >= EfiMaximumPhase) 379 ) { 380 goto Error; 381 } 382 383 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); 384 CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc)); 385 // 386 // use default clear source function 387 // 388 break; 389 390 case SwType: 391 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) { 392 // 393 // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure. 394 // 395 Status = EFI_NOT_FOUND; 396 for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) { 397 Status = SmiInputValueDuplicateCheck (Index); 398 if (!EFI_ERROR (Status)) { 399 RegisterContext->Sw.SwSmiInputValue = Index; 400 break; 401 } 402 } 403 if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) { 404 Status = gSmst->SmmFreePool (Record); 405 return EFI_OUT_OF_RESOURCES; 406 } 407 // 408 // Update ChildContext again as SwSmiInputValue has been changed 409 // 410 Record->ChildContext = *RegisterContext; 411 } 412 413 // 414 // Check the validity of Context Value 415 // 416 if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) { 417 goto Error; 418 } 419 420 if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) { 421 goto Error; 422 } 423 424 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); 425 CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc)); 426 Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT); 427 // 428 // use default clear source function 429 // 430 break; 431 432 case GpiType: 433 434 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); 435 CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc)); 436 // 437 // use default clear source function 438 // 439 break; 440 441 case QNCnType: 442 // 443 // Check the validity of Context Type 444 // 445 if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) { 446 goto Error; 447 } 448 449 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); 450 CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc)); 451 Record->ClearSource = QNCSmmQNCnClearSource; 452 break; 453 454 case PeriodicTimerType: 455 456 Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc)); 457 if (EFI_ERROR (Status)) { 458 goto Error; 459 } 460 461 InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); 462 Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); 463 Record->ClearSource = QNCSmmPeriodicTimerClearSource; 464 break; 465 466 default: 467 goto Error; 468 break; 469 }; 470 471 if (Record->ClearSource == NULL) { 472 // 473 // Clear the SMI associated w/ the source using the default function 474 // 475 QNCSmmClearSource (&Record->SrcDesc); 476 } else { 477 // 478 // This source requires special handling to clear 479 // 480 Record->ClearSource (&Record->SrcDesc); 481 } 482 483 QNCSmmEnableSource (&Record->SrcDesc); 484 485 // 486 // Child's handle will be the address linked list link in the record 487 // 488 *DispatchHandle = (EFI_HANDLE) (&Record->Link); 489 490 return EFI_SUCCESS; 491 492 Error: 493 FreePool (Record); 494 // 495 // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status )); 496 // 497 return EFI_INVALID_PARAMETER; 498 } 499 500 EFI_STATUS 501 QNCSmmCoreUnRegister ( 502 IN QNC_SMM_GENERIC_PROTOCOL *This, 503 IN EFI_HANDLE DispatchHandle 504 ) 505 /*++ 506 507 Routine Description: 508 509 Arguments: 510 511 Returns: 512 513 --*/ 514 // GC_TODO: This - add argument and description to function comment 515 // GC_TODO: DispatchHandle - add argument and description to function comment 516 // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment 517 // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment 518 // GC_TODO: EFI_SUCCESS - add return value to function comment 519 { 520 BOOLEAN SafeToDisable; 521 DATABASE_RECORD *RecordToDelete; 522 DATABASE_RECORD *RecordInDb; 523 LIST_ENTRY *LinkInDb; 524 525 if (DispatchHandle == NULL) { 526 return EFI_INVALID_PARAMETER; 527 } 528 529 if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) { 530 return EFI_INVALID_PARAMETER; 531 } 532 533 RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); 534 535 RemoveEntryList (&RecordToDelete->Link); 536 RecordToDelete->Signature = 0; 537 538 // 539 // See if we can disable the source, reserved for future use since this might 540 // not be the only criteria to disable 541 // 542 SafeToDisable = TRUE; 543 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); 544 while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { 545 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); 546 if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) { 547 SafeToDisable = FALSE; 548 break; 549 } 550 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); 551 } 552 if (SafeToDisable) { 553 QNCSmmDisableSource( &RecordToDelete->SrcDesc ); 554 } 555 556 FreePool (RecordToDelete); 557 558 return EFI_SUCCESS; 559 } 560 561 /** 562 This function is the main entry point for an SMM handler dispatch 563 or communicate-based callback. 564 565 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). 566 @param RegisterContext Points to an optional handler context which was specified when the handler was registered. 567 @param CommBuffer A pointer to a collection of data in memory that will 568 be conveyed from a non-SMM environment into an SMM environment. 569 @param CommBufferSize The size of the CommBuffer. 570 571 @return Status Code 572 573 **/ 574 EFI_STATUS 575 QNCSmmCoreDispatcher ( 576 IN EFI_HANDLE DispatchHandle, 577 IN CONST VOID *RegisterContext, 578 IN OUT VOID *CommBuffer, 579 IN OUT UINTN *CommBufferSize 580 ) 581 { 582 // 583 // Used to prevent infinite loops 584 // 585 UINTN EscapeCount; 586 587 BOOLEAN ContextsMatch; 588 BOOLEAN ResetListSearch; 589 BOOLEAN EosSet; 590 BOOLEAN SxChildWasDispatched; 591 BOOLEAN ChildWasDispatched; 592 593 DATABASE_RECORD *RecordInDb; 594 LIST_ENTRY *LinkInDb; 595 DATABASE_RECORD *RecordToExhaust; 596 LIST_ENTRY *LinkToExhaust; 597 598 QNC_SMM_CONTEXT Context; 599 VOID *CommunicationBuffer; 600 UINTN BufferSize; 601 602 EFI_STATUS Status; 603 UINT32 NewValue; 604 605 QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER; 606 607 EscapeCount = 100; 608 ContextsMatch = FALSE; 609 ResetListSearch = FALSE; 610 EosSet = FALSE; 611 SxChildWasDispatched = FALSE; 612 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING; 613 ChildWasDispatched = FALSE; 614 615 // 616 // Preserve Index registers 617 // 618 SaveState (); 619 620 if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { 621 // 622 // We have children registered w/ us -- continue 623 // 624 while ((!EosSet) && (EscapeCount > 0)) { 625 EscapeCount--; 626 627 // 628 // Reset this flag in order to be able to process multiple SMI Sources in one loop. 629 // 630 ResetListSearch = FALSE; 631 632 LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); 633 634 while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) { 635 RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); 636 637 // 638 // look for the first active source 639 // 640 if (!SourceIsActive (&RecordInDb->SrcDesc)) { 641 // 642 // Didn't find the source yet, keep looking 643 // 644 LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); 645 646 } else { 647 // 648 // We found a source. If this is a sleep type, we have to go to 649 // appropriate sleep state anyway.No matter there is sleep child or not 650 // 651 if (RecordInDb->ProtocolType == SxType) { 652 SxChildWasDispatched = TRUE; 653 } 654 // 655 // "cache" the source description and don't query I/O anymore 656 // 657 CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource)); 658 LinkToExhaust = LinkInDb; 659 660 // 661 // exhaust the rest of the queue looking for the same source 662 // 663 while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) { 664 RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust); 665 666 if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) { 667 // 668 // These source descriptions are equal, so this callback should be 669 // dispatched. 670 // 671 if (RecordToExhaust->ContextFunctions.GetContext != NULL) { 672 // 673 // This child requires that we get a calling context from 674 // hardware and compare that context to the one supplied 675 // by the child. 676 // 677 ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL); 678 679 // 680 // Make sure contexts match before dispatching event to child 681 // 682 RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context); 683 ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext); 684 685 } else { 686 // 687 // This child doesn't require any more calling context beyond what 688 // it supplied in registration. Simply pass back what it gave us. 689 // 690 ASSERT (RecordToExhaust->Callback != NULL); 691 Context = RecordToExhaust->ChildContext; 692 ContextsMatch = TRUE; 693 } 694 695 if (ContextsMatch) { 696 697 if (RecordToExhaust->BufferSize != 0) { 698 ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL); 699 700 RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust); 701 702 CommunicationBuffer = &RecordToExhaust->CommBuffer; 703 BufferSize = RecordToExhaust->BufferSize; 704 } else { 705 CommunicationBuffer = NULL; 706 BufferSize = 0; 707 } 708 709 ASSERT (RecordToExhaust->Callback != NULL); 710 711 RecordToExhaust->Callback ( 712 (EFI_HANDLE) & RecordToExhaust->Link, 713 &Context, 714 CommunicationBuffer, 715 &BufferSize 716 ); 717 718 ChildWasDispatched = TRUE; 719 if (RecordToExhaust->ProtocolType == SxType) { 720 SxChildWasDispatched = TRUE; 721 } 722 } 723 } 724 // 725 // Get next record in DB 726 // 727 LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link); 728 } 729 730 if (RecordInDb->ClearSource == NULL) { 731 // 732 // Clear the SMI associated w/ the source using the default function 733 // 734 QNCSmmClearSource (&ActiveSource); 735 } else { 736 // 737 // This source requires special handling to clear 738 // 739 RecordInDb->ClearSource (&ActiveSource); 740 } 741 742 if (ChildWasDispatched) { 743 // 744 // The interrupt was handled and quiesced 745 // 746 Status = EFI_SUCCESS; 747 } else { 748 // 749 // The interrupt was not handled but quiesced 750 // 751 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED; 752 } 753 754 // 755 // Queue is empty, reset the search 756 // 757 ResetListSearch = TRUE; 758 759 } 760 } 761 EosSet = QNCSmmSetAndCheckEos (); 762 } 763 } 764 // 765 // If you arrive here, there are two possible reasons: 766 // (1) you've got problems with clearing the SMI status bits in the 767 // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the 768 // EOS bit. If this happens too many times, the loop exits. 769 // (2) there was a SMM communicate for callback messages that was received prior 770 // to this driver. 771 // If there is an asynchronous SMI that occurs while processing the Callback, let 772 // all of the drivers (including this one) have an opportunity to scan for the SMI 773 // and handle it. 774 // If not, we don't want to exit and have the foreground app. clear EOS without letting 775 // these other sources get serviced. 776 // 777 ASSERT (EscapeCount > 0); 778 779 // 780 // Restore Index registers 781 // 782 RestoreState (); 783 784 if (SxChildWasDispatched) { 785 // 786 // A child of the SmmSxDispatch protocol was dispatched during this call; 787 // put the system to sleep. 788 // 789 QNCSmmSxGoToSleep (); 790 } 791 792 // 793 // Ensure that SMI signal pin indicator is clear at the end of SMM handling. 794 // 795 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG); 796 NewValue &= ~(HLEGACY_SMI_PIN_VALUE); 797 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue); 798 799 return Status; 800 } 801