ArmPlatformPkg/Bds: Upgrade the BDS to be more conformed to the UEFI Specification

The UEFI Specification defines some requirement related to the Boot Manager.
This new version of the BDS support most of the features:
- TimeOut, BootNext, BootOrder, Boot### environment variable for boot device selection
- ConOut. ConIn, ConErr environment variables for console intialization
- Boot EFI application defined by a Device Path
- Support removable devices
- Support FileSystem, MemMap, PXE and TFTP boot devices



git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11800 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
oliviermartin 2011-06-11 11:58:23 +00:00
parent a355a3654f
commit ea46ebbe6a
12 changed files with 2746 additions and 351 deletions

View File

@ -71,3 +71,24 @@
gArmPlatformTokenSpaceGuid.PcdSP804FrequencyInMHz|1|UINT32|0x0000001D
gArmPlatformTokenSpaceGuid.PcdSP804Timer0InterruptNum|0|UINT32|0x0000001E
#
# BDS - Boot Manager
#
gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM Platform"|VOID*|0x00000019
gArmPlatformTokenSpaceGuid.PcdDefaultBootDescription|L""|VOID*|0x0000000C
gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath|L""|VOID*|0x0000000D
gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|""|VOID*|0x000000F
# PcdDefaultBootType define the type of the binary pointed by PcdDefaultBootDevicePath:
# - 0 = an EFI application
# - 1 = a Linux kernel with ATAG support
# - 2 = a Linux kernel with FDT support
gArmPlatformTokenSpaceGuid.PcdDefaultBootType|0|UINT32|0x00000010
gArmPlatformTokenSpaceGuid.PcdFdtDevicePath|L""|VOID*|0x00000011
## Timeout value for displaying progressing bar in before boot OS.
# According to UEFI 2.0 spec, the default TimeOut should be 0xffff.
gArmPlatformTokenSpaceGuid.PcdPlatformBootTimeOut|0xffff|UINT16|0x0000001A
gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths|L""|VOID*|0x0000001B
gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths|L""|VOID*|0x0000001C

View File

@ -262,6 +262,8 @@
!endif
[PcdsFixedAtBuild.common]
gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM RealView Emulation Board"
gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"ArmRealViewEb-A8"
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0
@ -381,11 +383,11 @@
#
# ARM OS Loader
#
# Versatile Express machine type (ARM VERSATILE EXPRESS = 2272) required for ARM Linux:
gArmTokenSpaceGuid.PcdArmMachineType|2272
gArmTokenSpaceGuid.PcdLinuxKernelDP|L"VenHw(02118005-9DA7-443a-92D5-781F022AEDBB)/MemoryMapped(0,0x46000000,0x46400000)"
gArmTokenSpaceGuid.PcdLinuxAtag|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=1G"
gArmTokenSpaceGuid.PcdFdtDP|L""
gArmTokenSpaceGuid.PcdArmMachineType|827
gArmPlatformTokenSpaceGuid.PcdDefaultBootDescription|L"SemiHosting"
gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath|L"VenHw(C5B9C74A-6D72-4719-99AB-C59F199091EB)/zImage-RTSM"
gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=128M"
gArmPlatformTokenSpaceGuid.PcdDefaultBootType|1
#
# ARM L2x0 PCDs

View File

@ -264,6 +264,8 @@
!endif
[PcdsFixedAtBuild.common]
gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM RealView Emulation Board"
gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"ArmRealViewEb-A9x2"
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0
@ -385,11 +387,11 @@
#
# ARM OS Loader
#
# Versatile Express machine type (ARM VERSATILE EXPRESS = 2272) required for ARM Linux:
gArmTokenSpaceGuid.PcdArmMachineType|2272
gArmTokenSpaceGuid.PcdLinuxKernelDP|L"VenHw(02118005-9DA7-443a-92D5-781F022AEDBB)/MemoryMapped(0,0x46000000,0x46400000)"
gArmTokenSpaceGuid.PcdLinuxAtag|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=1G"
gArmTokenSpaceGuid.PcdFdtDP|L""
gArmTokenSpaceGuid.PcdArmMachineType|827
gArmPlatformTokenSpaceGuid.PcdDefaultBootDescription|L"SemiHosting"
gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath|L"VenHw(C5B9C74A-6D72-4719-99AB-C59F199091EB)/zImage"
gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=128M"
gArmPlatformTokenSpaceGuid.PcdDefaultBootType|1
#
# ARM L2x0 PCDs

View File

@ -285,6 +285,8 @@
!endif
[PcdsFixedAtBuild.common]
gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM Versatile Express"
gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"ArmVExpress"
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0
@ -411,9 +413,10 @@
#
# Versatile Express machine type (ARM VERSATILE EXPRESS = 2272) required for ARM Linux:
gArmTokenSpaceGuid.PcdArmMachineType|2272
gArmTokenSpaceGuid.PcdLinuxKernelDP|L"VenHw(02118005-9DA7-443a-92D5-781F022AEDBB)/MemoryMapped(0,0x46000000,0x46400000)"
gArmTokenSpaceGuid.PcdLinuxAtag|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=1G"
gArmTokenSpaceGuid.PcdFdtDP|L""
gArmPlatformTokenSpaceGuid.PcdDefaultBootDescription|L"NorFlash"
gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath|L"VenHw(1F15DA3C-37FF-4070-B471-BB4AF12A724A)/MemoryMapped(0x0,0x46000000,0x46400000)"
gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=1G"
gArmPlatformTokenSpaceGuid.PcdDefaultBootType|1
#
# ARM L2x0 PCDs

398
ArmPlatformPkg/Bds/Bds.c Normal file
View File

@ -0,0 +1,398 @@
/** @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"
#include <Library/PcdLib.h>
#include <Library/PerformanceLib.h>
#include <Protocol/Bds.h>
#define EFI_SET_TIMER_TO_SECOND 10000000
EFI_HANDLE mImageHandle;
STATIC
EFI_STATUS
GetConsoleDevicePathFromVariable (
IN CHAR16* ConsoleVarName,
IN CHAR16* DefaultConsolePaths,
OUT EFI_DEVICE_PATH** DevicePaths
)
{
EFI_STATUS Status;
UINTN Size;
EFI_DEVICE_PATH_PROTOCOL* DevicePathInstances;
EFI_DEVICE_PATH_PROTOCOL* DevicePathInstance;
CHAR16* DevicePathStr;
CHAR16* NextDevicePathStr;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
Status = GetEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);
if (EFI_ERROR(Status)) {
Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
ASSERT_EFI_ERROR(Status);
DevicePathInstances = NULL;
// Extract the Device Path instances from the multi-device path string
while ((DefaultConsolePaths != NULL) && (DefaultConsolePaths[0] != L'\0')) {
NextDevicePathStr = StrStr (DefaultConsolePaths, L";");
if (NextDevicePathStr == NULL) {
DevicePathStr = DefaultConsolePaths;
DefaultConsolePaths = NULL;
} else {
DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DefaultConsolePaths + 1) * sizeof(CHAR16), DefaultConsolePaths);
*(DevicePathStr + (NextDevicePathStr - DefaultConsolePaths)) = L'\0';
DefaultConsolePaths = NextDevicePathStr;
if (DefaultConsolePaths[0] == L';') {
DefaultConsolePaths++;
}
}
DevicePathInstance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
ASSERT(DevicePathInstance != NULL);
DevicePathInstances = AppendDevicePathInstance (DevicePathInstances, DevicePathInstance);
if (NextDevicePathStr != NULL) {
FreePool (DevicePathStr);
}
FreePool (DevicePathInstance);
}
// Set the environment variable with this device path multi-instances
Size = GetDevicePathSize (DevicePathInstances);
if (Size > 0) {
Status = gRT->SetVariable (
ConsoleVarName,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
Size,
DevicePathInstances
);
} else {
Status = EFI_INVALID_PARAMETER;
}
}
if (!EFI_ERROR(Status)) {
*DevicePaths = DevicePathInstances;
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
InitializeConsolePipe (
IN EFI_DEVICE_PATH *ConsoleDevicePaths,
IN EFI_GUID *Protocol,
OUT EFI_HANDLE *Handle,
OUT VOID* *Interface
)
{
EFI_STATUS Status;
UINTN Size;
UINTN NoHandles;
EFI_HANDLE *Buffer;
EFI_DEVICE_PATH_PROTOCOL* DevicePath;
// Connect all the Device Path Consoles
do {
DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size);
Status = BdsConnectDevicePath (DevicePath, Handle, NULL);
DEBUG_CODE_BEGIN();
if (EFI_ERROR(Status)) {
// We convert back to the text representation of the device Path
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
CHAR16* DevicePathTxt;
ASSERT_EFI_ERROR(gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol));
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);
DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status));
FreePool (DevicePathTxt);
}
DEBUG_CODE_END();
// If the console splitter driver is not supported by the platform then use the first Device Path
// instance for the console interface.
if (!EFI_ERROR(Status) && (*Interface == NULL)) {
Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
}
} while (ConsoleDevicePaths != NULL);
// No Device Path has been defined for this console interface. We take the first protocol implementation
if (*Interface == NULL) {
Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
if (EFI_ERROR (Status)) {
BdsConnectAllDrivers();
Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
}
if (!EFI_ERROR(Status)) {
*Handle = Buffer[0];
Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
ASSERT_EFI_ERROR(Status);
}
FreePool (Buffer);
} else {
Status = EFI_SUCCESS;
}
return Status;
}
EFI_STATUS
InitializeConsole (
VOID
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH* ConOutDevicePaths;
EFI_DEVICE_PATH* ConInDevicePaths;
EFI_DEVICE_PATH* ConErrDevicePaths;
// By getting the Console Device Paths from the environment variables before initializing the console pipe, we
// create the 3 environment variables (ConIn, ConOut, ConErr) that allows to initialize all the console interface
// of newly installed console drivers
Status = GetConsoleDevicePathFromVariable (L"ConOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths),&ConOutDevicePaths);
ASSERT_EFI_ERROR (Status);
Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths),&ConInDevicePaths);
ASSERT_EFI_ERROR (Status);
Status = GetConsoleDevicePathFromVariable (L"ConErr", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths),&ConErrDevicePaths);
ASSERT_EFI_ERROR (Status);
// Initialize the Consoles
Status = InitializeConsolePipe (ConOutDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut);
ASSERT_EFI_ERROR (Status);
Status = InitializeConsolePipe (ConInDevicePaths, &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn);
ASSERT_EFI_ERROR (Status);
Status = InitializeConsolePipe (ConErrDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr);
if (EFI_ERROR(Status)) {
// In case of error, we reuse the console output for the error output
gST->StandardErrorHandle = gST->ConsoleOutHandle;
gST->StdErr = gST->ConOut;
}
return EFI_SUCCESS;
}
EFI_STATUS
DefineDefaultBootEntries (
VOID
)
{
BDS_LOAD_OPTION *BdsLoadOption;
UINTN Size;
EFI_STATUS Status;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
EFI_DEVICE_PATH* BootDevicePath;
//
// If Boot Order does not exist then create a default entry
//
Size = 0;
Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);
if (Status == EFI_NOT_FOUND) {
Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
ASSERT_EFI_ERROR(Status);
BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath));
DEBUG_CODE_BEGIN();
// We convert back to the text representation of the device Path to see if the initial text is correct
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
CHAR16* DevicePathTxt;
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
ASSERT_EFI_ERROR(Status);
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE);
ASSERT (StrCmp ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath), DevicePathTxt) == 0);
FreePool (DevicePathTxt);
DEBUG_CODE_END();
// Create the entry is the Default values are correct
if (BootDevicePath != NULL) {
BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
(CHAR16*)PcdGetPtr(PcdDefaultBootDescription),
BootDevicePath,
(BDS_LOADER_TYPE)PcdGet32 (PcdDefaultBootType),
(CHAR8*)PcdGetPtr(PcdDefaultBootArgument),
&BdsLoadOption
);
FreePool (BdsLoadOption);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
StartDefaultBootOnTimeout (
VOID
)
{
UINTN Size;
UINT16 Timeout;
UINT16 *TimeoutPtr;
EFI_EVENT WaitList[2];
UINTN WaitIndex;
UINT16 *BootOrder;
UINTN BootOrderSize;
UINTN Index;
CHAR16 BootVariableName[9];
EFI_STATUS Status;
Size = sizeof(UINT16);
Timeout = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);
TimeoutPtr = &Timeout;
GetEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);
if (Timeout != 0xFFFF) {
if (Timeout > 0) {
// Create the waiting events (keystroke and 1sec timer)
gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[0]);
gBS->SetTimer (WaitList[0], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);
WaitList[1] = gST->ConIn->WaitForKey;
// Start the timer
WaitIndex = 0;
Print(L"The default boot selection will start in ");
while ((Timeout > 0) && (WaitIndex == 0)) {
Print(L"%3d seconds",Timeout);
gBS->WaitForEvent (2, WaitList, &WaitIndex);
if (WaitIndex == 0) {
Print(L"\b\b\b\b\b\b\b\b\b\b\b");
Timeout--;
}
}
gBS->CloseEvent (WaitList[0]);
Print(L"\n\r");
}
// In case of Timeout we start the default boot selection
if (Timeout == 0) {
// Get the Boot Option Order from the environment variable (a default value should have been created)
GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOrder[Index]);
Status = BdsStartBootOption (BootVariableName);
if(!EFI_ERROR(Status)){
// Boot option returned successfully, hence don't need to start next boot option
break;
}
// In case of success, we should not return from this call.
}
}
}
return EFI_SUCCESS;
}
/**
This function uses policy data from the platform to determine what operating
system or system utility should be loaded and invoked. This function call
also optionally make the use of user input to determine the operating system
or system utility to be loaded and invoked. When the DXE Core has dispatched
all the drivers on the dispatch queue, this function is called. This
function will attempt to connect the boot devices required to load and invoke
the selected operating system or system utility. During this process,
additional firmware volumes may be discovered that may contain addition DXE
drivers that can be dispatched by the DXE Core. If a boot device cannot be
fully connected, this function calls the DXE Service Dispatch() to allow the
DXE drivers from any newly discovered firmware volumes to be dispatched.
Then the boot device connection can be attempted again. If the same boot
device connection operation fails twice in a row, then that boot device has
failed, and should be skipped. This function should never return.
@param This The EFI_BDS_ARCH_PROTOCOL instance.
@return None.
**/
VOID
EFIAPI
BdsEntry (
IN EFI_BDS_ARCH_PROTOCOL *This
)
{
UINTN Size;
EFI_STATUS Status;
PERF_END (NULL, "DXE", NULL, 0);
//
// Declare the Firmware Vendor
//
Size = 0x100;
gST->FirmwareVendor = AllocateRuntimePool (Size);
ASSERT (gST->FirmwareVendor != NULL);
UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__);
// If BootNext environment variable is defined then we just load it !
Status = BdsStartBootOption (L"BootNext");
if (Status != EFI_NOT_FOUND) {
// BootNext has not been succeeded launched
if (EFI_ERROR(Status)) {
Print(L"Fail to start BootNext.\n");
}
// Delete the BootNext environment variable
gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
0, NULL);
}
// If Boot Order does not exist then create a default entry
DefineDefaultBootEntries ();
// Now we need to setup the EFI System Table with information about the console devices.
InitializeConsole ();
// Timer before initiating the default boot selection
StartDefaultBootOnTimeout ();
// Start the Boot Menu
Status = BootMenuMain ();
ASSERT_EFI_ERROR (Status);
}
EFI_BDS_ARCH_PROTOCOL gBdsProtocol = {
BdsEntry,
};
EFI_STATUS
EFIAPI
BdsInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
mImageHandle = ImageHandle;
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiBdsArchProtocolGuid, &gBdsProtocol,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@ -2,7 +2,7 @@
#
# Component discription file for NorFlashDxe module
#
# Copyright (c) 2010, ARM Ltd. All rights reserved.<BR>
# Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
# 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
@ -24,30 +24,49 @@
ENTRY_POINT = BdsInitialize
[Sources.common]
BdsEntry.c
Bds.c
BdsHelper.c
BootMenu.c
BootOption.c
BootOptionSupport.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
ArmPkg/ArmPkg.dec
ArmPlatformPkg/ArmPlatformPkg.dec
[LibraryClasses]
BdsLib
TimerLib
PerformanceLib
UefiBootServicesTableLib
DxeServicesTableLib
UefiDriverEntryPoint
DebugLib
PrintLib
[Guids]
gEfiFileSystemInfoGuid
[Protocols]
gEfiBdsArchProtocolGuid
gEfiBlockIoProtocolGuid
gEfiSimpleTextInProtocolGuid
gEfiPxeBaseCodeProtocolGuid
gEfiSimpleNetworkProtocolGuid
gEfiDevicePathToTextProtocolGuid
[Pcd]
gArmTokenSpaceGuid.PcdLinuxKernelDP
gArmTokenSpaceGuid.PcdLinuxAtag
gArmTokenSpaceGuid.PcdFdtDP
gArmPlatformTokenSpaceGuid.PcdFirmwareVendor
gArmPlatformTokenSpaceGuid.PcdDefaultBootDescription
gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath
gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument
gArmPlatformTokenSpaceGuid.PcdDefaultBootType
gArmPlatformTokenSpaceGuid.PcdFdtDevicePath
gArmPlatformTokenSpaceGuid.PcdPlatformBootTimeOut
gArmPlatformTokenSpaceGuid.PcdDefaultConInPaths
gArmPlatformTokenSpaceGuid.PcdDefaultConOutPaths
[Depex]
TRUE

View File

@ -1,332 +0,0 @@
/** @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 <PiDxe.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/PerformanceLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/PcdLib.h>
#include <Library/BdsUnixLib.h>
#include <Protocol/Bds.h>
#include <Protocol/DevicePathToText.h>
#include <Guid/GlobalVariable.h>
#define MAX_CMD_LINE 256
VOID
EFIAPI
BdsEntry (
IN EFI_BDS_ARCH_PROTOCOL *This
);
EFI_HANDLE mBdsImageHandle = NULL;
EFI_BDS_ARCH_PROTOCOL gBdsProtocol = {
BdsEntry,
};
EFI_STATUS GetEnvironmentVariable (
IN CONST CHAR16* VariableName,
IN VOID* DefaultValue,
IN UINTN DefaultSize,
OUT VOID** Value)
{
EFI_STATUS Status;
UINTN Size;
// Try to get the variable size.
*Value = NULL;
Size = 0;
Status = gRT->GetVariable ((CHAR16 *) VariableName, &gEfiGlobalVariableGuid, NULL, &Size, *Value);
if (Status == EFI_NOT_FOUND) {
// If the environment variable does not exist yet then set it with the default value
Status = gRT->SetVariable (
(CHAR16*)VariableName,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
DefaultSize,
DefaultValue
);
*Value = DefaultValue;
} else if (Status == EFI_BUFFER_TOO_SMALL) {
// Get the environment variable value
*Value = AllocatePool (Size);
if (*Value == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gRT->GetVariable ((CHAR16 *)VariableName, &gEfiGlobalVariableGuid, NULL, &Size, *Value);
if (EFI_ERROR (Status)) {
FreePool(*Value);
return EFI_INVALID_PARAMETER;
}
} else {
*Value = DefaultValue;
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
InitializeConsole (
VOID
)
{
EFI_STATUS Status;
UINTN NoHandles;
EFI_HANDLE *Buffer;
BOOLEAN AllDriversConnected;
AllDriversConnected = FALSE;
//
// Now we need to setup the EFI System Table with information about the console devices.
// This code is normally in the console spliter driver on platforms that support multiple
// consoles at the same time
//
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer);
if (EFI_ERROR (Status)) {
BdsConnectAllDrivers();
AllDriversConnected = TRUE;
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer);
}
if (!EFI_ERROR (Status)) {
// Use the first SimpleTextOut we find and update the EFI System Table
gST->ConsoleOutHandle = Buffer[0];
gST->StandardErrorHandle = Buffer[0];
Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextOutProtocolGuid, (VOID **)&gST->ConOut);
ASSERT_EFI_ERROR (Status);
gST->StdErr = gST->ConOut;
FreePool (Buffer);
} else {
return Status;
}
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer);
if (EFI_ERROR (Status) && !AllDriversConnected) {
BdsConnectAllDrivers();
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer);
}
if (!EFI_ERROR (Status)) {
// Use the first SimpleTextIn we find and update the EFI System Table
gST->ConsoleInHandle = Buffer[0];
Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextInProtocolGuid, (VOID **)&gST->ConIn);
ASSERT_EFI_ERROR (Status);
FreePool (Buffer);
} else {
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
GetHIInputAscii (
CHAR8 *CmdLine,
UINTN MaxCmdLine
) {
UINTN CmdLineIndex;
UINTN WaitIndex;
CHAR8 Char;
EFI_INPUT_KEY Key;
EFI_STATUS Status;
CmdLine[0] = '\0';
for (CmdLineIndex = 0; CmdLineIndex < MaxCmdLine; ) {
Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
ASSERT_EFI_ERROR (Status);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
ASSERT_EFI_ERROR (Status);
Char = (CHAR8)Key.UnicodeChar;
if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) {
CmdLine[CmdLineIndex] = '\0';
AsciiPrint ("\n");
return EFI_SUCCESS;
} else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
if (CmdLineIndex != 0) {
CmdLineIndex--;
AsciiPrint ("\b \b");
}
} else {
CmdLine[CmdLineIndex++] = Char;
AsciiPrint ("%c", Char);
}
}
return EFI_SUCCESS;
}
VOID
ListDevicePaths (
IN BOOLEAN AllDrivers
) {
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
CHAR16* String;
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* EfiDevicePathToTextProtocol;
if (AllDrivers) {
BdsConnectAllDrivers();
}
Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&EfiDevicePathToTextProtocol);
if (EFI_ERROR (Status)) {
AsciiPrint ("Did not find the DevicePathToTextProtocol.\n");
return;
}
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
AsciiPrint ("No device path found\n");
return;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
String = EfiDevicePathToTextProtocol->ConvertDevicePathToText(DevicePathProtocol,TRUE,TRUE);
Print (L"\t- [%d] %s\n",Index, String);
}
}
INTN BdsComparefile (
IN CHAR16 *DeviceFilePath1,
IN CHAR16 *DeviceFilePath2,
VOID **FileImage1,VOID **FileImage2,UINTN* FileSize
);
/**
This function uses policy data from the platform to determine what operating
system or system utility should be loaded and invoked. This function call
also optionally make the use of user input to determine the operating system
or system utility to be loaded and invoked. When the DXE Core has dispatched
all the drivers on the dispatch queue, this function is called. This
function will attempt to connect the boot devices required to load and invoke
the selected operating system or system utility. During this process,
additional firmware volumes may be discovered that may contain addition DXE
drivers that can be dispatched by the DXE Core. If a boot device cannot be
fully connected, this function calls the DXE Service Dispatch() to allow the
DXE drivers from any newly discovered firmware volumes to be dispatched.
Then the boot device connection can be attempted again. If the same boot
device connection operation fails twice in a row, then that boot device has
failed, and should be skipped. This function should never return.
@param This The EFI_BDS_ARCH_PROTOCOL instance.
@return None.
**/
VOID
EFIAPI
BdsEntry (
IN EFI_BDS_ARCH_PROTOCOL *This
)
{
EFI_STATUS Status;
CHAR8 CmdLine[MAX_CMD_LINE];
VOID* DefaultVariableValue;
UINTN DefaultVariableSize;
CHAR16 *LinuxKernelDP;
CHAR8 *LinuxAtag;
CHAR16 *FdtDP;
PERF_END (NULL, "DXE", NULL, 0);
PERF_START (NULL, "BDS", NULL, 0);
Status = InitializeConsole();
ASSERT_EFI_ERROR(Status);
while (1) {
// Get the Linux Kernel Device Path from Environment Variable
DefaultVariableValue = (VOID*)PcdGetPtr(PcdLinuxKernelDP);
DefaultVariableSize = StrSize((CHAR16*)DefaultVariableValue);
GetEnvironmentVariable(L"LinuxKernelDP",DefaultVariableValue,DefaultVariableSize,(VOID**)&LinuxKernelDP);
// Get the Linux ATAG from Environment Variable
DefaultVariableValue = (VOID*)PcdGetPtr(PcdLinuxAtag);
DefaultVariableSize = AsciiStrSize((CHAR8*)DefaultVariableValue);
GetEnvironmentVariable(L"LinuxAtag",DefaultVariableValue,DefaultVariableSize,(VOID**)&LinuxAtag);
// Get the FDT Device Path from Environment Variable
DefaultVariableValue = (VOID*)PcdGetPtr(PcdFdtDP);
DefaultVariableSize = StrSize((CHAR16*)DefaultVariableValue);
GetEnvironmentVariable(L"FdtDP",DefaultVariableValue,DefaultVariableSize,(VOID**)&FdtDP);
AsciiPrint ("1. Start EBL\n\r");
AsciiPrint ("2. List Device Paths of all the drivers\n");
AsciiPrint ("3. Start Linux\n");
Print (L"\t- Kernel: %s\n", LinuxKernelDP);
AsciiPrint ("\t- Atag: %a\n", LinuxAtag);
Print (L"\t- Fdt: %s\n", FdtDP);
AsciiPrint ("Choice: ");
Status = GetHIInputAscii(CmdLine,MAX_CMD_LINE);
ASSERT_EFI_ERROR (Status);
if (AsciiStrCmp(CmdLine,"1") == 0) {
// Start EBL
Status = BdsLoadApplication(L"Ebl");
if (Status == EFI_NOT_FOUND) {
AsciiPrint ("Error: EFI Application not found.\n");
} else {
AsciiPrint ("Error: Status Code: 0x%X\n",(UINT32)Status);
}
} else if (AsciiStrCmp(CmdLine,"2") == 0) {
ListDevicePaths (TRUE);
} else if (AsciiStrCmp(CmdLine,"3") == 0) {
// Start Linux Kernel
Status = BdsBootLinux(LinuxKernelDP,LinuxAtag,FdtDP);
if (EFI_ERROR(Status)) {
AsciiPrint ("Error: Fail to start Linux (0x%X)\n",(UINT32)Status);
}
} else {
AsciiPrint ("Error: Invalid choice.\n");
}
}
}
EFI_STATUS
EFIAPI
BdsInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
mBdsImageHandle = ImageHandle;
Status = gBS->InstallMultipleProtocolInterfaces (
&mBdsImageHandle,
&gEfiBdsArchProtocolGuid, &gBdsProtocol,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@ -0,0 +1,307 @@
/** @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"
EFI_STATUS
GetEnvironmentVariable (
IN CONST CHAR16* VariableName,
IN VOID* DefaultValue,
IN OUT UINTN* Size,
OUT VOID** Value
)
{
EFI_STATUS Status;
UINTN VariableSize;
// Try to get the variable size.
*Value = NULL;
VariableSize = 0;
Status = gRT->GetVariable ((CHAR16 *) VariableName, &gEfiGlobalVariableGuid, NULL, &VariableSize, *Value);
if (Status == EFI_NOT_FOUND) {
if ((DefaultValue != NULL) && (Size != NULL) && (*Size != 0)) {
// If the environment variable does not exist yet then set it with the default value
Status = gRT->SetVariable (
(CHAR16*)VariableName,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
*Size,
DefaultValue
);
*Value = DefaultValue;
} else {
return EFI_NOT_FOUND;
}
} else if (Status == EFI_BUFFER_TOO_SMALL) {
// Get the environment variable value
*Value = AllocatePool (VariableSize);
if (*Value == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gRT->GetVariable ((CHAR16 *)VariableName, &gEfiGlobalVariableGuid, NULL, &VariableSize, *Value);
if (EFI_ERROR (Status)) {
FreePool(*Value);
return EFI_INVALID_PARAMETER;
}
if (Size) {
*Size = VariableSize;
}
} else {
*Value = DefaultValue;
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
EditHIInputAscii (
IN OUT CHAR8 *CmdLine,
IN UINTN MaxCmdLine
)
{
UINTN CmdLineIndex;
UINTN WaitIndex;
CHAR8 Char;
EFI_INPUT_KEY Key;
EFI_STATUS Status;
AsciiPrint (CmdLine);
for (CmdLineIndex = AsciiStrLen(CmdLine); CmdLineIndex < MaxCmdLine; ) {
Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
ASSERT_EFI_ERROR (Status);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
ASSERT_EFI_ERROR (Status);
// Unicode character is valid when Scancode is NUll
if (Key.ScanCode == SCAN_NULL) {
// Scan code is NUll, hence read Unicode character
Char = (CHAR8)Key.UnicodeChar;
} else {
Char = CHAR_NULL;
}
if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {
CmdLine[CmdLineIndex] = '\0';
AsciiPrint ("\n\r");
return EFI_SUCCESS;
} else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
if (CmdLineIndex != 0) {
CmdLineIndex--;
AsciiPrint ("\b \b");
}
} else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {
return EFI_INVALID_PARAMETER;
} else {
CmdLine[CmdLineIndex++] = Char;
AsciiPrint ("%c", Char);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
GetHIInputAscii (
IN OUT CHAR8 *CmdLine,
IN UINTN MaxCmdLine
)
{
// For a new input just passed an empty string
CmdLine[0] = '\0';
return EditHIInputAscii (CmdLine,MaxCmdLine);
}
EFI_STATUS
GetHIInputInteger (
OUT UINTN *Integer
)
{
CHAR8 CmdLine[255];
EFI_STATUS Status;
CmdLine[0] = '\0';
Status = EditHIInputAscii (CmdLine,255);
if (!EFI_ERROR(Status)) {
*Integer = AsciiStrDecimalToUintn (CmdLine);
}
return Status;
}
EFI_STATUS
GetHIInputIP (
OUT EFI_IP_ADDRESS *Ip
)
{
CHAR8 CmdLine[255];
CHAR8 *Str;
EFI_STATUS Status;
CmdLine[0] = '\0';
Status = EditHIInputAscii (CmdLine,255);
if (!EFI_ERROR(Status)) {
Str = CmdLine;
Ip->v4.Addr[0] = (UINT8)AsciiStrDecimalToUintn (Str);
Str = AsciiStrStr (Str, ".");
if (Str == NULL) {
return EFI_INVALID_PARAMETER;
}
Ip->v4.Addr[1] = (UINT8)AsciiStrDecimalToUintn (++Str);
Str = AsciiStrStr (Str, ".");
if (Str == NULL) {
return EFI_INVALID_PARAMETER;
}
Ip->v4.Addr[2] = (UINT8)AsciiStrDecimalToUintn (++Str);
Str = AsciiStrStr (Str, ".");
if (Str == NULL) {
return EFI_INVALID_PARAMETER;
}
Ip->v4.Addr[3] = (UINT8)AsciiStrDecimalToUintn (++Str);
}
return Status;
}
EFI_STATUS
GetHIInputBoolean (
OUT BOOLEAN *Value
)
{
CHAR8 CmdBoolean[2];
EFI_STATUS Status;
while(1) {
Print (L"[y/n] ");
Status = GetHIInputAscii (CmdBoolean,2);
if (EFI_ERROR(Status)) {
return Status;
} else if ((CmdBoolean[0] == 'y') || (CmdBoolean[0] == 'Y')) {
if (Value) *Value = TRUE;
return EFI_SUCCESS;
} else if ((CmdBoolean[0] == 'n') || (CmdBoolean[0] == 'N')) {
if (Value) *Value = FALSE;
return EFI_SUCCESS;
}
}
}
BOOLEAN
HasFilePathEfiExtension (
IN CHAR16* FilePath
)
{
return (StrCmp (FilePath + (StrSize(FilePath)/sizeof(CHAR16)) - 5, L".efi") == 0);
}
// Return the last non end-type Device Path Node from a Device Path
EFI_DEVICE_PATH*
GetLastDevicePathNode (
IN EFI_DEVICE_PATH* DevicePath
)
{
EFI_DEVICE_PATH* PrevDevicePathNode;
PrevDevicePathNode = DevicePath;
while (!IsDevicePathEndType (DevicePath)) {
PrevDevicePathNode = DevicePath;
DevicePath = NextDevicePathNode (DevicePath);
}
return PrevDevicePathNode;
}
EFI_STATUS
GenerateDeviceDescriptionName (
IN EFI_HANDLE Handle,
IN OUT CHAR16* Description
)
{
EFI_STATUS Status;
EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
CHAR16* DriverName;
CHAR16* DevicePathTxt;
EFI_DEVICE_PATH* DevicePathNode;
ComponentName2Protocol = NULL;
Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);
if (!EFI_ERROR(Status)) {
//TODO: Fixme. we must find the best langague
Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);
if (!EFI_ERROR(Status)) {
StrnCpy (Description,DriverName,BOOT_DEVICE_DESCRIPTION_MAX);
}
}
if (EFI_ERROR(Status)) {
// Use the lastest non null entry of the Device path as a description
Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
if (EFI_ERROR(Status)) {
return Status;
}
// Convert the last non end-type Device Path Node in text for the description
DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);
Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
ASSERT_EFI_ERROR(Status);
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathNode,TRUE,TRUE);
StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);
FreePool (DevicePathTxt);
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsStartBootOption (
IN CHAR16* BootOption
)
{
EFI_STATUS Status;
EFI_LOAD_OPTION EfiLoadOption;
UINTN EfiLoadOptionSize;
BDS_LOAD_OPTION *BdsLoadOption;
Status = GetEnvironmentVariable (BootOption, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
if (!EFI_ERROR(Status)) {
Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, &BdsLoadOption);
if (!EFI_ERROR(Status)) {
Status = BootOptionStart (BdsLoadOption);
FreePool (BdsLoadOption);
}
if (!EFI_ERROR(Status)) {
Status = EFI_SUCCESS;
} else {
Status = EFI_NOT_STARTED;
}
} else {
Status = EFI_NOT_FOUND;
}
return Status;
}

View File

@ -0,0 +1,214 @@
/** @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.
*
**/
#ifndef _BDSINTERNAL_H_
#define _BDSINTERNAL_H_
#include <PiDxe.h>
#include <Library/BaseMemoryLib.h>
#include <Library/BdsLib.h>
#include <Library/BdsUnixLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/PcdLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/DevicePathFromText.h>
#include <Protocol/DevicePathToText.h>
#include <Guid/GlobalVariable.h>
#define BOOT_DEVICE_DESCRIPTION_MAX 100
#define BOOT_DEVICE_FILEPATH_MAX 100
#define BOOT_DEVICE_OPTION_MAX 100
#define BOOT_DEVICE_ADDRESS_MAX 20
typedef enum {
BDS_LOADER_EFI_APPLICATION = 0,
BDS_LOADER_KERNEL_LINUX_ATAG,
BDS_LOADER_KERNEL_LINUX_FDT,
} BDS_LOADER_TYPE;
typedef struct {
BDS_LOADER_TYPE LoaderType;
CHAR8 Arguments[];
} BDS_LOADER_OPTIONAL_DATA;
typedef enum {
BDS_DEVICE_FILESYSTEM = 0,
BDS_DEVICE_MEMMAP,
BDS_DEVICE_PXE,
BDS_DEVICE_TFTP,
BDS_DEVICE_MAX
} BDS_SUPPORTED_DEVICE_TYPE;
typedef struct {
LIST_ENTRY Link;
CHAR16 Description[BOOT_DEVICE_DESCRIPTION_MAX];
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
struct _BDS_LOAD_OPTION_SUPPORT* Support;
} BDS_SUPPORTED_DEVICE;
#define SUPPORTED_BOOT_DEVICE_FROM_LINK(a) BASE_CR(a, BDS_SUPPORTED_DEVICE, Link)
typedef UINT8* EFI_LOAD_OPTION;
typedef struct {
LIST_ENTRY Link;
UINT16 LoadOptionIndex;
EFI_LOAD_OPTION LoadOption;
UINTN LoadOptionSize;
UINT32 Attributes;
UINT16 FilePathListLength;
CHAR16 *Description;
EFI_DEVICE_PATH_PROTOCOL *FilePathList;
BDS_LOADER_OPTIONAL_DATA *OptionalData;
} BDS_LOAD_OPTION;
typedef struct _BDS_LOAD_OPTION_SUPPORT {
BDS_SUPPORTED_DEVICE_TYPE Type;
EFI_STATUS (*ListDevices)(IN OUT LIST_ENTRY* BdsLoadOptionList);
BOOLEAN (*IsSupported)(IN BDS_LOAD_OPTION* BdsLoadOption);
EFI_STATUS (*CreateDevicePathNode)(IN BDS_SUPPORTED_DEVICE* BdsLoadOption, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode, OUT BDS_LOADER_TYPE *BootType, OUT UINT32 *Attributes);
EFI_STATUS (*UpdateDevicePathNode)(IN BDS_LOAD_OPTION *BootOption, OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath, OUT BDS_LOADER_TYPE *BootType, OUT UINT32 *Attributes);
} BDS_LOAD_OPTION_SUPPORT;
#define LOAD_OPTION_FROM_LINK(a) BASE_CR(a, BDS_LOAD_OPTION, Link)
EFI_STATUS
GetEnvironmentVariable (
IN CONST CHAR16* VariableName,
IN VOID* DefaultValue,
IN OUT UINTN* Size,
OUT VOID** Value
);
EFI_STATUS
BootDeviceListSupportedInit (
IN OUT LIST_ENTRY *SupportedDeviceList
);
EFI_STATUS
BootDeviceListSupportedFree (
IN LIST_ENTRY *SupportedDeviceList
);
EFI_STATUS
BootDeviceGetDeviceSupport (
IN BDS_LOAD_OPTION *BootOption,
OUT BDS_LOAD_OPTION_SUPPORT** DeviceSupport
);
EFI_STATUS
GetHIInputAscii (
IN OUT CHAR8 *CmdLine,
IN UINTN MaxCmdLine
);
EFI_STATUS
EditHIInputAscii (
IN OUT CHAR8 *CmdLine,
IN UINTN MaxCmdLine
);
EFI_STATUS
GetHIInputInteger (
IN OUT UINTN *Integer
);
EFI_STATUS
GetHIInputIP (
OUT EFI_IP_ADDRESS *Ip
);
EFI_STATUS
GetHIInputBoolean (
OUT BOOLEAN *Value
);
BOOLEAN
HasFilePathEfiExtension (
IN CHAR16* FilePath
);
EFI_DEVICE_PATH*
GetLastDevicePathNode (
IN EFI_DEVICE_PATH* DevicePath
);
EFI_STATUS
BdsStartBootOption (
IN CHAR16* BootOption
);
EFI_STATUS
GenerateDeviceDescriptionName (
IN EFI_HANDLE Handle,
IN OUT CHAR16* Description
);
EFI_STATUS
BootOptionList (
IN OUT LIST_ENTRY *BootOptionList
);
EFI_STATUS
BootOptionParseLoadOption (
IN EFI_LOAD_OPTION EfiLoadOption,
IN UINTN EfiLoadOptionSize,
OUT BDS_LOAD_OPTION **BdsLoadOption
);
EFI_STATUS
BootOptionStart (
IN BDS_LOAD_OPTION *BootOption
);
EFI_STATUS
BootOptionCreate (
IN UINT32 Attributes,
IN CHAR16* BootDescription,
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
IN BDS_LOADER_TYPE BootType,
IN CHAR8* BootArguments,
OUT BDS_LOAD_OPTION **BdsLoadOption
);
EFI_STATUS
BootOptionUpdate (
IN BDS_LOAD_OPTION *BdsLoadOption,
IN UINT32 Attributes,
IN CHAR16* BootDescription,
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
IN BDS_LOADER_TYPE BootType,
IN CHAR8* BootArguments
);
EFI_STATUS
BootOptionDelete (
IN BDS_LOAD_OPTION *BootOption
);
EFI_STATUS
BootMenuMain (
VOID
);
#endif /* _BDSINTERNAL_H_ */

View File

@ -0,0 +1,487 @@
/** @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
BootMenuAddBootOption (
IN LIST_ENTRY *BootOptionsList
)
{
EFI_STATUS Status;
LIST_ENTRY SupportedDeviceList;
UINTN SupportedDeviceCount;
BDS_SUPPORTED_DEVICE* SupportedBootDevice;
LIST_ENTRY* Entry;
UINTN SupportedDeviceSelected;
CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];
CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
CHAR16 *BootDescription;
UINT32 Attributes;
BDS_LOADER_TYPE BootType;
UINTN Index;
BDS_LOAD_OPTION *BdsLoadOption;
EFI_DEVICE_PATH* DevicePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
Attributes = 0;
//
// 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)
)
{
SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
Print(L"[%d] %s\n",SupportedDeviceCount+1,SupportedBootDevice->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(SupportedBootDevice->DevicePathProtocol,TRUE,TRUE);
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) {
SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
break;
}
Index++;
}
// Create the specific device path node
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);
Print(L"Arguments to pass to the binary: ");
Status = GetHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);
if (EFI_ERROR(Status)) {
Status = EFI_ABORTED;
goto FREE_DEVICE_PATH;
}
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
Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, AsciiBootOption, &BdsLoadOption);
if (!EFI_ERROR(Status)) {
InsertTailList (BootOptionsList,&BdsLoadOption->Link);
}
FreePool (BootDescription);
FREE_DEVICE_PATH:
FreePool (DevicePath);
EXIT:
BootDeviceListSupportedFree (&SupportedDeviceList);
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);
if ((BootOption->OptionalData != NULL) && (BootOption->OptionalData->Arguments != NULL)) {
Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);
}
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)) {
Print(L"Invalid input (max %d)\n",BootOptionCount);
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
)
{
EFI_STATUS Status;
BDS_LOAD_OPTION *BootOption;
BDS_LOAD_OPTION_SUPPORT* DeviceSupport;
CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];
CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
CHAR16 *BootDescription;
EFI_DEVICE_PATH* DevicePath;
UINT32 Attributes;
BDS_LOADER_TYPE BootType;
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;
}
Status = DeviceSupport->UpdateDevicePathNode (BootOption,&DevicePath,&BootType,&Attributes);
if (EFI_ERROR(Status)) {
Status = EFI_ABORTED;
goto EXIT;
}
Print(L"Arguments to pass to the binary: ");
if (BootOption->OptionalData) {
AsciiStrnCpy(AsciiBootOption,BootOption->OptionalData->Arguments,BOOT_DEVICE_FILEPATH_MAX);
} else {
AsciiBootOption[0] = '\0';
}
Status = EditHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);
if (EFI_ERROR(Status)) {
Status = EFI_ABORTED;
goto FREE_DEVICE_PATH;
}
Print(L"Description for this new Entry: ");
UnicodeStrToAsciiStr (BootOption->Description,AsciiBootDescription);
Status = EditHIInputAscii (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);
// Update the entry
Status = BootOptionUpdate (BootOption, Attributes, BootDescription, DevicePath, BootType, AsciiBootOption);
FreePool (BootDescription);
FREE_DEVICE_PATH:
FreePool (DevicePath);
EXIT:
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))) {
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;
BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
// 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);
ASSERT_EFI_ERROR(Status);
DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
Print(L"\t- %s\n",DevicePathTxt);
if (BootOption->OptionalData != NULL) {
Print(L"\t- LoaderType: %d\n",BootOption->OptionalData->LoaderType);
if (BootOption->OptionalData->Arguments != NULL) {
Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);
}
}
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;
}

View File

@ -0,0 +1,407 @@
/** @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;
EFI_STATUS
BootOptionStart (
IN BDS_LOAD_OPTION *BootOption
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH* FdtDevicePath;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
Status = EFI_UNSUPPORTED;
if (BootOption->OptionalData->LoaderType == BDS_LOADER_EFI_APPLICATION) {
// Need to connect every drivers to ensure no dependencies are missing for the application
BdsConnectAllDrivers();
Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList);
} else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, NULL);
} else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
// Convert the FDT path into a Device Path
Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
ASSERT_EFI_ERROR(Status);
FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));
Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, FdtDevicePath);
FreePool(FdtDevicePath);
}
return Status;
}
EFI_STATUS
BootOptionParseLoadOption (
IN EFI_LOAD_OPTION EfiLoadOption,
IN UINTN EfiLoadOptionSize,
OUT BDS_LOAD_OPTION **BdsLoadOption
)
{
BDS_LOAD_OPTION *LoadOption;
UINTN FilePathListLength;
UINTN DescriptionLength;
if (EfiLoadOption == NULL) {
return EFI_INVALID_PARAMETER;
}
if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
return EFI_BAD_BUFFER_SIZE;
}
LoadOption = (BDS_LOAD_OPTION*)AllocatePool(sizeof(BDS_LOAD_OPTION));
if (LoadOption == NULL) {
return EFI_OUT_OF_RESOURCES;
}
LoadOption->LoadOption = EfiLoadOption;
LoadOption->LoadOptionSize = EfiLoadOptionSize;
LoadOption->Attributes = *(UINT32*)EfiLoadOption;
FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32));
LoadOption->Description = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));
DescriptionLength = StrSize (LoadOption->Description);
LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
if ((UINTN)((UINT8*)LoadOption->FilePathList + FilePathListLength - EfiLoadOption) == EfiLoadOptionSize) {
LoadOption->OptionalData = NULL;
} else {
LoadOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)((UINT8*)LoadOption->FilePathList + FilePathListLength);
}
*BdsLoadOption = LoadOption;
return EFI_SUCCESS;
}
EFI_STATUS
BootOptionFromLoadOptionVariable (
IN UINT16 LoadOptionIndex,
OUT BDS_LOAD_OPTION **BdsLoadOption
)
{
EFI_STATUS Status;
CHAR16 BootVariableName[9];
EFI_LOAD_OPTION EfiLoadOption;
UINTN EfiLoadOptionSize;
UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
Status = GetEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
if (!EFI_ERROR(Status)) {
Status = BootOptionParseLoadOption (EfiLoadOption,EfiLoadOptionSize,BdsLoadOption);
if (!EFI_ERROR(Status)) {
(*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
}
}
return Status;
}
EFI_STATUS
BootOptionList (
IN OUT LIST_ENTRY *BootOptionList
)
{
EFI_STATUS Status;
UINTN Index;
UINT16 *BootOrder;
UINTN BootOrderSize;
BDS_LOAD_OPTION *BdsLoadOption;
InitializeListHead (BootOptionList);
// Get the Boot Option Order from the environment variable
Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
if (EFI_ERROR(Status)) {
return Status;
}
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
Status = BootOptionFromLoadOptionVariable (BootOrder[Index],&BdsLoadOption);
if (!EFI_ERROR(Status)) {
InsertTailList (BootOptionList,&BdsLoadOption->Link);
}
}
return EFI_SUCCESS;
}
UINT16
BootOptionAllocateBootIndex (
VOID
)
{
EFI_STATUS Status;
UINTN Index;
UINT32 BootIndex;
UINT16 *BootOrder;
UINTN BootOrderSize;
BOOLEAN Found;
// Get the Boot Option Order from the environment variable
Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
if (!EFI_ERROR(Status)) {
for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
Found = FALSE;
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
if (BootOrder[Index] == BootIndex) {
Found = TRUE;
break;
}
}
if (!Found) {
return BootIndex;
}
}
}
// Return the first index
return 0;
}
STATIC
EFI_STATUS
BootOptionSetFields (
IN BDS_LOAD_OPTION *BootOption,
IN UINT32 Attributes,
IN CHAR16* BootDescription,
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
IN BDS_LOADER_TYPE BootType,
IN CHAR8* BootArguments
)
{
EFI_LOAD_OPTION EfiLoadOption;
UINTN EfiLoadOptionSize;
UINTN BootDescriptionSize;
UINTN BootOptionalDataSize;
UINT16 FilePathListLength;
EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;
UINTN NodeLength;
UINT8* EfiLoadOptionPtr;
// If we are overwriting an existent Boot Option then we have to free previously allocated memory
if (BootOption->LoadOption) {
FreePool(BootOption->LoadOption);
}
BootDescriptionSize = StrSize(BootDescription);
BootOptionalDataSize = sizeof(BDS_LOADER_OPTIONAL_DATA) +
(BootArguments == NULL ? 0 : AsciiStrSize(BootArguments));
// Compute the size of the FilePath list
FilePathListLength = 0;
DevicePathNode = DevicePath;
while (!IsDevicePathEndType (DevicePathNode)) {
FilePathListLength += DevicePathNodeLength (DevicePathNode);
DevicePathNode = NextDevicePathNode (DevicePathNode);
}
// Add the length of the DevicePath EndType
FilePathListLength += DevicePathNodeLength (DevicePathNode);
// Allocate the memory for the EFI Load Option
EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + BootOptionalDataSize;
EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);
EfiLoadOptionPtr = EfiLoadOption;
//
// Populate the EFI Load Option and BDS Boot Option structures
//
// Attributes fields
BootOption->Attributes = Attributes;
*(UINT32*)EfiLoadOptionPtr = Attributes;
EfiLoadOptionPtr += sizeof(UINT32);
// FilePath List fields
BootOption->FilePathListLength = FilePathListLength;
*(UINT16*)EfiLoadOptionPtr = FilePathListLength;
EfiLoadOptionPtr += sizeof(UINT16);
// Boot description fields
BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
EfiLoadOptionPtr += BootDescriptionSize;
// File path fields
BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
DevicePathNode = DevicePath;
while (!IsDevicePathEndType (DevicePathNode)) {
NodeLength = DevicePathNodeLength(DevicePathNode);
CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
EfiLoadOptionPtr += NodeLength;
DevicePathNode = NextDevicePathNode (DevicePathNode);
}
// Set the End Device Path Type
SetDevicePathEndNode (EfiLoadOptionPtr);
EfiLoadOptionPtr = (UINT8 *)EfiLoadOptionPtr + sizeof(EFI_DEVICE_PATH);
// Optional Data fields, Do unaligned writes
WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, BootType);
CopyMem (&((BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments, BootArguments, AsciiStrSize(BootArguments));
BootOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)EfiLoadOptionPtr;
// Fill the EFI Load option fields
BootOption->LoadOptionIndex = BootOptionAllocateBootIndex();
BootOption->LoadOption = EfiLoadOption;
BootOption->LoadOptionSize = EfiLoadOptionSize;
return EFI_SUCCESS;
}
EFI_STATUS
BootOptionCreate (
IN UINT32 Attributes,
IN CHAR16* BootDescription,
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
IN BDS_LOADER_TYPE BootType,
IN CHAR8* BootArguments,
OUT BDS_LOAD_OPTION **BdsLoadOption
)
{
EFI_STATUS Status;
BDS_LOAD_OPTION *BootOption;
CHAR16 BootVariableName[9];
UINT16 *BootOrder;
UINTN BootOrderSize;
//
// Allocate and fill the memory for the BDS Load Option structure
//
BootOption = (BDS_LOAD_OPTION*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION));
InitializeListHead (&BootOption->Link);
BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
//
// Set the related environment variables
//
// Create Boot#### environment variable
UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
Status = gRT->SetVariable (
BootVariableName,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
BootOption->LoadOptionSize,
BootOption->LoadOption
);
// Add the new Boot Index to the list
Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
if (!EFI_ERROR(Status)) {
BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
// Add the new index at the end
BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
BootOrderSize += sizeof(UINT16);
} else {
// BootOrder does not exist. Create it
BootOrderSize = sizeof(UINT16);
BootOrder = &(BootOption->LoadOptionIndex);
}
// Update (or Create) the BootOrder environment variable
Status = gRT->SetVariable (
L"BootOrder",
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
BootOrderSize,
BootOrder
);
*BdsLoadOption = BootOption;
return Status;
}
EFI_STATUS
BootOptionUpdate (
IN BDS_LOAD_OPTION *BdsLoadOption,
IN UINT32 Attributes,
IN CHAR16* BootDescription,
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
IN BDS_LOADER_TYPE BootType,
IN CHAR8* BootArguments
)
{
EFI_STATUS Status;
BDS_LOAD_OPTION *BootOption;
CHAR16 BootVariableName[9];
// Update the BDS Load Option structure
BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
// Update the related environment variables
UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
Status = gRT->SetVariable (
BootVariableName,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
BootOption->LoadOptionSize,
BootOption->LoadOption
);
return Status;
}
EFI_STATUS
BootOptionDelete (
IN BDS_LOAD_OPTION *BootOption
)
{
UINTN Index;
UINTN BootOrderSize;
UINT16* BootOrder;
UINTN BootOrderCount;
EFI_STATUS Status;
// If the Boot Optiono was attached to a list remove it
if (!IsListEmpty (&BootOption->Link)) {
// Remove the entry from the list
RemoveEntryList (&BootOption->Link);
}
// Remove the entry from the BootOrder environment variable
Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
if (!EFI_ERROR(Status)) {
BootOrderCount = BootOrderSize / sizeof(UINT16);
// Find the index of the removed entry
for (Index = 0; Index < BootOrderCount; Index++) {
if (BootOrder[Index] == BootOption->LoadOptionIndex) {
// If it the last entry we do not need to rearrange the BootOrder list
if (Index + 1 != BootOrderCount) {
CopyMem (&BootOrder[Index],&BootOrder[Index+1], BootOrderCount - (Index + 1));
}
break;
}
}
// Update the BootOrder environment variable
Status = gRT->SetVariable (
L"BootOrder",
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
BootOrderSize - sizeof(UINT16),
BootOrder
);
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,867 @@
/** @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"
#include <Library/NetLib.h>
#include <Protocol/BlockIo.h>
#include <Protocol/DevicePathToText.h>
#include <Protocol/PxeBaseCode.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/SimpleNetwork.h>
#include <Guid/FileSystemInfo.h>
#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
EFI_STATUS
BdsLoadOptionFileSystemList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionFileSystemCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionFileSystemUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionFileSystemIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
EFI_STATUS
BdsLoadOptionMemMapList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionMemMapCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionMemMapUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionMemMapIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
EFI_STATUS
BdsLoadOptionPxeList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionPxeCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionPxeUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionPxeIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
EFI_STATUS
BdsLoadOptionTftpList (
IN OUT LIST_ENTRY* BdsLoadOptionList
);
EFI_STATUS
BdsLoadOptionTftpCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
EFI_STATUS
BdsLoadOptionTftpUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
);
BOOLEAN
BdsLoadOptionTftpIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
);
BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {
{
BDS_DEVICE_FILESYSTEM,
BdsLoadOptionFileSystemList,
BdsLoadOptionFileSystemIsSupported,
BdsLoadOptionFileSystemCreateDevicePath,
BdsLoadOptionFileSystemUpdateDevicePath
},
{
BDS_DEVICE_MEMMAP,
BdsLoadOptionMemMapList,
BdsLoadOptionMemMapIsSupported,
BdsLoadOptionMemMapCreateDevicePath,
BdsLoadOptionMemMapUpdateDevicePath
},
{
BDS_DEVICE_PXE,
BdsLoadOptionPxeList,
BdsLoadOptionPxeIsSupported,
BdsLoadOptionPxeCreateDevicePath,
BdsLoadOptionPxeUpdateDevicePath
},
{
BDS_DEVICE_TFTP,
BdsLoadOptionTftpList,
BdsLoadOptionTftpIsSupported,
BdsLoadOptionTftpCreateDevicePath,
BdsLoadOptionTftpUpdateDevicePath
}
};
EFI_STATUS
BootDeviceListSupportedInit (
IN OUT LIST_ENTRY *SupportedDeviceList
)
{
UINTN Index;
// Initialize list of supported devices
InitializeListHead (SupportedDeviceList);
for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {
BdsLoadOptionSupportList[Index].ListDevices(SupportedDeviceList);
}
return EFI_SUCCESS;
}
EFI_STATUS
BootDeviceListSupportedFree (
IN LIST_ENTRY *SupportedDeviceList
)
{
LIST_ENTRY *Entry;
BDS_SUPPORTED_DEVICE* SupportedDevice;
Entry = GetFirstNode (SupportedDeviceList);
while (Entry != SupportedDeviceList) {
SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
Entry = RemoveEntryList (Entry);
FreePool(SupportedDevice);
}
return EFI_SUCCESS;
}
EFI_STATUS
BootDeviceGetDeviceSupport (
IN BDS_LOAD_OPTION *BootOption,
OUT BDS_LOAD_OPTION_SUPPORT** DeviceSupport
)
{
UINTN Index;
// Find which supported device is the most appropriate
for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {
if (BdsLoadOptionSupportList[Index].IsSupported(BootOption)) {
*DeviceSupport = &BdsLoadOptionSupportList[Index];
return EFI_SUCCESS;
}
}
return EFI_UNSUPPORTED;
}
STATIC
EFI_STATUS
BootDeviceGetType (
IN CHAR16* FileName,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
BOOLEAN IsEfiApp;
BOOLEAN IsBootLoader;
BOOLEAN HasFDTSupport;
if (FileName == NULL) {
Print(L"Is an EFI Application? ");
Status = GetHIInputBoolean (&IsEfiApp);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
} else if (HasFilePathEfiExtension(FileName)) {
IsEfiApp = TRUE;
} else {
IsEfiApp = FALSE;
}
if (IsEfiApp) {
Print(L"Is your application is an OS loader? ");
Status = GetHIInputBoolean (&IsBootLoader);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
if (!IsBootLoader) {
*Attributes |= LOAD_OPTION_CATEGORY_APP;
}
*BootType = BDS_LOADER_EFI_APPLICATION;
} else {
Print(L"Has FDT support? ");
Status = GetHIInputBoolean (&HasFDTSupport);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
if (HasFDTSupport) {
*BootType = BDS_LOADER_KERNEL_LINUX_FDT;
} else {
*BootType = BDS_LOADER_KERNEL_LINUX_ATAG;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionFileSystemList (
IN OUT LIST_ENTRY* BdsLoadOptionList
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
BDS_SUPPORTED_DEVICE *SupportedDevice;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileProtocol;
EFI_FILE_HANDLE Fs;
UINTN Size;
EFI_FILE_SYSTEM_INFO* FsInfo;
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
// List all the Simple File System Protocols
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
if (!EFI_ERROR(Status)) {
// Allocate BDS Supported Device structure
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
FileProtocol = NULL;
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileProtocol);
ASSERT_EFI_ERROR(Status);
FileProtocol->OpenVolume (FileProtocol, &Fs);
// Generate a Description from the file system
Size = 0;
FsInfo = NULL;
Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);
if (Status == EFI_BUFFER_TOO_SMALL) {
FsInfo = AllocatePool (Size);
Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);
}
UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"%s (%d MB)",FsInfo->VolumeLabel,(UINT32)(FsInfo->VolumeSize / (1024 * 1024)));
FreePool(FsInfo);
Fs->Close (Fs);
SupportedDevice->DevicePathProtocol = DevicePathProtocol;
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_FILESYSTEM];
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionFileSystemCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
CHAR16 *BootFilePath;
UINTN BootFilePathSize;
Print(L"File path of the EFI Application or the kernel: ");
Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
// Convert Ascii into Unicode
BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
BootFilePathSize = StrSize(BootFilePath);
// Create the FilePath Device Path node
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
FreePool (BootFilePath);
Status = BootDeviceGetType (FilePathDevicePath->PathName, BootType, Attributes);
if (EFI_ERROR(Status)) {
FreePool (FilePathDevicePath);
} else {
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;
}
return Status;
}
EFI_STATUS
BdsLoadOptionFileSystemUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
CHAR16 *BootFilePath;
UINTN BootFilePathSize;
FILEPATH_DEVICE_PATH* EndingDevicePath;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
EFI_DEVICE_PATH* DevicePath;
DevicePath = DuplicateDevicePath (BootOption->FilePathList);
EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
Print(L"File path of the EFI Application or the kernel: ");
UnicodeStrToAsciiStr (EndingDevicePath->PathName,AsciiBootFilePath);
Status = EditHIInputAscii(AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
if (EFI_ERROR(Status)) {
return Status;
}
// Convert Ascii into Unicode
BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
BootFilePathSize = StrSize(BootFilePath);
// Create the FilePath Device Path node
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
FreePool (BootFilePath);
// Generate the new Device Path by replacing the last node by the updated node
SetDevicePathEndNode (EndingDevicePath);
*NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath);
FreePool(DevicePath);
return BootDeviceGetType (FilePathDevicePath->PathName, BootType, Attributes);
}
BOOLEAN
BdsLoadOptionFileSystemIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_DEVICE_PATH* DevicePathNode;
DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);
return IS_DEVICE_PATH_NODE(DevicePathNode,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP);
}
STATIC
BOOLEAN
IsParentDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath
)
{
UINTN ParentSize;
UINTN ChildSize;
ParentSize = GetDevicePathSize (ParentDevicePath);
ChildSize = GetDevicePathSize (ChildDevicePath);
if (ParentSize > ChildSize) {
return FALSE;
}
if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {
return FALSE;
}
return TRUE;
}
EFI_STATUS
BdsLoadOptionMemMapList (
IN OUT LIST_ENTRY* BdsLoadOptionList
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN DevicePathHandleCount;
EFI_HANDLE *DevicePathHandleBuffer;
BOOLEAN IsParent;
UINTN Index;
UINTN Index2;
BDS_SUPPORTED_DEVICE *SupportedDevice;
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
EFI_DEVICE_PATH* DevicePath;
// List all the BlockIo Protocols
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
// We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
if (!EFI_ERROR(Status)) {
// BlockIo is not part of Media Device Path
DevicePath = DevicePathProtocol;
while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {
DevicePath = NextDevicePathNode (DevicePath);
}
if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {
continue;
}
// Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);
ASSERT_EFI_ERROR (Status);
IsParent = FALSE;
for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {
if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {
gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {
IsParent = TRUE;
}
}
}
if (IsParent) {
continue;
}
// Allocate BDS Supported Device structure
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);
ASSERT_EFI_ERROR (Status);
SupportedDevice->DevicePathProtocol = DevicePathProtocol;
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionMemMapCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
MEMMAP_DEVICE_PATH* MemMapDevicePath;
CHAR8 AsciiStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
CHAR8 AsciiEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
Print(L"Starting Address of the binary: ");
Status = GetHIInputAscii (AsciiStartingAddress,BOOT_DEVICE_ADDRESS_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
Print(L"Ending Address of the binary: ");
Status = GetHIInputAscii (AsciiEndingAddress,BOOT_DEVICE_ADDRESS_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
// Create the MemMap Device Path Node
MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool(sizeof(MEMMAP_DEVICE_PATH));
MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;
MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;
MemMapDevicePath->MemoryType = EfiBootServicesData;
MemMapDevicePath->StartingAddress = AsciiStrHexToUint64 (AsciiStartingAddress);
MemMapDevicePath->EndingAddress = AsciiStrHexToUint64 (AsciiEndingAddress);
Status = BootDeviceGetType (NULL, BootType, Attributes);
if (EFI_ERROR(Status)) {
FreePool (MemMapDevicePath);
} else {
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;
}
return Status;
}
EFI_STATUS
BdsLoadOptionMemMapUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
ASSERT(0);
//TODO: Implement me
return EFI_SUCCESS;
}
BOOLEAN
BdsLoadOptionMemMapIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_DEVICE_PATH* DevicePathNode;
DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);
return IS_DEVICE_PATH_NODE(DevicePathNode,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
}
EFI_STATUS
BdsLoadOptionPxeList (
IN OUT LIST_ENTRY* BdsLoadOptionList
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
BDS_SUPPORTED_DEVICE *SupportedDevice;
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
EFI_MAC_ADDRESS *Mac;
// List all the PXE Protocols
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
// We only select the handle WITH a Device Path AND the PXE Protocol
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
if (!EFI_ERROR(Status)) {
// Allocate BDS Supported Device structure
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
if (!EFI_ERROR(Status)) {
Mac = &SimpleNet->Mode->CurrentAddress;
UnicodeSPrint (DeviceDescription,BOOT_DEVICE_DESCRIPTION_MAX,L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac->Addr[0], Mac->Addr[1], Mac->Addr[2], Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]);
} else {
Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
ASSERT_EFI_ERROR (Status);
}
UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);
SupportedDevice->DevicePathProtocol = DevicePathProtocol;
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionPxeCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
SetDevicePathEndNode (*DevicePathNode);
*BootType = BDS_LOADER_EFI_APPLICATION;
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionPxeUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
ASSERT (0);
return EFI_SUCCESS;
}
BOOLEAN
BdsLoadOptionPxeIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &Handle, &RemainingDevicePath);
if (EFI_ERROR(Status)) {
return FALSE;
}
if (!IsDevicePathEnd(RemainingDevicePath)) {
return FALSE;
}
Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
if (EFI_ERROR (Status)) {
return FALSE;
} else {
return TRUE;
}
}
EFI_STATUS
BdsLoadOptionTftpList (
IN OUT LIST_ENTRY* BdsLoadOptionList
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
BDS_SUPPORTED_DEVICE *SupportedDevice;
EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
EFI_MAC_ADDRESS *Mac;
// List all the PXE Protocols
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
// We only select the handle WITH a Device Path AND the PXE Protocol AND the TFTP Protocol (the TFTP protocol is required to start PXE)
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
if (!EFI_ERROR(Status)) {
// Allocate BDS Supported Device structure
SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
if (!EFI_ERROR(Status)) {
Mac = &SimpleNet->Mode->CurrentAddress;
UnicodeSPrint (DeviceDescription,BOOT_DEVICE_DESCRIPTION_MAX,L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac->Addr[0], Mac->Addr[1], Mac->Addr[2], Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]);
} else {
Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
ASSERT_EFI_ERROR (Status);
}
UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFP on %s",DeviceDescription);
SupportedDevice->DevicePathProtocol = DevicePathProtocol;
SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];
InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
}
}
return EFI_SUCCESS;
}
EFI_STATUS
BdsLoadOptionTftpCreateDevicePath (
IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
EFI_STATUS Status;
BOOLEAN IsDHCP;
EFI_IP_ADDRESS LocalIp;
EFI_IP_ADDRESS RemoteIp;
IPv4_DEVICE_PATH* IPv4DevicePathNode;
FILEPATH_DEVICE_PATH* FilePathDevicePath;
CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
CHAR16* BootFilePath;
UINTN BootFilePathSize;
Print(L"Get the IP address from DHCP: ");
Status = GetHIInputBoolean (&IsDHCP);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
if (!IsDHCP) {
Print(L"Get the static IP address: ");
Status = GetHIInputIP (&LocalIp);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
}
Print(L"Get the TFTP server IP address: ");
Status = GetHIInputIP (&RemoteIp);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
Print(L"File path of the EFI Application or the kernel: ");
Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
if (EFI_ERROR(Status)) {
return EFI_ABORTED;
}
// Convert Ascii into Unicode
BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
BootFilePathSize = StrSize(BootFilePath);
// Allocate the memory for the IPv4 + File Path Device Path Nodes
IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
// Create the IPv4 Device Path
IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;
IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;
SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));
CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));
CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));
IPv4DevicePathNode->LocalPort = 0;
IPv4DevicePathNode->RemotePort = 0;
IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;
IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);
// Create the FilePath Device Path node
FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
FreePool (BootFilePath);
Status = BootDeviceGetType (NULL, BootType, Attributes);
if (EFI_ERROR(Status)) {
FreePool (IPv4DevicePathNode);
} else {
*DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;
}
return Status;
}
EFI_STATUS
BdsLoadOptionTftpUpdateDevicePath (
IN BDS_LOAD_OPTION *BootOption,
OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
OUT BDS_LOADER_TYPE *BootType,
OUT UINT32 *Attributes
)
{
ASSERT (0);
return EFI_SUCCESS;
}
BOOLEAN
BdsLoadOptionTftpIsSupported (
IN BDS_LOAD_OPTION* BdsLoadOption
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_DEVICE_PATH *RemainingDevicePath;
EFI_DEVICE_PATH *NextDevicePath;
EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &Handle, &RemainingDevicePath);
if (EFI_ERROR(Status)) {
return FALSE;
}
// Validate the Remaining Device Path
if (IsDevicePathEnd(RemainingDevicePath)) {
return FALSE;
}
if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
return FALSE;
}
NextDevicePath = NextDevicePathNode (RemainingDevicePath);
if (IsDevicePathEnd(NextDevicePath)) {
return FALSE;
}
if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
return FALSE;
}
Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
if (EFI_ERROR (Status)) {
return FALSE;
} else {
return TRUE;
}
}