Home | History | Annotate | Download | only in QncSmmDispatcher
      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