EFI_STATUS BootMenuMain ( VOID ) { LIST_ENTRY BootOptionsList; UINTN OptionCount; UINTN BootOptionCount; EFI_STATUS Status; LIST_ENTRY* Entry; BDS_LOAD_OPTION* BootOption; UINTN BootOptionSelected; UINTN Index; UINTN BootMainEntryCount; BOOLEAN IsUnicode; BootOption = NULL; BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY); while (TRUE) { // Get Boot#### list BootOptionList (&BootOptionsList); OptionCount = 1; // Display the Boot options for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { BootOption = LOAD_OPTION_FROM_LINK(Entry); Print(L"[%d] %s\n", OptionCount, BootOption->Description); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; UINTN CmdLineSize; ARM_BDS_LOADER_TYPE LoaderType; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n")); return Status; } DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE); Print(L"\t- %s\n",DevicePathTxt); // If it is a supported BootEntry then print its details if (IS_ARM_BDS_BOOTENTRY (BootOption)) { OptionalData = BootOption->OptionalData; LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) { if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) { CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ( GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE); Print(L"\t- Initrd: %s\n", DevicePathTxt); } if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) { Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1)); } } switch (LoaderType) { case BDS_LOADER_EFI_APPLICATION: Print(L"\t- LoaderType: EFI Application\n"); break; case BDS_LOADER_KERNEL_LINUX_ATAG: Print(L"\t- LoaderType: Linux kernel with ATAG support\n"); break; case BDS_LOADER_KERNEL_LINUX_FDT: Print(L"\t- LoaderType: Linux kernel with FDT support\n"); break; default: Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType); } } else if (BootOption->OptionalData != NULL) { if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) { if (IsUnicode) { Print (L"\t- Arguments: %s\n", BootOption->OptionalData); } else { AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData); } } } FreePool(DevicePathTxt); DEBUG_CODE_END(); OptionCount++; } BootOptionCount = OptionCount-1; // Display the hardcoded Boot entries for (Index = 0; Index < BootMainEntryCount; Index++) { Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]); OptionCount++; } // Request the boot entry from the user BootOptionSelected = 0; while (BootOptionSelected == 0) { Print(L"Start: "); Status = GetHIInputInteger (&BootOptionSelected); if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) { Print(L"Invalid input (max %d)\n",(OptionCount-1)); BootOptionSelected = 0; } } // Start the selected entry if (BootOptionSelected > BootOptionCount) { // Start the hardcoded entry Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList); } else { // Find the selected entry from the Boot#### list Index = 1; for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { if (Index == BootOptionSelected) { BootOption = LOAD_OPTION_FROM_LINK(Entry); break; } Index++; } Status = BootOptionStart (BootOption); } } // Should never go here }
/** Worker function that displays the list of boot options that is passed in. The function loops over the entries of the list of boot options that is passed in. For each entry, the boot option description is displayed on a single line along with the position of the option in the list. In debug mode, the UEFI device path and the arguments of the boot option are displayed as well in subsequent lines. @param[in] BootOptionsList List of the boot options **/ STATIC VOID DisplayBootOptions ( IN LIST_ENTRY* BootOptionsList ) { EFI_STATUS Status; UINTN BootOptionCount; LIST_ENTRY *Entry; BDS_LOAD_OPTION *BdsLoadOption; BOOLEAN IsUnicode; BootOptionCount = 0 ; for (Entry = GetFirstNode (BootOptionsList); !IsNull (BootOptionsList, Entry); Entry = GetNextNode (BootOptionsList, Entry) ) { BdsLoadOption = LOAD_OPTION_FROM_LINK (Entry); Print (L"[%d] %s\n", ++BootOptionCount, BdsLoadOption->Description); DEBUG_CODE_BEGIN (); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; ARM_BDS_LOADER_TYPE LoaderType; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; Status = gBS->LocateProtocol ( &gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol ); ASSERT_EFI_ERROR (Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ( BdsLoadOption->FilePathList, TRUE, TRUE ); Print (L"\t- %s\n", DevicePathTxt); OptionalData = BdsLoadOption->OptionalData; if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) { LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT ) ) { Print (L"\t- Arguments: %a\n", &OptionalData->Arguments.LinuxArguments + 1); } } else if (OptionalData != NULL) { if (IsPrintableString (OptionalData, &IsUnicode)) { if (IsUnicode) { Print (L"\t- Arguments: %s\n", OptionalData); } else { AsciiPrint ("\t- Arguments: %a\n", OptionalData); } } } FreePool (DevicePathTxt); DEBUG_CODE_END (); } }
/** Reorder boot options Ask for the boot option to move and then move it when up or down arrows are pressed. This function is called when the user selects the "Reorder Boot Device Entries" entry in the boot manager menu. The order of the boot options in BootOptionList and in the UEFI BootOrder global variable are kept coherent until the user confirm his reordering (ie: he does not exit by pressing escape). @param[in] BootOptionsList List of the boot devices constructed in BootMenuMain() @retval EFI_SUCCESS No error encountered. @retval !EFI_SUCCESS An error has occured either in the selection of the boot option to move or while interacting with the user. **/ STATIC EFI_STATUS BootMenuReorderBootOptions ( IN LIST_ENTRY *BootOptionsList ) { EFI_STATUS Status; BDS_LOAD_OPTION_ENTRY *BootOptionEntry; LIST_ENTRY *SelectedEntry; LIST_ENTRY *PrevEntry; BOOLEAN Move; BOOLEAN Save; BOOLEAN Cancel; UINTN WaitIndex; EFI_INPUT_KEY Key; LIST_ENTRY *SecondEntry; UINTN BootOrderSize; UINT16 *BootOrder; LIST_ENTRY *Entry; UINTN Index; DisplayBootOptions (BootOptionsList); // Ask to select the boot option to move while (TRUE) { Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry); if (EFI_ERROR (Status)) { goto ErrorExit; } SelectedEntry = &BootOptionEntry->Link; SecondEntry = NULL; // Note down the previous entry in the list to be able to cancel changes PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry); // Start of interaction while (TRUE) { Print ( L"* Use up/down arrows to move the entry '%s'", BootOptionEntry->BdsLoadOption->Description ); // Wait for a move, save or cancel request Move = FALSE; Save = FALSE; Cancel = FALSE; do { Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex); if (!EFI_ERROR (Status)) { Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); } if (EFI_ERROR (Status)) { Print (L"\n"); goto ErrorExit; } switch (Key.ScanCode) { case SCAN_NULL: Save = (Key.UnicodeChar == CHAR_LINEFEED) || (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) || (Key.UnicodeChar == 0x7f); break; case SCAN_UP: SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry); Move = SecondEntry != BootOptionsList; break; case SCAN_DOWN: SecondEntry = GetNextNode (BootOptionsList, SelectedEntry); Move = SecondEntry != BootOptionsList; break; case SCAN_ESC: Cancel = TRUE; break; } } while ((!Move) && (!Save) && (!Cancel)); if (Move) { if ((SelectedEntry != NULL) && (SecondEntry != NULL)) { SwapListEntries (SelectedEntry, SecondEntry); } } else { if (Save) { Status = GetGlobalEnvironmentVariable ( L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder ); BootOrderSize /= sizeof (UINT16); if (!EFI_ERROR (Status)) { // The order of the boot options in the 'BootOptionsList' is the // new order that has been just defined by the user. Save this new // order in "BootOrder" UEFI global variable. Entry = GetFirstNode (BootOptionsList); for (Index = 0; Index < BootOrderSize; Index++) { BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex; Entry = GetNextNode (BootOptionsList, Entry); } Status = gRT->SetVariable ( (CHAR16*)L"BootOrder", &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, BootOrderSize * sizeof (UINT16), BootOrder ); FreePool (BootOrder); } if (EFI_ERROR (Status)) { Print (L"\nAn error occurred, move not completed!\n"); Cancel = TRUE; } } if (Cancel) { // // Restore initial position of the selected boot option // RemoveEntryList (SelectedEntry); InsertHeadList (PrevEntry, SelectedEntry); } } Print (L"\n"); DisplayBootOptions (BootOptionsList); // Saved or cancelled, back to the choice of boot option to move if (!Move) { break; } } } ErrorExit: return Status ; }
EFI_STATUS GetBootDeviceTypeInfo ( VOID ) { EFI_STATUS Status = EFI_SUCCESS; LIST_ENTRY BootOptionsList; LIST_ENTRY* Entry; UINT16 *SataDes = NULL; UINT16 *MacDes = NULL; UINTN SataDesSize = 0; UINTN MacDesSize = 0; BDS_LOAD_OPTION* BootOption; UINTN OptionCount = 0; CHAR16* SataStr = L"Sata"; CHAR16* MacStr = L"MAC"; CHAR16* DevicePathTxt = NULL; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol = NULL; // Get Boot#### list BootOptionList (&BootOptionsList); // Display the Boot options for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { BootOption = LOAD_OPTION_FROM_LINK(Entry); //Print(L"[%d] %s\n", OptionCount, BootOption->Description); //DEBUG_CODE_BEGIN(); Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n")); return Status; } DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE); //Print(L"\t- %s\n",DevicePathTxt); //DEBUG_CODE_END(); //FIND SATA BOOT DEVICES if(!(StringFind(DevicePathTxt, SataStr))) { if(SataDesSize != 0) { SataDes = ReallocatePool (SataDesSize, SataDesSize + sizeof(UINT16), SataDes); SataDes[SataDesSize / sizeof(UINT16)] = BootOption->LoadOptionIndex; SataDesSize += sizeof(UINT16); }else{ SataDesSize = sizeof(UINT16); SataDes = &(BootOption->LoadOptionIndex); } // Print(L"liuhuan SATA boot num: %d\n",SataDesSize / sizeof(UINT16)); } //FIND PXE BOOT DEVICES if(!(StringFind(DevicePathTxt, MacStr) )) { if(MacDesSize != 0) { MacDes = ReallocatePool (MacDesSize, MacDesSize + sizeof(UINT16), MacDes); MacDes[MacDesSize / sizeof(UINT16)] = BootOption->LoadOptionIndex; MacDesSize += sizeof(UINT16); }else{ MacDesSize = sizeof(UINT16); MacDes = &(BootOption->LoadOptionIndex); } // Print(L"liuhuan PXE boot num: %d\n",MacDesSize / sizeof(UINT16)); } //FreePool(DevicePathTxt); OptionCount++; } OemGetSataBootNum(SataDesSize); OemGetPXEBootNum(MacDesSize); if(SataDes != NULL) { FreePool(SataDes); } if(MacDes != NULL) { FreePool(MacDes); } if(DevicePathTxt != NULL) { FreePool(DevicePathTxt); } return EFI_SUCCESS; }