/** 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####")]; EFI_BOOT_MANAGER_LOAD_OPTION BootOption; SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xff); GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize); if (BootOrder == NULL) { return; } for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]); Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption); ASSERT_EFI_ERROR (Status); if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) { // // Legacy Boot Option // DEBUG ((EFI_D_ERROR, "[BootManagerDxe] ==== Find Legacy Boot Option 0x%x! ==== \n", Index)); ASSERT ((((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType & 0xF) < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0])); NextIndex = &DeviceTypeIndex[((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->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 < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) { if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) { DeviceTypeIndex[DeviceIndex]++; } } } } EfiBootManagerFreeLoadOption (&BootOption); } gRT->SetVariable ( L"BootOrder", &gEfiGlobalVariableGuid, VAR_FLAG, BootOrderSize, BootOrder ); FreePool (BootOrder); }
/** 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; EFI_BOOT_MANAGER_LOAD_OPTION BootOption; CHAR16 OptionName[sizeof ("Boot####")]; UINT16 *BbsIndexArray; UINT16 *DeviceTypeArray; GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize); ASSERT (BootOrder != NULL); BbsIndexArray = AllocatePool (BootOrderSize); DeviceTypeArray = AllocatePool (BootOrderSize); *EnBootOption = AllocatePool (BootOrderSize); *DisBootOption = AllocatePool (BootOrderSize); *DisBootOptionCount = 0; *EnBootOptionCount = 0; Index = 0; ASSERT (*EnBootOption != NULL); ASSERT (*DisBootOption != NULL); for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]); Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption); ASSERT_EFI_ERROR (Status); if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) { // // Legacy Boot Option // ASSERT (BootOption.OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA)); DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType; BbsIndexArray [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption.OptionalData)->BbsIndex; } else { DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN; BbsIndexArray [Index] = 0xFFFF; } EfiBootManagerFreeLoadOption (&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)); 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, VAR_FLAG, BootOrderSize, BootOrder ); ASSERT_EFI_ERROR (Status); FreePool (NewBootOption); FreePool (DeviceTypeArray); FreePool (BbsIndexArray); }
/** 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 ) { LIST_ENTRY *Link; HOTKEY *Hotkey; CHAR16 OptionName[sizeof ("Boot####")]; EFI_STATUS Status; EFI_KEY_DATA *HotkeyData; if (mHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) { // // Do not process sequential hotkey stroke until the current boot option returns // return EFI_SUCCESS; } DEBUG ((EFI_D_INFO, "[Bds]HotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar)); EfiAcquireLock (&mHotkeyLock); for ( Link = GetFirstNode (&mHotkeyList) ; !IsNull (&mHotkeyList, Link) ; Link = GetNextNode (&mHotkeyList, Link) ) { Hotkey = HOTKEY_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 ) ) { // // Receive an expecting key stroke, transit to next waiting state // Hotkey->WaitingKey++; if (Hotkey->WaitingKey == Hotkey->CodeCount) { // // Reset to initial waiting state // Hotkey->WaitingKey = 0; // // Received the whole key stroke sequence // Status = gBS->SignalEvent (mHotkeyTriggered); ASSERT_EFI_ERROR (Status); if (!Hotkey->IsContinue) { // // Launch its BootOption // UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", Hotkey->BootOption); Status = EfiBootManagerVariableToLoadOption (OptionName, &mHotkeyBootOption); DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status)); if (EFI_ERROR (Status)) { mHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned; } } else { DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n")); } } } else { // // Receive an unexpected key stroke, reset to initial waiting state // Hotkey->WaitingKey = 0; } } EfiReleaseLock (&mHotkeyLock); return EFI_SUCCESS; }
EFIAPI EfiBootManagerGetLoadOptions ( OUT UINTN *OptionCount, IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType ) { EFI_STATUS Status; UINT16 *OptionOrder; UINTN OptionOrderSize; UINTN Index; UINTN OptionIndex; EFI_BOOT_MANAGER_LOAD_OPTION *Options; CHAR16 OptionName[BM_OPTION_NAME_LEN]; UINT16 OptionNumber; *OptionCount = 0; if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) { // // Read the BootOrder, or DriverOrder variable. // GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize); if (OptionOrder == NULL) { return NULL; } *OptionCount = OptionOrderSize / sizeof (UINT16); Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); ASSERT (Options != NULL); OptionIndex = 0; for (Index = 0; Index < *OptionCount; Index++) { OptionNumber = OptionOrder[Index]; UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber); Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName)); EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType); } else { ASSERT (Options[OptionIndex].OptionNumber == OptionNumber); OptionIndex++; } } if (OptionOrder != NULL) { FreePool (OptionOrder); } if (OptionIndex < *OptionCount) { Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options); ASSERT (Options != NULL); *OptionCount = OptionIndex; } } else { return NULL; } return Options; }
/** Dump Provisioned Capsule. @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation. **/ VOID DumpProvisionedCapsule ( IN BOOLEAN DumpCapsuleInfo ) { EFI_STATUS Status; CHAR16 CapsuleVarName[30]; CHAR16 *TempVarName; UINTN Index; EFI_PHYSICAL_ADDRESS *CapsuleDataPtr64; UINT16 *BootNext; CHAR16 BootOptionName[20]; EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; EFI_SHELL_PROTOCOL *ShellProtocol; Index = 0; CapsuleDataPtr64 = NULL; BootNext = NULL; ShellProtocol = GetShellProtocol (); if (ShellProtocol == NULL) { Print (L"Get Shell Protocol Fail\n"); return ; } // // Dump capsule provisioned on Memory // Print (L"#########################\n"); Print (L"### Capsule on Memory ###\n"); Print (L"#########################\n"); StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME); TempVarName = CapsuleVarName + StrLen (CapsuleVarName); while (TRUE) { if (Index > 0) { UnicodeValueToStringS ( TempVarName, sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName), 0, Index, 0 ); } Status = GetVariable2 ( CapsuleVarName, &gEfiCapsuleVendorGuid, (VOID **) &CapsuleDataPtr64, NULL ); if (EFI_ERROR (Status) || CapsuleDataPtr64 == NULL) { if (Index == 0) { Print (L"No data.\n"); } break; } Index++; Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64); DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN) *CapsuleDataPtr64, DumpCapsuleInfo); } // // Dump capsule provisioned on Disk // Print (L"#########################\n"); Print (L"### Capsule on Disk #####\n"); Print (L"#########################\n"); Status = GetVariable2 ( L"BootNext", &gEfiGlobalVariableGuid, (VOID **) &BootNext, NULL ); if (EFI_ERROR (Status) || BootNext == NULL) { Print (L"Get BootNext Variable Fail. Status = %r\n", Status); } else { UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNext); Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry); if (!EFI_ERROR (Status)) { // // Display description and device path // GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath, &DevicePath, &Fs); if(!EFI_ERROR (Status)) { Print (L"Capsules are provisioned on BootOption: %s\n", BootNextOptionEntry.Description); Print (L" %s %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE)); DumpCapsuleFromDisk (Fs, DumpCapsuleInfo); } } } }