Esempio n. 1
0
EFI_STATUS
QNCSmmCoreUnRegister (
  IN QNC_SMM_GENERIC_PROTOCOL                         *This,
  IN EFI_HANDLE                                        DispatchHandle
  )
/*++

Routine Description:

Arguments:

Returns:

--*/
// GC_TODO:    This - add argument and description to function comment
// GC_TODO:    DispatchHandle - add argument and description to function comment
// GC_TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// GC_TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// GC_TODO:    EFI_SUCCESS - add return value to function comment
{
  BOOLEAN         SafeToDisable;
  DATABASE_RECORD *RecordToDelete;
  DATABASE_RECORD *RecordInDb;
  LIST_ENTRY      *LinkInDb;

  if (DispatchHandle == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {
    return EFI_INVALID_PARAMETER;
  }

  RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);

  RemoveEntryList (&RecordToDelete->Link);
  RecordToDelete->Signature = 0;

  //
  // See if we can disable the source, reserved for future use since this might
  //  not be the only criteria to disable
  //
  SafeToDisable = TRUE;
  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
  while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
    if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {
      SafeToDisable = FALSE;
      break;
    }
    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
  }
  if (SafeToDisable) {
    QNCSmmDisableSource( &RecordToDelete->SrcDesc );
}

  FreePool (RecordToDelete);

  return EFI_SUCCESS;
}
Esempio n. 2
0
VOID
QNCSmmPeriodicTimerClearSource (
  IN QNC_SMM_SOURCE_DESC     *SrcDesc
  )
/*++

Routine Description:

  This function is responsible for calculating and enabling any timers that are required
  to dispatch messages to children. The SrcDesc argument isn't acutally used.

Arguments:

  SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance.

Returns:

  None.

--*/
{
  DATABASE_RECORD   *RecordInDb;
  LIST_ENTRY        *LinkInDb;

  QNCSmmPeriodicTimerProgramTimers ();

  //
  // Reset Elapsed time
  //
  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
    if (RecordInDb->ProtocolType == PeriodicTimerType) {
      //
      // This child is registerd with the PeriodicTimer protocol and Callback
      // has been invoked, so reset the ElapsedTime to 0
      //
      if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) {
        RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0;
      }
    }
    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
  }
}
Esempio n. 3
0
EFI_STATUS
SmiInputValueDuplicateCheck (
  UINTN           FedSwSmiInputValue
  )
/*++

Routine Description:

  Check the Fed SwSmiInputValue to see if there is a duplicated one in the database

Arguments:
  None

Returns:
  Status - EFI_SUCCESS, EFI_INVALID_PARAMETER

--*/
// GC_TODO:    FedSwSmiInputValue - add argument and description to function comment
{

  DATABASE_RECORD *RecordInDb;
  LIST_ENTRY      *LinkInDb;

  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);

    if (RecordInDb->ProtocolType == SwType) {
      if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {
        return EFI_INVALID_PARAMETER;
      }
    }

    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
  }

  return EFI_SUCCESS;
}
Esempio n. 4
0
/**
  This function is the main entry point for an SMM handler dispatch
  or communicate-based callback.

  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
  @param  RegisterContext Points to an optional handler context which was specified when the handler was registered.
  @param  CommBuffer      A pointer to a collection of data in memory that will
                          be conveyed from a non-SMM environment into an SMM environment.
  @param  CommBufferSize  The size of the CommBuffer.

  @return Status Code

**/
EFI_STATUS
QNCSmmCoreDispatcher (
  IN     EFI_HANDLE               DispatchHandle,
  IN     CONST VOID               *RegisterContext,
  IN OUT VOID                     *CommBuffer,
  IN OUT UINTN                    *CommBufferSize
  )
{
  //
  // Used to prevent infinite loops
  //
  UINTN               EscapeCount;

  BOOLEAN             ContextsMatch;
  BOOLEAN             ResetListSearch;
  BOOLEAN             EosSet;
  BOOLEAN             SxChildWasDispatched;
  BOOLEAN             ChildWasDispatched;

  DATABASE_RECORD     *RecordInDb;
  DATABASE_RECORD     ActiveRecordInDb;
  LIST_ENTRY          *LinkInDb;
  DATABASE_RECORD     *RecordToExhaust;
  LIST_ENTRY          *LinkToExhaust;

  QNC_SMM_CONTEXT     Context;
  VOID                *CommunicationBuffer;
  UINTN               BufferSize;

  EFI_STATUS          Status;
  UINT32              NewValue;

  QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;

  EscapeCount           = 100;
  ContextsMatch         = FALSE;
  ResetListSearch       = FALSE;
  EosSet                = FALSE;
  SxChildWasDispatched  = FALSE;
  Status                = EFI_WARN_INTERRUPT_SOURCE_PENDING;
  ChildWasDispatched    = FALSE;

  //
  // Mark all child handlers as not processed
  //
  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
    RecordInDb->Processed = FALSE;
    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);
  }

  //
  // Preserve Index registers
  //
  SaveState ();

  if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
    //
    // We have children registered w/ us -- continue
    //
    while ((!EosSet) && (EscapeCount > 0)) {
      EscapeCount--;

      //
      // Reset this flag in order to be able to process multiple SMI Sources in one loop.
      //
      ResetListSearch = FALSE;

      LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);

      while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {
        RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
        //
        // Make a copy of the record that contains an active SMI source,
        // because un-register maybe invoked in callback function and
        // RecordInDb maybe released
        //
        CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb));

        //
        // look for the first active source
        //
        if (!SourceIsActive (&RecordInDb->SrcDesc)) {
          //
          // Didn't find the source yet, keep looking
          //
          LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);

        } else {
          //
          // We found a source. If this is a sleep type, we have to go to
          // appropriate sleep state anyway.No matter there is sleep child or not
          //
          if (RecordInDb->ProtocolType == SxType) {
            SxChildWasDispatched = TRUE;
          }
          //
          // "cache" the source description and don't query I/O anymore
          //
          CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));
          LinkToExhaust = LinkInDb;

          //
          // exhaust the rest of the queue looking for the same source
          //
          while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
            RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
            LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust);
            if (RecordToExhaust->Processed) {
              //
              // Record has already been processed.  Continue with next child handler.
              //
              continue;
            }

            if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
              //
              // These source descriptions are equal, so this callback should be
              // dispatched.
              //
              if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
                //
                // This child requires that we get a calling context from
                // hardware and compare that context to the one supplied
                // by the child.
                //
                ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);

                //
                // Make sure contexts match before dispatching event to child
                //
                RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
                ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);

              } else {
                //
                // This child doesn't require any more calling context beyond what
                // it supplied in registration.  Simply pass back what it gave us.
                //
                ASSERT (RecordToExhaust->Callback != NULL);
                ContextsMatch = TRUE;
              }

              //
              // Mark this child handler so it will not be processed again
              //
              RecordToExhaust->Processed = TRUE;

              if (ContextsMatch) {

                if (RecordToExhaust->BufferSize != 0) {
                  ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);

                  RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);

                  CommunicationBuffer = &RecordToExhaust->CommBuffer;
                  BufferSize = RecordToExhaust->BufferSize;
                } else {
                  CommunicationBuffer = NULL;
                  BufferSize = 0;
                }

                ASSERT (RecordToExhaust->Callback != NULL);

                RecordToExhaust->Callback (
                                   (EFI_HANDLE) & RecordToExhaust->Link,
                                   RecordToExhaust->CallbackContext,
                                   CommunicationBuffer,
                                   &BufferSize
                                   );

                ChildWasDispatched = TRUE;
                if (RecordToExhaust->ProtocolType == SxType) {
                  SxChildWasDispatched = TRUE;
                }
              }
              //
              // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb
              // Restart processing of SMI handlers from the begining of the linked list because the
              // state of the linked listed may have been modified due to unregister actions in the Callback.
              //
              LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase);
            }
          }

          if (ActiveRecordInDb.ClearSource == NULL) {
            //
            // Clear the SMI associated w/ the source using the default function
            //
            QNCSmmClearSource (&ActiveSource);
          } else {
            //
            // This source requires special handling to clear
            //
            ActiveRecordInDb.ClearSource (&ActiveSource);
          }

          if (ChildWasDispatched) {
            //
            // The interrupt was handled and quiesced
            //
            Status = EFI_SUCCESS;
          } else {
            //
            // The interrupt was not handled but quiesced
            //
            Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
          }

          //
          // Queue is empty, reset the search
          //
          ResetListSearch = TRUE;

        }
      }
      EosSet = QNCSmmSetAndCheckEos ();
    }
  }
  //
  // If you arrive here, there are two possible reasons:
  // (1) you've got problems with clearing the SMI status bits in the
  // ACPI table.  If you don't properly clear the SMI bits, then you won't be able to set the
  // EOS bit.  If this happens too many times, the loop exits.
  // (2) there was a SMM communicate for callback messages that was received prior
  // to this driver.
  // If there is an asynchronous SMI that occurs while processing the Callback, let
  // all of the drivers (including this one) have an opportunity to scan for the SMI
  // and handle it.
  // If not, we don't want to exit and have the foreground app. clear EOS without letting
  // these other sources get serviced.
  //
  ASSERT (EscapeCount > 0);

  //
  // Restore Index registers
  //
  RestoreState ();

  if (SxChildWasDispatched) {
    //
    // A child of the SmmSxDispatch protocol was dispatched during this call;
    // put the system to sleep.
    //
    QNCSmmSxGoToSleep ();
  }

  //
  // Ensure that SMI signal pin indicator is clear at the end of SMM handling.
  //
  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);
  NewValue &= ~(HLEGACY_SMI_PIN_VALUE);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);

  return Status;
}
Esempio n. 5
0
VOID
QNCSmmPeriodicTimerProgramTimers (
  VOID
  )
{
  UINT32            GpePmcwValue;
  SUPPORTED_TIMER   Timer;
  DATABASE_RECORD   *RecordInDb;
  LIST_ENTRY        *LinkInDb;
  TIMER_INTERVAL    *TimerInterval;

  //
  // Find the minimum required interval for each timer
  //
  for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) {
    mTimers[Timer].MinReqInterval = ~(UINT64)0x0;
    mTimers[Timer].NumChildren = 0;
  }
  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
    if (RecordInDb->ProtocolType == PeriodicTimerType) {
      //
      // This child is registerd with the PeriodicTimer protocol
      //
      TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);

      if(TimerInterval != NULL) {
        Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer;

        ASSERT (Timer >= 0 && Timer < NUM_TIMERS);

        if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {
          mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;
        }
        mTimers[Timer].NumChildren++;
      }
    }
    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
  }

  //
  // Program the hardware
  //
  GpePmcwValue = 0;
  if (mTimers[PERIODIC_TIMER].NumChildren > 0) {
    switch (mTimers[PERIODIC_TIMER].MinReqInterval) {

    case TIME_64s:
      GpePmcwValue = INDEX_TIME_64s;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
      break;

    case TIME_32s:
      GpePmcwValue = INDEX_TIME_32s;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
      break;

    case TIME_16s:
      GpePmcwValue = INDEX_TIME_16s;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
      break;

    case TIME_8s:
      GpePmcwValue = INDEX_TIME_8s;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
      break;

    case TIME_64ms:
      GpePmcwValue = INDEX_TIME_64ms;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms;
      break;

    case TIME_32ms:
      GpePmcwValue = INDEX_TIME_32ms;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms;
      break;

    case TIME_16ms:
      GpePmcwValue = INDEX_TIME_16ms;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms;
      break;

    case TIME_1_5ms:
      GpePmcwValue = INDEX_TIME_1_5ms;
      mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
      break;

    default:
      ASSERT (FALSE);
      break;
    };

    GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE;

    IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue);

    //
    // Restart the timer here, just need to clear the SMI
    //
    QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
  } else {
    QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
  }
}