From: oliviermartin Date: Sat, 11 Jun 2011 11:58:23 +0000 (+0000) Subject: ArmPlatformPkg/Bds: Upgrade the BDS to be more conformed to the UEFI Specification X-Git-Tag: edk2-stable201903~14707 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=ea46ebbe6a5a579ff341071a13ae625e15edae64 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 --- diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec index 1d9c05a233..7a9223bc6c 100644 --- a/ArmPlatformPkg/ArmPlatformPkg.dec +++ b/ArmPlatformPkg/ArmPlatformPkg.dec @@ -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 + diff --git a/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A8.dsc b/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A8.dsc index b64f784bc9..533acd215d 100644 --- a/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A8.dsc +++ b/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A8.dsc @@ -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 diff --git a/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A9x2.dsc b/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A9x2.dsc index 9254c01514..8245cc750e 100644 --- a/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A9x2.dsc +++ b/ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A9x2.dsc @@ -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 diff --git a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc index 7f88fccc68..7dda73f9b2 100644 --- a/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc +++ b/ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc @@ -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 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 +#include + +#include + +#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.
+# Copyright (c) 2011, ARM Ltd. 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 @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#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 + +#include +#include +#include +#include +#include + +#include + +#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; + } +}