Ejemplo n.º 1
0
/**
  Process BootOrder, or DriverOrder variables, by calling
  BdsLibVariableToOption () for each UINT16 in the variables.

  @param  BdsCommonOptionList   The header of the option list base on variable
                                VariableName
  @param  VariableName          EFI Variable name indicate the BootOrder or
                                DriverOrder

  @retval EFI_SUCCESS           Success create the boot option or driver option
                                list
  @retval EFI_OUT_OF_RESOURCES  Failed to get the boot option or driver option list

**/
EFI_STATUS
EFIAPI
BdsLibBuildOptionFromVar (
  IN  LIST_ENTRY                      *BdsCommonOptionList,
  IN  CHAR16                          *VariableName
  )
{
  UINT16            *OptionOrder;
  UINTN             OptionOrderSize;
  UINTN             Index;
  BDS_COMMON_OPTION *Option;
  CHAR16            OptionName[20];

  //
  // Zero Buffer in order to get all BOOT#### variables
  //
  ZeroMem (OptionName, sizeof (OptionName));

  //
  // Read the BootOrder, or DriverOrder variable.
  //
  OptionOrder = BdsLibGetVariableAndSize (
                  VariableName,
                  &gEfiGlobalVariableGuid,
                  &OptionOrderSize
                  );
  if (OptionOrder == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
    if (*VariableName == 'B') {
      UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
    } else {
      UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
    }

    Option              = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
    //ASSERT (Option != NULL);
    if (!Option)
    {
        DEBUG((DEBUG_INFO, "%a:%d Option %s wasn't found \n", __FILE__, __LINE__, Option));
        continue;
    }
    Option->BootCurrent = OptionOrder[Index];

  }

  FreePool (OptionOrder);

  return EFI_SUCCESS;
}
Ejemplo n.º 2
0
VOID
EFIAPI
PlatformBdsPolicyBehavior (
  IN OUT LIST_ENTRY                  *DriverOptionList,
  IN OUT LIST_ENTRY                  *BootOptionList,
  IN PROCESS_CAPSULES                ProcessCapsules,
  IN BASEM_MEMORY_TEST               BaseMemoryTest
  )
/*++

Routine Description:

  The function will excute with as the platform policy, current policy
  is driven by boot mode. IBV/OEM can customize this code for their specific
  policy action.

Arguments:

  DriverOptionList - The header of the driver option link list

  BootOptionList   - The header of the boot option link list

  ProcessCapsules  - A pointer to ProcessCapsules()

  BaseMemoryTest   - A pointer to BaseMemoryTest()

Returns:

  None.

--*/
{
  EFI_STATUS                         Status;
  UINT16                             Timeout;
  EFI_EVENT                          UserInputDurationTime;
  LIST_ENTRY                     *Link;
  BDS_COMMON_OPTION                  *BootOption;
  UINTN                              Index;
  EFI_INPUT_KEY                      Key;
  EFI_TPL                            OldTpl;
  EFI_BOOT_MODE                      BootMode;

  VBoxLogFlowFuncEnter();

  ConnectRootBridge ();

  if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
    DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
      "from disk since flash variables appear to be supported.\n"));
  } else {
    //
    // Try to restore variables from the hard disk early so
    // they can be used for the other BDS connect operations.
    //
    PlatformBdsRestoreNvVarsFromHardDisk ();
  }

  //
  // Init the time out value
  //
  Timeout = PcdGet16 (PcdPlatformBootTimeOut);

  //
  // Load the driver option as the driver option list
  //
  PlatformBdsGetDriverOption (DriverOptionList);

  //
  // Get current Boot Mode
  //
  Status = BdsLibGetBootMode (&BootMode);
  DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));

  //
  // Go the different platform policy with different boot mode
  // Notes: this part code can be change with the table policy
  //
  ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
  //
  // Connect platform console
  //
  Status = PlatformBdsConnectConsole (gPlatformConsole);
  if (EFI_ERROR (Status)) {
    //
    // Here OEM/IBV can customize with defined action
    //
    PlatformBdsNoConsoleAction ();
  }
  //
  // Create a 300ms duration event to ensure user has enough input time to enter Setup
  //
  Status = gBS->CreateEvent (
                  EVT_TIMER,
                  0,
                  NULL,
                  NULL,
                  &UserInputDurationTime
                  );
  ASSERT (Status == EFI_SUCCESS);
  Status = gBS->SetTimer (UserInputDurationTime, TimerRelative, 3000000);
  ASSERT (Status == EFI_SUCCESS);
  //
  // Memory test and Logo show
  //
  PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);

  //
  // Perform some platform specific connect sequence
  //
  PlatformBdsConnectSequence ();

  //
  // Process QEMU's -kernel command line option
  //
  TryRunningQemuKernel ();

  //
  // Give one chance to enter the setup if we
  // have the time out
  //
  if (Timeout != 0) {
    //PlatformBdsEnterFrontPage (Timeout, FALSE);
  }

  DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n"));
  BdsLibConnectAll ();
#ifdef VBOX
    {
        UINTN cFileSystem = 0;
        EFI_HANDLE *phFileSystem = NULL;
        BDS_COMMON_OPTION *BootOption0080 = NULL;
        EFI_STATUS rc = EFI_SUCCESS;
        DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization Start -----------------------\n"));
        BootOption0080 = BdsLibVariableToOption(BootOptionList, L"Boot0080");
        if (!BootOption0080)
        {
            rc = gBS->LocateHandleBuffer (ByProtocol,
                                          &gEfiSimpleFileSystemProtocolGuid,
                                          NULL,
                                          &cFileSystem,
                                          &phFileSystem);
            VBoxLogFlowFuncMarkRC(rc);
            VBoxLogFlowFuncMarkVar(cFileSystem, "%d");
            if (   rc == EFI_SUCCESS
                && cFileSystem > 0)
            {
                EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFSVolume;
                EFI_FILE_HANDLE                  hFSRoot;
                EFI_FILE_HANDLE                  hBootEfiFile;
                UINTN iFileSystem = 0;
                /* Ok, we've found several simple file system handles
                 * 1. we should find if '\\System\\Library\\CoreServices\\boot.efi' present
                 * 2. Alter 'BootOrder' to include this file in boot sequence.
                 */
                for (iFileSystem = 0; iFileSystem < cFileSystem; ++iFileSystem)
                {
                    EFI_DEVICE_PATH_PROTOCOL *pDevicePath = NULL;
                    /* mount and look up the boot.efi */
                    rc = gBS->HandleProtocol (phFileSystem[iFileSystem],
                                              &gEfiSimpleFileSystemProtocolGuid,
                                              (VOID *) &pFSVolume);
                    VBoxLogFlowFuncMarkVar(iFileSystem, "%d");
                    VBoxLogFlowFuncMarkRC(rc);
                    if (EFI_ERROR(rc))
                        continue;

                    rc = pFSVolume->OpenVolume(pFSVolume, &hFSRoot);
                    VBoxLogFlowFuncMarkRC(rc);
                    if (EFI_ERROR(rc))
                        continue;

                    rc = hFSRoot->Open(hFSRoot, &hBootEfiFile, L"\\System\\Library\\CoreServices\\boot.efi", EFI_FILE_MODE_READ, 0);
                    VBoxLogFlowFuncMarkRC(rc);
                    if (EFI_ERROR(rc))
                        continue;
                    /* nice file is found and we have to register it */
                    pDevicePath = FileDevicePath(phFileSystem[iFileSystem], L"\\System\\Library\\CoreServices\\boot.efi");
                    VBoxLogFlowFuncMarkVar(pDevicePath,"%p");
                    if (!pDevicePath)
                        continue;
                    rc = BdsLibRegisterNewOption (BootOptionList, pDevicePath, L"Mac Boot", L"BootOrder");
                    VBoxLogFlowFuncMarkRC(rc);
                }
            }
        }
        else
        {
            VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptionsSize, "%d");
            if (BootOption0080->LoadOptionsSize)
                VBoxLogFlowFuncMarkVar(BootOption0080->LoadOptions, "%s");
#if 0
            /* Boot0080 option is found */
            UINT16                    *BootOrder;
            UINTN                     BootOrderSize;
            UINTN                     Index = 0;
            CHAR16                    *BootOptionName;
            ASSERT(BootOption0080->Signature == BDS_LOAD_OPTION_SIGNATURE);
            BootOrder = BdsLibGetVariableAndSize (
                          L"BootOrder",
                          &gEfiGlobalVariableGuid,
                          &BootOrderSize);
            ASSERT(BootOrder);
            BootOptionName = AllocateRuntimePool(256 * sizeof(UINT16));
            UnicodeSPrint(BootOptionName, 256 * sizeof(UINT16), L"Boot%04x", BootOrder[Index]);
            BootOption0080->OptionName = BootOptionName;
            rc = gRT->SetVariable(BootOptionName,
                                  &gEfiGlobalVariableGuid,
                                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
                                  sizeof(BDS_COMMON_OPTION),
                                  BootOption0080);
            LogFlowFuncMarkRC(rc);
#if 0
            rc = BdsLibRegisterNewOption (BootOptionList, BootOption0080->DevicePath, L"Mac Boot Temp", L"BootOrder");
#endif
            LogFlowFuncMarkRC(rc);
#endif
        }
        DEBUG ((EFI_D_INFO, "------------------ VBox Platform Specific Initialization End -----------------------\n"));
    }
#endif
  BdsLibEnumerateAllBootOption (BootOptionList);

  SetBootOrderFromQemu (BootOptionList);
  //
  // The BootOrder variable may have changed, reload the in-memory list with
  // it.
  //
  BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");

  //
  // To give the User a chance to enter Setup here, if user set TimeOut is 0.
  // BDS should still give user a chance to enter Setup
  //
  // Connect first boot option, and then check user input before exit
  //
  for (Link = BootOptionList->ForwardLink; Link != BootOptionList;Link = Link->ForwardLink) {
    BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
    if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
      //
      // skip the header of the link list, becuase it has no boot option
      //
      continue;
    } else {
      //
      // Make sure the boot option device path connected, but ignore the BBS device path
      //
      if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
        BdsLibConnectDevicePath (BootOption->DevicePath);
      }
      break;
    }
  }

  //
  // Check whether the user input after the duration time has expired
  //
  OldTpl = EfiGetCurrentTpl();
  gBS->RestoreTPL (TPL_APPLICATION);
  gBS->WaitForEvent (1, &UserInputDurationTime, &Index);
  gBS->CloseEvent (UserInputDurationTime);
  Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
  gBS->RaiseTPL (OldTpl);

  if (!EFI_ERROR (Status)) {
    //
    // Enter Setup if user input
    //
    Timeout = 0xffff;
    PlatformBdsEnterFrontPage (Timeout, FALSE);
  }

  VBoxLogFlowFuncLeave();
  return ;
}
/**
  Re-order the Boot Option according to the DevOrder.

  The routine re-orders the Boot Option in BootOption array according to
  the order specified by DevOrder.

  @param DevOrder           Pointer to buffer containing the BBS Index,
                            high 8-bit value 0xFF indicating a disabled boot option
  @param DevOrderCount      Count of the BBS Index
  @param EnBootOption       Callee allocated buffer containing the enabled Boot Option Numbers
  @param EnBootOptionCount  Count of the enabled Boot Option Numbers
  @param DisBootOption      Callee allocated buffer containing the disabled Boot Option Numbers
  @param DisBootOptionCount Count of the disabled Boot Option Numbers
**/
VOID
OrderLegacyBootOption4SameType (
  UINT16                   *DevOrder,
  UINTN                    DevOrderCount,
  UINT16                   **EnBootOption,
  UINTN                    *EnBootOptionCount,
  UINT16                   **DisBootOption,
  UINTN                    *DisBootOptionCount
  )
{
  EFI_STATUS               Status;
  UINT16                   *NewBootOption;
  UINT16                   *BootOrder;
  UINTN                    BootOrderSize;
  UINTN                    Index;
  UINTN                    StartPosition;

  BDS_COMMON_OPTION        *BootOption;

  CHAR16                   OptionName[sizeof ("Boot####")];
  UINT16                   *BbsIndexArray;
  UINT16                   *DeviceTypeArray;
  LIST_ENTRY               List;

  BootOrder = BdsLibGetVariableAndSize (
                L"BootOrder",
                &gEfiGlobalVariableGuid,
                &BootOrderSize
                );
  ASSERT (BootOrder != NULL);

  BbsIndexArray       = AllocatePool (BootOrderSize);
  DeviceTypeArray     = AllocatePool (BootOrderSize);
  *EnBootOption       = AllocatePool (BootOrderSize);
  *DisBootOption      = AllocatePool (BootOrderSize);
  *DisBootOptionCount = 0;
  *EnBootOptionCount  = 0;
  Index               = 0;

  ASSERT (BbsIndexArray != NULL);
  ASSERT (DeviceTypeArray != NULL);
  ASSERT (*EnBootOption != NULL);
  ASSERT (*DisBootOption != NULL);

  for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {

    UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
    InitializeListHead (&List);
    BootOption = BdsLibVariableToOption (&List, OptionName);
    ASSERT (BootOption != NULL);

    if ((DevicePathType (BootOption->DevicePath) == BBS_DEVICE_PATH) &&
        (DevicePathSubType (BootOption->DevicePath) == BBS_BBS_DP)) {
      //
      // Legacy Boot Option
      //
      ASSERT (BootOption->LoadOptionsSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));

      DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType;
      BbsIndexArray  [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption->LoadOptions)->BbsIndex;
    } else {
      DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
      BbsIndexArray  [Index] = 0xFFFF;
    }
    FreePool (BootOption->DevicePath);
    FreePool (BootOption->Description);
    FreePool (BootOption->LoadOptions);
    FreePool (BootOption);
  }

  //
  // Record the corresponding Boot Option Numbers according to the DevOrder
  // Record the EnBootOption and DisBootOption according to the DevOrder
  //
  StartPosition = BootOrderSize / sizeof (UINT16);
  NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
  ASSERT (NewBootOption != NULL);
  while (DevOrderCount-- != 0) {
    for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
      if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
        StartPosition = MIN (StartPosition, Index);
        NewBootOption[DevOrderCount] = BootOrder[Index];

        if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
          (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
          (*DisBootOptionCount)++;
        } else {
          (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
          (*EnBootOptionCount)++;
        }
        break;
      }
    }
  }

  //
  // Overwrite the old BootOption
  //
  CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
  Status = gRT->SetVariable (
                  L"BootOrder",
                  &gEfiGlobalVariableGuid,
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
                  BootOrderSize,
                  BootOrder
                  );
  //
  // Changing content without increasing its size with current variable implementation shouldn't fail.
  //
  ASSERT_EFI_ERROR (Status);

  FreePool (NewBootOption);
  FreePool (DeviceTypeArray);
  FreePool (BbsIndexArray);
  FreePool (BootOrder);
}
/**
  Group the legacy boot options in the BootOption.

  The routine assumes the boot options in the beginning that covers all the device
  types are ordered properly and re-position the following boot options just after
  the corresponding boot options with the same device type.
  For example:
  1. Input  = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
     Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
     Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]

  2. Input  = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
     Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
     Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]

**/
VOID
GroupMultipleLegacyBootOption4SameType (
  VOID
  )
{
  EFI_STATUS                   Status;
  UINTN                        Index;
  UINTN                        DeviceIndex;
  UINTN                        DeviceTypeIndex[7];
  UINTN                        *NextIndex;
  UINT16                       OptionNumber;
  UINT16                       *BootOrder;
  UINTN                        BootOrderSize;
  CHAR16                       OptionName[sizeof ("Boot####")];
  BDS_COMMON_OPTION            *BootOption;
  LIST_ENTRY                   List;

  SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xff);

  BootOrder = BdsLibGetVariableAndSize (
                L"BootOrder",
                &gEfiGlobalVariableGuid,
                &BootOrderSize
                );

  for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
    UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
    InitializeListHead (&List);
    BootOption = BdsLibVariableToOption (&List, OptionName);
    ASSERT (BootOption != NULL);

    if ((DevicePathType (BootOption->DevicePath) == BBS_DEVICE_PATH) &&
        (DevicePathSubType (BootOption->DevicePath) == BBS_BBS_DP)) {
      //
      // Legacy Boot Option
      //
      ASSERT ((((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType & 0xF) < ARRAY_SIZE (DeviceTypeIndex));
      NextIndex = &DeviceTypeIndex[((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType & 0xF];

      if (*NextIndex == (UINTN) -1) {
        //
        // *NextIndex is the Index in BootOrder to put the next Option Number for the same type
        //
        *NextIndex = Index + 1;
      } else {
        //
        // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
        //
        OptionNumber = BootOrder[Index];
        CopyMem (&BootOrder[*NextIndex + 1], &BootOrder[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
        BootOrder[*NextIndex] = OptionNumber;

        //
        // Update the DeviceTypeIndex array to reflect the right shift operation
        //
        for (DeviceIndex = 0; DeviceIndex < ARRAY_SIZE (DeviceTypeIndex); DeviceIndex++) {
          if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
            DeviceTypeIndex[DeviceIndex]++;
          }
        }
      }
    }
    FreePool (BootOption->DevicePath);
    FreePool (BootOption->Description);
    FreePool (BootOption->LoadOptions);
    FreePool (BootOption);
  }

  Status = gRT->SetVariable (
                  L"BootOrder",
                  &gEfiGlobalVariableGuid,
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
                  BootOrderSize,
                  BootOrder
                  );
  //
  // Changing content without increasing its size with current variable implementation shouldn't fail.
  //
  ASSERT_EFI_ERROR (Status);
  FreePool (BootOrder);
}
Ejemplo n.º 5
0
/**

  This function attempts to boot for the boot order specified
  by platform policy.

**/
VOID
BdsBootDeviceSelect (
  VOID
  )
{
  EFI_STATUS        Status;
  LIST_ENTRY        *Link;
  BDS_COMMON_OPTION *BootOption;
  UINTN             ExitDataSize;
  CHAR16            *ExitData;
  UINT16            Timeout;
  LIST_ENTRY        BootLists;
  CHAR16            Buffer[20];
  BOOLEAN           BootNextExist;
  LIST_ENTRY        *LinkBootNext;
  EFI_EVENT         ConnectConInEvent;

  //
  // Got the latest boot option
  //
  BootNextExist = FALSE;
  LinkBootNext  = NULL;
  ConnectConInEvent = NULL;
  InitializeListHead (&BootLists);

  //
  // First check the boot next option
  //
  ZeroMem (Buffer, sizeof (Buffer));

  //
  // Create Event to signal ConIn connection request
  //
  if (PcdGetBool (PcdConInConnectOnDemand)) {
    Status = gBS->CreateEventEx (
                    EVT_NOTIFY_SIGNAL,
                    TPL_CALLBACK,
                    BdsEmptyCallbackFunction,
                    NULL,
                    &gConnectConInEventGuid,
                    &ConnectConInEvent
                    );
    if (EFI_ERROR(Status)) {
      ConnectConInEvent = NULL;
    }
  }

  if (mBootNext != NULL) {
    //
    // Indicate we have the boot next variable, so this time
    // boot will always have this boot option
    //
    BootNextExist = TRUE;

    //
    // Clear the this variable so it's only exist in this time boot
    //
    Status = gRT->SetVariable (
                    L"BootNext",
                    &gEfiGlobalVariableGuid,
                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
                    0,
                    NULL
                    );
    //
    // Deleting variable with current variable implementation shouldn't fail.
    //
    ASSERT_EFI_ERROR (Status);

    //
    // Add the boot next boot option
    //
    UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
    BootOption = BdsLibVariableToOption (&BootLists, Buffer);

    //
    // If fail to get boot option from variable, just return and do nothing.
    //
    if (BootOption == NULL) {
      return;
    }

    BootOption->BootCurrent = *mBootNext;
  }
  //
  // Parse the boot order to get boot option
  //
  BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");

  //
  // When we didn't have chance to build boot option variables in the first 
  // full configuration boot (e.g.: Reset in the first page or in Device Manager),
  // we have no boot options in the following mini configuration boot.
  // Give the last chance to enumerate the boot options.
  //
  if (IsListEmpty (&BootLists)) {
    BdsLibEnumerateAllBootOption (&BootLists);
  }

  Link = BootLists.ForwardLink;

  //
  // Parameter check, make sure the loop will be valid
  //
  if (Link == NULL) {
    return ;
  }
  //
  // Here we make the boot in a loop, every boot success will
  // return to the front page
  //
  for (;;) {
    //
    // Check the boot option list first
    //
    if (Link == &BootLists) {
      //
      // When LazyConIn enabled, signal connect ConIn event before enter UI
      //
      if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
        gBS->SignalEvent (ConnectConInEvent);
      }

      //
      // There are two ways to enter here:
      // 1. There is no active boot option, give user chance to
      //    add new boot option
      // 2. All the active boot option processed, and there is no
      //    one is success to boot, then we back here to allow user
      //    add new active boot option
      //
      Timeout = 0xffff;
      PlatformBdsEnterFrontPage (Timeout, FALSE);
      InitializeListHead (&BootLists);
      BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
      Link = BootLists.ForwardLink;
      continue;
    }
    //
    // Get the boot option from the link list
    //
    BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);

    //
    // According to EFI Specification, if a load option is not marked
    // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
    // load the option.
    //
    if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
      //
      // skip the header of the link list, because it has no boot option
      //
      Link = Link->ForwardLink;
      continue;
    }
    //
    // Make sure the boot option device path connected,
    // but ignore the BBS device path
    //
    if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
      //
      // Notes: the internal shell can not been connected with device path
      // so we do not check the status here
      //
      BdsLibConnectDevicePath (BootOption->DevicePath);
    }

    //
    // Restore to original mode before launching boot option.
    //
    BdsSetConsoleMode (FALSE);
    
    //
    // All the driver options should have been processed since
    // now boot will be performed.
    //
    Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
    if (Status != EFI_SUCCESS) {
      //
      // Call platform action to indicate the boot fail
      //
      BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
      PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);

      //
      // Check the next boot option
      //
      Link = Link->ForwardLink;

    } else {
      //
      // Call platform action to indicate the boot success
      //
      BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
      PlatformBdsBootSuccess (BootOption);

      //
      // Boot success, then stop process the boot order, and
      // present the boot manager menu, front page
      //

      //
      // When LazyConIn enabled, signal connect ConIn Event before enter UI
      //
      if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
        gBS->SignalEvent (ConnectConInEvent);
      }

      Timeout = 0xffff;
      PlatformBdsEnterFrontPage (Timeout, FALSE);

      //
      // Rescan the boot option list, avoid potential risk of the boot
      // option change in front page
      //
      if (BootNextExist) {
        LinkBootNext = BootLists.ForwardLink;
      }

      InitializeListHead (&BootLists);
      if (LinkBootNext != NULL) {
        //
        // Reserve the boot next option
        //
        InsertTailList (&BootLists, LinkBootNext);
      }

      BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
      Link = BootLists.ForwardLink;
    }
  }

}
Ejemplo n.º 6
0
/**

  This is the common notification function for HotKeys, it will be registered
  with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.

  @param KeyData         A pointer to a buffer that is filled in with the keystroke
                         information for the key that was pressed.

  @retval  EFI_SUCCESS   KeyData is successfully processed.
  @return  EFI_NOT_FOUND Fail to find boot option variable.
**/
EFI_STATUS
EFIAPI
HotkeyCallback (
  IN EFI_KEY_DATA     *KeyData
)
{
  BOOLEAN            HotkeyCatched;
  LIST_ENTRY         BootLists;
  LIST_ENTRY         *Link;
  BDS_HOTKEY_OPTION  *Hotkey;
  UINT16             Buffer[10];
  BDS_COMMON_OPTION  *BootOption;
  UINTN              ExitDataSize;
  CHAR16             *ExitData;
  EFI_STATUS         Status;
  EFI_KEY_DATA       *HotkeyData;

  if (mHotkeyCallbackPending) {
    //
    // When responsing to a Hotkey, ignore sequential hotkey stroke until
    // the current Boot#### load option returned
    //
    return EFI_SUCCESS;
  }

  Status = EFI_SUCCESS;
  Link = GetFirstNode (&mHotkeyList);

  while (!IsNull (&mHotkeyList, Link)) {
    HotkeyCatched = FALSE;
    Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);

    //
    // Is this Key Stroke we are waiting for?
    //
    ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
    HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
    if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
       (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
       (((HotkeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE)) {
      //
      // Receive an expecting key stroke
      //
      if (Hotkey->CodeCount > 1) {
        //
        // For hotkey of key combination, transit to next waiting state
        //
        Hotkey->WaitingKey++;

        if (Hotkey->WaitingKey == Hotkey->CodeCount) {
          //
          // Received the whole key stroke sequence
          //
          HotkeyCatched = TRUE;
        }
      } else {
        //
        // For hotkey of single key stroke
        //
        HotkeyCatched = TRUE;
      }
    } else {
      //
      // Receive an unexpected key stroke, reset to initial waiting state
      //
      Hotkey->WaitingKey = 0;
    }

    if (HotkeyCatched) {
      //
      // Reset to initial waiting state
      //
      Hotkey->WaitingKey = 0;

      //
      // Launch its BootOption
      //
      InitializeListHead (&BootLists);

      UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
      BootOption = BdsLibVariableToOption (&BootLists, Buffer);
      if (BootOption == NULL) {
        return EFI_NOT_FOUND;
      }
      BootOption->BootCurrent = Hotkey->BootOptionNumber;
      BdsLibConnectDevicePath (BootOption->DevicePath);

      //
      // Clear the screen before launch this BootOption
      //
      gST->ConOut->Reset (gST->ConOut, FALSE);

      mHotkeyCallbackPending = TRUE;
      Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
      mHotkeyCallbackPending = FALSE;

      if (EFI_ERROR (Status)) {
        //
        // Call platform action to indicate the boot fail
        //
        BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
        PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
      } else {
        //
        // Call platform action to indicate the boot success
        //
        BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
        PlatformBdsBootSuccess (BootOption);
      }
    }

    Link = GetNextNode (&mHotkeyList, Link);
  }

  return Status;
}
Ejemplo n.º 7
0
Archivo: Hotkey.c Proyecto: etiago/vbox
/**

  This is the common notification function for HotKeys, it will be registered
  with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.

  @param KeyData         A pointer to a buffer that is filled in with the keystroke
                         information for the key that was pressed.

  @retval  EFI_SUCCESS   KeyData is successfully processed.
  @return  EFI_NOT_FOUND Fail to find boot option variable.
**/
EFI_STATUS
EFIAPI
HotkeyCallback (
  IN EFI_KEY_DATA     *KeyData
)
{
  BOOLEAN            HotkeyCatched;
  LIST_ENTRY         BootLists;
  LIST_ENTRY         *Link;
  BDS_HOTKEY_OPTION  *Hotkey;
  UINT16             Buffer[10];
  EFI_STATUS         Status;
  EFI_KEY_DATA       *HotkeyData;

  if (mHotkeyBootOption != NULL) {
    //
    // Do not process sequential hotkey stroke until the current boot option returns
    //
    return EFI_SUCCESS;
  }

  Status                 = EFI_SUCCESS;

  for ( Link = GetFirstNode (&mHotkeyList)
      ; !IsNull (&mHotkeyList, Link)
      ; Link = GetNextNode (&mHotkeyList, Link)
      ) {
    HotkeyCatched = FALSE;
    Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);

    //
    // Is this Key Stroke we are waiting for?
    //
    ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
    HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
    if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
        (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
        (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? 
          (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
        )
       ) {
      //
      // For hotkey of key combination, transit to next waiting state
      //
      Hotkey->WaitingKey++;

      if (Hotkey->WaitingKey == Hotkey->CodeCount) {
        //
        // Received the whole key stroke sequence
        //
        HotkeyCatched = TRUE;
      }
    } else {
      //
      // Receive an unexpected key stroke, reset to initial waiting state
      //
      Hotkey->WaitingKey = 0;
    }

    if (HotkeyCatched) {
      //
      // Reset to initial waiting state
      //
      Hotkey->WaitingKey = 0;

      //
      // Launch its BootOption
      //
      InitializeListHead (&BootLists);

      UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
      mHotkeyBootOption = BdsLibVariableToOption (&BootLists, Buffer);
    }
  }

  return Status;
}