/** 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; }
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); }
/** 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; } } }
/** 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; }
/** 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; }