Пример #1
0
/**
  Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
  and initilize any state variables. Read the Depex from the FV and store it
  in DriverEntry. Pre-process the Depex to set the Before and After state.
  The Discovered list is never free'ed and contains booleans that represent the
  other possible SMM driver states.

  @param  Fv                    Fv protocol, needed to read Depex info out of
                                FLASH.
  @param  FvHandle              Handle for Fv, needed in the
                                EFI_SMM_DRIVER_ENTRY so that the PE image can be
                                read out of the FV at a later time.
  @param  DriverName            Name of driver to add to mDiscoveredList.

  @retval EFI_SUCCESS           If driver was added to the mDiscoveredList.
  @retval EFI_ALREADY_STARTED   The driver has already been started. Only one
                                DriverName may be active in the system at any one
                                time.

**/
EFI_STATUS
SmmAddToDriverList (
  IN EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
  IN EFI_HANDLE                     FvHandle,
  IN EFI_GUID                       *DriverName
  )
{
  EFI_SMM_DRIVER_ENTRY  *DriverEntry;

  //
  // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
  // NULL or FALSE.
  //
  DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));
  ASSERT (DriverEntry != NULL);

  DriverEntry->Signature        = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
  CopyGuid (&DriverEntry->FileName, DriverName);
  DriverEntry->FvHandle         = FvHandle;
  DriverEntry->Fv               = Fv;
  DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);

  SmmGetDepexSectionAndPreProccess (DriverEntry);

  InsertTailList (&mDiscoveredList, &DriverEntry->Link);
  gRequestDispatch = TRUE;

  return EFI_SUCCESS;
}
Пример #2
0
/**
  This is the main Dispatcher for SMM and it exits when there are no more
  drivers to run. Drain the mScheduledQueue and load and start a PE
  image for each driver. Search the mDiscoveredList to see if any driver can
  be placed on the mScheduledQueue. If no drivers are placed on the
  mScheduledQueue exit the function. 

  @retval EFI_SUCCESS           All of the SMM Drivers that could be dispatched
                                have been run and the SMM Entry Point has been
                                registered.
  @retval EFI_NOT_READY         The SMM Driver that registered the SMM Entry Point
                                was just dispatched.
  @retval EFI_NOT_FOUND         There are no SMM Drivers available to be dispatched.
  @retval EFI_ALREADY_STARTED   The SMM Dispatcher is already running

**/
EFI_STATUS
SmmDispatcher (
  VOID
  )
{
  EFI_STATUS            Status;
  LIST_ENTRY            *Link;
  EFI_SMM_DRIVER_ENTRY  *DriverEntry;
  BOOLEAN               ReadyToRun;
  BOOLEAN               PreviousSmmEntryPointRegistered;

  if (!gRequestDispatch) {
    return EFI_NOT_FOUND;
  }

  if (gDispatcherRunning) {
    //
    // If the dispatcher is running don't let it be restarted.
    //
    return EFI_ALREADY_STARTED;
  }

  gDispatcherRunning = TRUE;

  do {
    //
    // Drain the Scheduled Queue
    //
    while (!IsListEmpty (&mScheduledQueue)) {
      DriverEntry = CR (
                      mScheduledQueue.ForwardLink,
                      EFI_SMM_DRIVER_ENTRY,
                      ScheduledLink,
                      EFI_SMM_DRIVER_ENTRY_SIGNATURE
                      );

      //
      // Load the SMM Driver image into memory. If the Driver was transitioned from
      // Untrused to Scheduled it would have already been loaded so we may need to
      // skip the LoadImage
      //
      if (DriverEntry->ImageHandle == NULL) {
        Status = SmmLoadImage (DriverEntry);

        //
        // Update the driver state to reflect that it's been loaded
        //
        if (EFI_ERROR (Status)) {
          //
          // The SMM Driver could not be loaded, and do not attempt to load or start it again.
          // Take driver from Scheduled to Initialized.
          //
          DriverEntry->Initialized  = TRUE;
          DriverEntry->Scheduled = FALSE;
          RemoveEntryList (&DriverEntry->ScheduledLink);

          //
          // If it's an error don't try the StartImage
          //
          continue;
        }
      }

      DriverEntry->Scheduled    = FALSE;
      DriverEntry->Initialized  = TRUE;
      RemoveEntryList (&DriverEntry->ScheduledLink);

      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
        EFI_PROGRESS_CODE,
        EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
        &DriverEntry->ImageHandle,
        sizeof (DriverEntry->ImageHandle)
        );

      //
      // Cache state of SmmEntryPointRegistered before calling entry point
      //
      PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;

      //
      // For each SMM driver, pass NULL as ImageHandle
      //
      Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
      if (EFI_ERROR(Status)){
        SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
      }

      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
        EFI_PROGRESS_CODE,
        EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,
        &DriverEntry->ImageHandle,
        sizeof (DriverEntry->ImageHandle)
        );

      if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {
        //
        // Return immediately if the SMM Entry Point was registered by the SMM 
        // Driver that was just dispatched.  The SMM IPL will reinvoke the SMM
        // Core Dispatcher.  This is required so SMM Mode may be enabled as soon 
        // as all the dependent SMM Drivers for SMM Mode have been dispatched.  
        // Once the SMM Entry Point has been registered, then SMM Mode will be 
        // used.
        //
        gRequestDispatch = TRUE;
        gDispatcherRunning = FALSE;
        return EFI_NOT_READY;
      }
    }

    //
    // Search DriverList for items to place on Scheduled Queue
    //
    ReadyToRun = FALSE;
    for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
      DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);

      if (DriverEntry->DepexProtocolError){
        //
        // If Section Extraction Protocol did not let the Depex be read before retry the read
        //
        Status = SmmGetDepexSectionAndPreProccess (DriverEntry);
      }

      if (DriverEntry->Dependent) {
        if (SmmIsSchedulable (DriverEntry)) {
          SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
          ReadyToRun = TRUE;
        }
      }
    }
  } while (ReadyToRun);

  //
  // If there is no more SMM driver to dispatch, stop the dispatch request
  //
  gRequestDispatch = FALSE;
  for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);

    if (!DriverEntry->Initialized){
      //
      // We have SMM driver pending to dispatch
      //
      gRequestDispatch = TRUE;
      break;
    }
  }

  gDispatcherRunning = FALSE;

  return EFI_SUCCESS;
}
Пример #3
0
/**
  This is the main Dispatcher for SMM and it exits when there are no more
  drivers to run. Drain the mScheduledQueue and load and start a PE
  image for each driver. Search the mDiscoveredList to see if any driver can
  be placed on the mScheduledQueue. If no drivers are placed on the
  mScheduledQueue exit the function. On exit it is assumed the Bds()
  will be called, and when the Bds() exits the Dispatcher will be called
  again.

  @retval EFI_ALREADY_STARTED   The SMM Dispatcher is already running
  @retval EFI_NOT_FOUND         No SMM Drivers were dispatched
  @retval EFI_SUCCESS           One or more SMM Drivers were dispatched

**/
EFI_STATUS
SmmDispatcher (
  VOID
  )
{
  EFI_STATUS            Status;
  EFI_STATUS            ReturnStatus;
  LIST_ENTRY            *Link;
  EFI_SMM_DRIVER_ENTRY  *DriverEntry;
  BOOLEAN               ReadyToRun;

  if (!gRequestDispatch) {
    return EFI_NOT_FOUND;
  }

  if (gDispatcherRunning) {
    //
    // If the dispatcher is running don't let it be restarted.
    //
    return EFI_ALREADY_STARTED;
  }

  gDispatcherRunning = TRUE;

  ReturnStatus = EFI_NOT_FOUND;
  do {
    //
    // Drain the Scheduled Queue
    //
    while (!IsListEmpty (&mScheduledQueue)) {
      DriverEntry = CR (
                      mScheduledQueue.ForwardLink,
                      EFI_SMM_DRIVER_ENTRY,
                      ScheduledLink,
                      EFI_SMM_DRIVER_ENTRY_SIGNATURE
                      );

      //
      // Load the SMM Driver image into memory. If the Driver was transitioned from
      // Untrused to Scheduled it would have already been loaded so we may need to
      // skip the LoadImage
      //
      if (DriverEntry->ImageHandle == NULL) {
        Status = SmmLoadImage (DriverEntry);

        //
        // Update the driver state to reflect that it's been loaded
        //
        if (EFI_ERROR (Status)) {

          if (Status == EFI_SECURITY_VIOLATION) {
            //
            // Take driver from Scheduled to Untrused state
            //
            DriverEntry->Untrusted = TRUE;
          } else {
            //
            // The SMM Driver could not be loaded, and do not attempt to load or start it again.
            // Take driver from Scheduled to Initialized.
            //
            // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
            //
            DriverEntry->Initialized  = TRUE;
          }

          DriverEntry->Scheduled = FALSE;
          RemoveEntryList (&DriverEntry->ScheduledLink);

          //
          // If it's an error don't try the StartImage
          //
          continue;
        }
      }

      DriverEntry->Scheduled    = FALSE;
      DriverEntry->Initialized  = TRUE;
      RemoveEntryList (&DriverEntry->ScheduledLink);

      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
        EFI_PROGRESS_CODE,
        EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
        &DriverEntry->ImageHandle,
        sizeof (DriverEntry->ImageHandle)
        );

      //
      // For each SMM driver, pass NULL as ImageHandle
      //
      Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
      if (EFI_ERROR(Status)){
        SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
      }

      REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
        EFI_PROGRESS_CODE,
        EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,
        &DriverEntry->ImageHandle,
        sizeof (DriverEntry->ImageHandle)
        );

      ReturnStatus = EFI_SUCCESS;
    }

    //
    // Search DriverList for items to place on Scheduled Queue
    //
    ReadyToRun = FALSE;
    for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
      DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);

      if (DriverEntry->DepexProtocolError){
        //
        // If Section Extraction Protocol did not let the Depex be read before retry the read
        //
        Status = SmmGetDepexSectionAndPreProccess (DriverEntry);
      }

      if (DriverEntry->Dependent) {
        if (SmmIsSchedulable (DriverEntry)) {
          SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
          ReadyToRun = TRUE;
        }
      }
    }
  } while (ReadyToRun);

  //
  // If there is no more SMM driver to dispatch, stop the dispatch request
  //
  gRequestDispatch = FALSE;
  for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);

    if (!DriverEntry->Initialized){
      //
      // We have SMM driver pending to dispatch
      //
      gRequestDispatch = TRUE;
      break;
    }
  }

  gDispatcherRunning = FALSE;

  return ReturnStatus;
}