summaryrefslogtreecommitdiff
path: root/ArmPlatformPkg/Bds
diff options
context:
space:
mode:
Diffstat (limited to 'ArmPlatformPkg/Bds')
-rw-r--r--ArmPlatformPkg/Bds/Bds.c398
-rw-r--r--ArmPlatformPkg/Bds/Bds.inf31
-rw-r--r--ArmPlatformPkg/Bds/BdsEntry.c332
-rw-r--r--ArmPlatformPkg/Bds/BdsHelper.c307
-rw-r--r--ArmPlatformPkg/Bds/BdsInternal.h214
-rw-r--r--ArmPlatformPkg/Bds/BootMenu.c487
-rw-r--r--ArmPlatformPkg/Bds/BootOption.c407
-rw-r--r--ArmPlatformPkg/Bds/BootOptionSupport.c867
8 files changed, 2705 insertions, 338 deletions
diff --git a/ArmPlatformPkg/Bds/Bds.c b/ArmPlatformPkg/Bds/Bds.c
new file mode 100644
index 0000000000..415f0a9cb2
--- /dev/null
+++ b/ArmPlatformPkg/Bds/Bds.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/Bds/Bds.inf b/ArmPlatformPkg/Bds/Bds.inf
index dbd26aedb4..5749e7c61b 100644
--- a/ArmPlatformPkg/Bds/Bds.inf
+++ b/ArmPlatformPkg/Bds/Bds.inf
@@ -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
diff --git a/ArmPlatformPkg/Bds/BdsEntry.c b/ArmPlatformPkg/Bds/BdsEntry.c
deleted file mode 100644
index 62e8236e84..0000000000
--- a/ArmPlatformPkg/Bds/BdsEntry.c
+++ /dev/null
@@ -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;
-}
diff --git a/ArmPlatformPkg/Bds/BdsHelper.c b/ArmPlatformPkg/Bds/BdsHelper.c
new file mode 100644
index 0000000000..2f0cb31d39
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BdsHelper.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/Bds/BdsInternal.h b/ArmPlatformPkg/Bds/BdsInternal.h
new file mode 100644
index 0000000000..9ef36a1ff6
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BdsInternal.h
@@ -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_ */
diff --git a/ArmPlatformPkg/Bds/BootMenu.c b/ArmPlatformPkg/Bds/BootMenu.c
new file mode 100644
index 0000000000..a2360d14f5
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BootMenu.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/Bds/BootOption.c b/ArmPlatformPkg/Bds/BootOption.c
new file mode 100644
index 0000000000..a8ba23fe73
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BootOption.c
@@ -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;
+}
diff --git a/ArmPlatformPkg/Bds/BootOptionSupport.c b/ArmPlatformPkg/Bds/BootOptionSupport.c
new file mode 100644
index 0000000000..7de2df4825
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BootOptionSupport.c
@@ -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;
+ }
+}