2011-06-11 13:58:23 +02:00
|
|
|
/** @file
|
|
|
|
*
|
|
|
|
* Copyright (c) 2011, ARM Limited. All rights reserved.
|
|
|
|
*
|
|
|
|
* This program and the accompanying materials
|
|
|
|
* are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
* which accompanies this distribution. The full text of the license may be found at
|
|
|
|
* http://opensource.org/licenses/bsd-license.php
|
|
|
|
*
|
|
|
|
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "BdsInternal.h"
|
|
|
|
|
|
|
|
extern EFI_HANDLE mImageHandle;
|
|
|
|
extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;
|
|
|
|
|
|
|
|
EFI_STATUS
|
2011-08-18 15:21:14 +02:00
|
|
|
SelectBootDevice (
|
|
|
|
OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice
|
2011-06-11 13:58:23 +02:00
|
|
|
)
|
|
|
|
{
|
2011-08-18 15:21:14 +02:00
|
|
|
EFI_STATUS Status;
|
2011-06-11 13:58:23 +02:00
|
|
|
LIST_ENTRY SupportedDeviceList;
|
|
|
|
UINTN SupportedDeviceCount;
|
|
|
|
LIST_ENTRY* Entry;
|
|
|
|
UINTN SupportedDeviceSelected;
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
//
|
|
|
|
// List the Boot Devices supported
|
|
|
|
//
|
|
|
|
|
|
|
|
// Start all the drivers first
|
|
|
|
BdsConnectAllDrivers ();
|
|
|
|
|
|
|
|
// List the supported devices
|
|
|
|
Status = BootDeviceListSupportedInit (&SupportedDeviceList);
|
|
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
|
|
|
|
SupportedDeviceCount = 0;
|
|
|
|
for (Entry = GetFirstNode (&SupportedDeviceList);
|
|
|
|
!IsNull (&SupportedDeviceList,Entry);
|
|
|
|
Entry = GetNextNode (&SupportedDeviceList,Entry)
|
|
|
|
)
|
|
|
|
{
|
2011-08-18 15:21:14 +02:00
|
|
|
*SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
|
|
|
|
Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
DEBUG_CODE_BEGIN();
|
|
|
|
CHAR16* DevicePathTxt;
|
|
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
|
|
|
|
|
|
|
|
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
|
|
|
|
ASSERT_EFI_ERROR(Status);
|
2011-08-18 15:21:14 +02:00
|
|
|
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
Print(L"\t- %s\n",DevicePathTxt);
|
|
|
|
|
|
|
|
FreePool(DevicePathTxt);
|
|
|
|
DEBUG_CODE_END();
|
|
|
|
|
|
|
|
SupportedDeviceCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SupportedDeviceCount == 0) {
|
|
|
|
Print(L"There is no supported device.\n");
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Select the Boot Device
|
|
|
|
//
|
|
|
|
SupportedDeviceSelected = 0;
|
|
|
|
while (SupportedDeviceSelected == 0) {
|
|
|
|
Print(L"Select the Boot Device: ");
|
|
|
|
Status = GetHIInputInteger (&SupportedDeviceSelected);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
} else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {
|
|
|
|
Print(L"Invalid input (max %d)\n",SupportedDeviceSelected);
|
|
|
|
SupportedDeviceSelected = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the Device Path for the selected boot device
|
|
|
|
//
|
|
|
|
Index = 1;
|
|
|
|
for (Entry = GetFirstNode (&SupportedDeviceList);
|
|
|
|
!IsNull (&SupportedDeviceList,Entry);
|
|
|
|
Entry = GetNextNode (&SupportedDeviceList,Entry)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (Index == SupportedDeviceSelected) {
|
2011-08-18 15:21:14 +02:00
|
|
|
*SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
|
2011-06-11 13:58:23 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Index++;
|
|
|
|
}
|
2011-08-18 15:21:14 +02:00
|
|
|
|
|
|
|
EXIT:
|
|
|
|
BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootMenuAddBootOption (
|
|
|
|
IN LIST_ENTRY *BootOptionsList
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
BDS_SUPPORTED_DEVICE* SupportedBootDevice;
|
|
|
|
BDS_LOADER_ARGUMENTS BootArguments;
|
|
|
|
CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
|
|
|
|
CHAR16 *BootDescription;
|
|
|
|
UINT32 Attributes;
|
|
|
|
BDS_LOADER_TYPE BootType;
|
|
|
|
BDS_LOAD_OPTION *BdsLoadOption;
|
|
|
|
EFI_DEVICE_PATH *DevicePath;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL *InitrdPathNode;
|
|
|
|
|
|
|
|
Attributes = 0;
|
|
|
|
SupportedBootDevice = NULL;
|
|
|
|
|
|
|
|
// List the Boot Devices supported
|
|
|
|
Status = SelectBootDevice(&SupportedBootDevice);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
// Create the specific device path node
|
2011-08-18 15:21:14 +02:00
|
|
|
Print(L"File path of the EFI Application or the kernel: ");
|
2011-06-11 13:58:23 +02:00
|
|
|
Status = SupportedBootDevice->Support->CreateDevicePathNode (SupportedBootDevice, &DevicePathNode, &BootType, &Attributes);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
// Append the Device Path node to the select device path
|
|
|
|
DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);
|
|
|
|
|
2011-08-18 15:21:14 +02:00
|
|
|
if (BootType == BDS_LOADER_KERNEL_LINUX_ATAG) {
|
|
|
|
// Create the specific device path node
|
|
|
|
Print(L"File path of the initrd: ");
|
|
|
|
Status = SupportedBootDevice->Support->CreateDevicePathNode (SupportedBootDevice, &InitrdPathNode, NULL, NULL);
|
|
|
|
if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InitrdPathNode != NULL) {
|
|
|
|
// Append the Device Path node to the select device path
|
|
|
|
BootArguments.LinuxAtagArguments.InitrdPathList = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNode);
|
|
|
|
} else {
|
|
|
|
BootArguments.LinuxAtagArguments.InitrdPathList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Print(L"Arguments to pass to the binary: ");
|
|
|
|
Status = GetHIInputAscii (BootArguments.LinuxAtagArguments.CmdLine,BOOT_DEVICE_OPTION_MAX);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto FREE_DEVICE_PATH;
|
|
|
|
}
|
|
|
|
BootArguments.LinuxAtagArguments.CmdLine[BOOT_DEVICE_OPTION_MAX]= '\0';
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Print(L"Description for this new Entry: ");
|
|
|
|
Status = GetHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto FREE_DEVICE_PATH;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert Ascii into Unicode
|
|
|
|
BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));
|
|
|
|
AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);
|
|
|
|
|
|
|
|
// Create new entry
|
2011-08-18 15:21:14 +02:00
|
|
|
Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, &BootArguments, &BdsLoadOption);
|
2011-06-11 13:58:23 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
|
|
|
InsertTailList (BootOptionsList,&BdsLoadOption->Link);
|
|
|
|
}
|
|
|
|
|
|
|
|
FreePool (BootDescription);
|
|
|
|
|
|
|
|
FREE_DEVICE_PATH:
|
|
|
|
FreePool (DevicePath);
|
|
|
|
|
2011-08-18 15:21:14 +02:00
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
EXIT:
|
2011-08-18 15:21:14 +02:00
|
|
|
if (Status == EFI_ABORTED) {
|
|
|
|
Print(L"\n");
|
|
|
|
}
|
|
|
|
FreePool(SupportedBootDevice);
|
2011-06-11 13:58:23 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
|
|
|
BootMenuSelectBootOption (
|
|
|
|
IN LIST_ENTRY *BootOptionsList,
|
|
|
|
IN CONST CHAR16* InputStatement,
|
|
|
|
OUT BDS_LOAD_OPTION **BdsLoadOption
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
LIST_ENTRY* Entry;
|
|
|
|
BDS_LOAD_OPTION *BootOption;
|
|
|
|
UINTN BootOptionSelected;
|
|
|
|
UINTN BootOptionCount;
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
// Display the list of supported boot devices
|
|
|
|
BootOptionCount = 1;
|
|
|
|
for (Entry = GetFirstNode (BootOptionsList);
|
|
|
|
!IsNull (BootOptionsList,Entry);
|
|
|
|
Entry = GetNextNode (BootOptionsList,Entry)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BootOption = LOAD_OPTION_FROM_LINK(Entry);
|
|
|
|
Print(L"[%d] %s\n",BootOptionCount,BootOption->Description);
|
|
|
|
|
|
|
|
DEBUG_CODE_BEGIN();
|
|
|
|
CHAR16* DevicePathTxt;
|
|
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
|
|
|
|
|
|
|
|
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
|
|
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
|
|
|
|
|
|
|
|
Print(L"\t- %s\n",DevicePathTxt);
|
2011-08-18 15:21:14 +02:00
|
|
|
if ((BDS_LOADER_TYPE)ReadUnaligned32(&BootOption->OptionalData->LoaderType) == BDS_LOADER_KERNEL_LINUX_ATAG) {
|
|
|
|
Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments.LinuxAtagArguments.CmdLine);
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FreePool(DevicePathTxt);
|
|
|
|
DEBUG_CODE_END();
|
|
|
|
|
|
|
|
BootOptionCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the index of the boot device to delete
|
|
|
|
BootOptionSelected = 0;
|
|
|
|
while (BootOptionSelected == 0) {
|
|
|
|
Print(InputStatement);
|
|
|
|
Status = GetHIInputInteger (&BootOptionSelected);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
return Status;
|
|
|
|
} else if ((BootOptionSelected == 0) || (BootOptionSelected >= BootOptionCount)) {
|
2011-08-18 15:21:14 +02:00
|
|
|
Print(L"Invalid input (max %d)\n",BootOptionCount-1);
|
2011-06-11 13:58:23 +02:00
|
|
|
BootOptionSelected = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the structure of the Boot device to delete
|
|
|
|
Index = 1;
|
|
|
|
for (Entry = GetFirstNode (BootOptionsList);
|
|
|
|
!IsNull (BootOptionsList,Entry);
|
|
|
|
Entry = GetNextNode (BootOptionsList,Entry)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (Index == BootOptionSelected) {
|
|
|
|
*BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootMenuRemoveBootOption (
|
|
|
|
IN LIST_ENTRY *BootOptionsList
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
BDS_LOAD_OPTION *BootOption;
|
|
|
|
|
|
|
|
Status = BootMenuSelectBootOption (BootOptionsList,L"Delete entry: ",&BootOption);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the BDS Load option structures
|
|
|
|
BootOptionDelete (BootOption);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootMenuUpdateBootOption (
|
|
|
|
IN LIST_ENTRY *BootOptionsList
|
|
|
|
)
|
|
|
|
{
|
2011-08-18 15:21:14 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
BDS_LOAD_OPTION *BootOption;
|
|
|
|
BDS_LOAD_OPTION_SUPPORT *DeviceSupport;
|
|
|
|
BDS_LOADER_ARGUMENTS BootArguments;
|
|
|
|
CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
|
|
|
|
CHAR16 *BootDescription;
|
|
|
|
EFI_DEVICE_PATH* DevicePath;
|
|
|
|
BDS_LOADER_TYPE BootType;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
Status = BootMenuSelectBootOption (BootOptionsList,L"Update entry: ",&BootOption);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the device support for this Boot Option
|
|
|
|
Status = BootDeviceGetDeviceSupport (BootOption,&DeviceSupport);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Print(L"Impossible to retrieve the supported device for the update\n");
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2011-08-18 15:21:14 +02:00
|
|
|
Print(L"File path of the EFI Application or the kernel: ");
|
|
|
|
Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, &DevicePath, NULL, NULL);
|
2011-06-11 13:58:23 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2011-08-18 15:21:14 +02:00
|
|
|
BootType = (BDS_LOADER_TYPE)ReadUnaligned32((UINT32 *)(&BootOption->OptionalData->LoaderType));
|
|
|
|
|
|
|
|
// TODO: Allow adding an initrd to a boot entry without one
|
|
|
|
if (BootType == BDS_LOADER_KERNEL_LINUX_ATAG) {
|
|
|
|
if (ReadUnaligned16(&BootOption->OptionalData->Arguments.LinuxAtagArguments.InitrdPathListLength) > 0
|
|
|
|
&& (EFI_DEVICE_PATH_PROTOCOL *)ReadUnaligned32((UINT32 *)(&BootOption->OptionalData->Arguments.LinuxAtagArguments.InitrdPathList)) != NULL) {
|
|
|
|
|
|
|
|
Print(L"File path of the initrd: ");
|
|
|
|
Status = DeviceSupport->UpdateDevicePathNode (
|
|
|
|
(EFI_DEVICE_PATH_PROTOCOL *)ReadUnaligned32((UINT32 *)(&BootOption->OptionalData->Arguments.LinuxAtagArguments.InitrdPathList)),
|
|
|
|
&BootArguments.LinuxAtagArguments.InitrdPathList,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
BootArguments.LinuxAtagArguments.InitrdPathList = NULL;
|
|
|
|
BootArguments.LinuxAtagArguments.InitrdPathListLength = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Print(L"Arguments to pass to the binary: ");
|
|
|
|
if (ReadUnaligned32((CONST UINT32*)&BootOption->OptionalData->Arguments.LinuxAtagArguments.CmdLine)) {
|
|
|
|
AsciiStrnCpy(BootArguments.LinuxAtagArguments.CmdLine,
|
|
|
|
BootOption->OptionalData->Arguments.LinuxAtagArguments.CmdLine,
|
|
|
|
BOOT_DEVICE_OPTION_MAX+1);
|
|
|
|
} else {
|
|
|
|
BootArguments.LinuxAtagArguments.CmdLine[0] = '\0';
|
|
|
|
}
|
|
|
|
Status = EditHIInputAscii (BootArguments.LinuxAtagArguments.CmdLine, BOOT_DEVICE_OPTION_MAX);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto FREE_DEVICE_PATH;
|
|
|
|
}
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Print(L"Description for this new Entry: ");
|
2011-08-18 15:21:14 +02:00
|
|
|
UnicodeStrToAsciiStr (BootOption->Description, AsciiBootDescription);
|
|
|
|
Status = EditHIInputAscii (AsciiBootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
|
2011-06-11 13:58:23 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Status = EFI_ABORTED;
|
|
|
|
goto FREE_DEVICE_PATH;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert Ascii into Unicode
|
|
|
|
BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));
|
|
|
|
AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);
|
|
|
|
|
|
|
|
// Update the entry
|
2011-08-18 15:21:14 +02:00
|
|
|
Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, &BootArguments);
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
FreePool (BootDescription);
|
|
|
|
|
|
|
|
FREE_DEVICE_PATH:
|
|
|
|
FreePool (DevicePath);
|
|
|
|
|
|
|
|
EXIT:
|
2011-08-18 13:29:26 +02:00
|
|
|
if (Status == EFI_ABORTED) {
|
|
|
|
Print(L"\n");
|
|
|
|
}
|
2011-06-11 13:58:23 +02:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct BOOT_MANAGER_ENTRY {
|
|
|
|
CONST CHAR16* Description;
|
|
|
|
EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
|
|
|
|
} BootManagerEntries[] = {
|
|
|
|
{ L"Add Boot Device Entry", BootMenuAddBootOption },
|
|
|
|
{ L"Update Boot Device Entry", BootMenuUpdateBootOption },
|
|
|
|
{ L"Remove Boot Device Entry", BootMenuRemoveBootOption },
|
|
|
|
};
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootMenuManager (
|
|
|
|
IN LIST_ENTRY *BootOptionsList
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
UINTN OptionSelected;
|
|
|
|
UINTN BootManagerEntryCount;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
// Display Boot Manager menu
|
|
|
|
for (Index = 0; Index < BootManagerEntryCount; Index++) {
|
|
|
|
Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);
|
|
|
|
}
|
|
|
|
Print(L"[%d] Return to main menu\n",Index+1);
|
|
|
|
|
|
|
|
// Select which entry to call
|
|
|
|
Print(L"Choice: ");
|
|
|
|
Status = GetHIInputInteger (&OptionSelected);
|
|
|
|
if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {
|
2011-08-18 13:29:26 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
Print(L"\n");
|
|
|
|
}
|
2011-06-11 13:58:23 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
} else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {
|
|
|
|
Status = BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootEBL (
|
|
|
|
IN LIST_ENTRY *BootOptionsList
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
// Start EFI Shell
|
|
|
|
Status = BdsLoadApplication(mImageHandle, L"Ebl");
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
|
|
Print (L"Error: EFI Application not found.\n");
|
|
|
|
} else if (EFI_ERROR(Status)) {
|
|
|
|
Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct BOOT_MAIN_ENTRY {
|
|
|
|
CONST CHAR16* Description;
|
|
|
|
EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
|
|
|
|
} BootMainEntries[] = {
|
|
|
|
{ L"EBL", BootEBL },
|
|
|
|
{ L"Boot Manager", BootMenuManager },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2011-06-15 21:53:15 +02:00
|
|
|
BootOption = NULL;
|
2011-06-11 13:58:23 +02:00
|
|
|
BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
|
2011-07-06 18:07:54 +02:00
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
// Get Boot#### list
|
|
|
|
BootOptionList (&BootOptionsList);
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
|
2011-06-28 13:50:32 +02:00
|
|
|
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;
|
|
|
|
}
|
2011-06-11 13:58:23 +02:00
|
|
|
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
|
|
|
|
|
|
|
|
Print(L"\t- %s\n",DevicePathTxt);
|
2011-08-18 15:21:14 +02:00
|
|
|
if (ReadUnaligned32(&BootOption->OptionalData->LoaderType) == BDS_LOADER_KERNEL_LINUX_ATAG) {
|
|
|
|
if (ReadUnaligned16(&BootOption->OptionalData->Arguments.LinuxAtagArguments.InitrdPathListLength) > 0
|
|
|
|
&& (EFI_DEVICE_PATH_PROTOCOL *)ReadUnaligned32((UINT32 *)(&BootOption->OptionalData->Arguments.LinuxAtagArguments.InitrdPathList)) != NULL) {
|
|
|
|
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL *)ReadUnaligned32((UINT32 *)(&BootOption->OptionalData->Arguments.LinuxAtagArguments.InitrdPathList)),TRUE,TRUE);
|
|
|
|
Print(L"\t- Initrd: %s\n", DevicePathTxt);
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
2011-08-18 15:21:14 +02:00
|
|
|
|
|
|
|
Print(L"\t- Arguments: %a\n", BootOption->OptionalData->Arguments.LinuxAtagArguments.CmdLine);
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
|
2011-08-18 15:21:14 +02:00
|
|
|
Print(L"\t- LoaderType: %d\n", ReadUnaligned32 (&BootOption->OptionalData->LoaderType));
|
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|