]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPlatformPkg/Bds: Upgrade the BDS to be more conformed to the UEFI Specification
authoroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>
Sat, 11 Jun 2011 11:58:23 +0000 (11:58 +0000)
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>
Sat, 11 Jun 2011 11:58:23 +0000 (11:58 +0000)
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

12 files changed:
ArmPlatformPkg/ArmPlatformPkg.dec
ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A8.dsc
ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb-RTSM-A9x2.dsc
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-CTA9x4.dsc
ArmPlatformPkg/Bds/Bds.c [new file with mode: 0644]
ArmPlatformPkg/Bds/Bds.inf
ArmPlatformPkg/Bds/BdsEntry.c [deleted file]
ArmPlatformPkg/Bds/BdsHelper.c [new file with mode: 0644]
ArmPlatformPkg/Bds/BdsInternal.h [new file with mode: 0644]
ArmPlatformPkg/Bds/BootMenu.c [new file with mode: 0644]
ArmPlatformPkg/Bds/BootOption.c [new file with mode: 0644]
ArmPlatformPkg/Bds/BootOptionSupport.c [new file with mode: 0644]

index 1d9c05a2336063c97178d0718976520edf666c96..7a9223bc6cb5ddd56eea9ed499fe9f4e6f185599 100644 (file)
   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
+  
index b64f784bc9d34fb0098a704c05b66a905e8629f2..533acd215d085835356214a3b349511064a08aa3 100644 (file)
 !endif\r
 \r
 [PcdsFixedAtBuild.common]\r
+  gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM RealView Emulation Board"\r
+  \r
   gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"ArmRealViewEb-A8"\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0\r
   #\r
   # ARM OS Loader\r
   #\r
-  # Versatile Express machine type (ARM VERSATILE EXPRESS = 2272) required for ARM Linux: \r
-  gArmTokenSpaceGuid.PcdArmMachineType|2272\r
-  gArmTokenSpaceGuid.PcdLinuxKernelDP|L"VenHw(02118005-9DA7-443a-92D5-781F022AEDBB)/MemoryMapped(0,0x46000000,0x46400000)"\r
-  gArmTokenSpaceGuid.PcdLinuxAtag|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=1G"\r
-  gArmTokenSpaceGuid.PcdFdtDP|L""\r
+  gArmTokenSpaceGuid.PcdArmMachineType|827\r
+  gArmPlatformTokenSpaceGuid.PcdDefaultBootDescription|L"SemiHosting"\r
+  gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath|L"VenHw(C5B9C74A-6D72-4719-99AB-C59F199091EB)/zImage-RTSM"\r
+  gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument|"rdinit=/bin/ash debug earlyprintk console=ttyAMA0,38400 mem=128M"\r
+  gArmPlatformTokenSpaceGuid.PcdDefaultBootType|1\r
   \r
   #\r
   # ARM L2x0 PCDs\r
index 9254c01514097a37dedbcc34f3bf6bfd72de7ea1..8245cc750e9090c8f35286d5a1a562978a38eff1 100644 (file)
 !endif
 
 [PcdsFixedAtBuild.common]
+  gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM RealView Emulation Board"
+  
   gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"ArmRealViewEb-A9x2"
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0
   #
   # 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
index 7f88fccc6823f9e3bb7ff3b435daefc6e5fbc76b..7dda73f9b20e51f83f87d56a0889112c5385996a 100644 (file)
 !endif
 
 [PcdsFixedAtBuild.common]
+  gArmPlatformTokenSpaceGuid.PcdFirmwareVendor|"ARM Versatile Express"
+  
   gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"ArmVExpress"
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0
   #
   # 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 (file)
index 0000000..415f0a9
--- /dev/null
@@ -0,0 +1,398 @@
+/** @file
+*
+*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  
+*  This program and the accompanying materials                          
+*  are licensed and made available under the terms and conditions of the BSD License         
+*  which accompanies this distribution.  The full text of the license may be found at        
+*  http://opensource.org/licenses/bsd-license.php                                            
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+*
+**/
+
+#include "BdsInternal.h"
+
+#include <Library/PcdLib.h>
+#include <Library/PerformanceLib.h>
+
+#include <Protocol/Bds.h>
+
+#define EFI_SET_TIMER_TO_SECOND   10000000
+
+EFI_HANDLE mImageHandle;
+
+STATIC
+EFI_STATUS
+GetConsoleDevicePathFromVariable (
+  IN  CHAR16*             ConsoleVarName,
+  IN  CHAR16*             DefaultConsolePaths,
+  OUT EFI_DEVICE_PATH**   DevicePaths
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     Size;
+  EFI_DEVICE_PATH_PROTOCOL* DevicePathInstances;
+  EFI_DEVICE_PATH_PROTOCOL* DevicePathInstance;
+  CHAR16*                   DevicePathStr;
+  CHAR16*                   NextDevicePathStr;
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
+
+  Status = GetEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);
+  if (EFI_ERROR(Status)) {
+    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
+    ASSERT_EFI_ERROR(Status);
+
+    DevicePathInstances = NULL;
+
+    // Extract the Device Path instances from the multi-device path string
+    while ((DefaultConsolePaths != NULL) && (DefaultConsolePaths[0] != L'\0')) {
+      NextDevicePathStr = StrStr (DefaultConsolePaths, L";");
+      if (NextDevicePathStr == NULL) {
+        DevicePathStr = DefaultConsolePaths;
+        DefaultConsolePaths = NULL;
+      } else {
+        DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DefaultConsolePaths + 1) * sizeof(CHAR16), DefaultConsolePaths);
+        *(DevicePathStr + (NextDevicePathStr - DefaultConsolePaths)) = L'\0';
+        DefaultConsolePaths = NextDevicePathStr;
+        if (DefaultConsolePaths[0] == L';') {
+          DefaultConsolePaths++;
+        }
+      }
+
+      DevicePathInstance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
+      ASSERT(DevicePathInstance != NULL);
+      DevicePathInstances = AppendDevicePathInstance (DevicePathInstances, DevicePathInstance);
+
+      if (NextDevicePathStr != NULL) {
+        FreePool (DevicePathStr);
+      }
+      FreePool (DevicePathInstance);
+    }
+
+    // Set the environment variable with this device path multi-instances
+    Size = GetDevicePathSize (DevicePathInstances);
+    if (Size > 0) {
+      Status = gRT->SetVariable (
+          ConsoleVarName,
+          &gEfiGlobalVariableGuid,
+          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+          Size,
+          DevicePathInstances
+          );
+    } else {
+      Status = EFI_INVALID_PARAMETER;
+    }
+  }
+
+  if (!EFI_ERROR(Status)) {
+    *DevicePaths = DevicePathInstances;
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+InitializeConsolePipe (
+  IN EFI_DEVICE_PATH    *ConsoleDevicePaths,
+  IN EFI_GUID           *Protocol,
+  OUT EFI_HANDLE        *Handle,
+  OUT VOID*             *Interface
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     Size;
+  UINTN                     NoHandles;
+  EFI_HANDLE                *Buffer;
+  EFI_DEVICE_PATH_PROTOCOL* DevicePath;
+
+  // Connect all the Device Path Consoles
+  do {
+    DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size);
+
+    Status = BdsConnectDevicePath (DevicePath, Handle, NULL);
+    DEBUG_CODE_BEGIN();
+      if (EFI_ERROR(Status)) {
+        // We convert back to the text representation of the device Path
+        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+        CHAR16* DevicePathTxt;
+
+        ASSERT_EFI_ERROR(gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol));
+        DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);
+
+        DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status));
+
+        FreePool (DevicePathTxt);
+      }
+    DEBUG_CODE_END();
+
+    // If the console splitter driver is not supported by the platform then use the first Device Path
+    // instance for the console interface.
+    if (!EFI_ERROR(Status) && (*Interface == NULL)) {
+      Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
+    }
+  } while (ConsoleDevicePaths != NULL);
+
+  // No Device Path has been defined for this console interface. We take the first protocol implementation
+  if (*Interface == NULL) {
+    Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
+    if (EFI_ERROR (Status)) {
+      BdsConnectAllDrivers();
+      Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
+    }
+
+    if (!EFI_ERROR(Status)) {
+      *Handle = Buffer[0];
+      Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
+      ASSERT_EFI_ERROR(Status);
+    }
+    FreePool (Buffer);
+  } else {
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+InitializeConsole (
+  VOID
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH*          ConOutDevicePaths;
+  EFI_DEVICE_PATH*          ConInDevicePaths;
+  EFI_DEVICE_PATH*          ConErrDevicePaths;
+
+  // By getting the Console Device Paths from the environment variables before initializing the console pipe, we
+  // create the 3 environment variables (ConIn, ConOut, ConErr) that allows to initialize all the console interface
+  // of newly installed console drivers
+  Status = GetConsoleDevicePathFromVariable (L"ConOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths),&ConOutDevicePaths);
+  ASSERT_EFI_ERROR (Status);
+  Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths),&ConInDevicePaths);
+  ASSERT_EFI_ERROR (Status);
+  Status = GetConsoleDevicePathFromVariable (L"ConErr", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths),&ConErrDevicePaths);
+  ASSERT_EFI_ERROR (Status);
+
+  // Initialize the Consoles
+  Status = InitializeConsolePipe (ConOutDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut);
+  ASSERT_EFI_ERROR (Status);
+  Status = InitializeConsolePipe (ConInDevicePaths, &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn);
+  ASSERT_EFI_ERROR (Status);
+  Status = InitializeConsolePipe (ConErrDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr);
+  if (EFI_ERROR(Status)) {
+    // In case of error, we reuse the console output for the error output
+    gST->StandardErrorHandle = gST->ConsoleOutHandle;
+    gST->StdErr = gST->ConOut;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DefineDefaultBootEntries (
+  VOID
+  )
+{
+  BDS_LOAD_OPTION     *BdsLoadOption;
+  UINTN               Size;
+  EFI_STATUS          Status;
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
+  EFI_DEVICE_PATH*    BootDevicePath;
+
+  //
+  // If Boot Order does not exist then create a default entry
+  //
+  Size = 0;
+  Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);
+  if (Status == EFI_NOT_FOUND) {
+    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
+    ASSERT_EFI_ERROR(Status);
+    BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath));
+
+    DEBUG_CODE_BEGIN();
+      // We convert back to the text representation of the device Path to see if the initial text is correct
+      EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
+      CHAR16* DevicePathTxt;
+
+      Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
+      ASSERT_EFI_ERROR(Status);
+      DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE);
+
+      ASSERT (StrCmp ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath), DevicePathTxt) == 0);
+
+      FreePool (DevicePathTxt);
+    DEBUG_CODE_END();
+
+    // Create the entry is the Default values are correct
+    if (BootDevicePath != NULL) {
+      BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
+        (CHAR16*)PcdGetPtr(PcdDefaultBootDescription),
+        BootDevicePath,
+        (BDS_LOADER_TYPE)PcdGet32 (PcdDefaultBootType),
+        (CHAR8*)PcdGetPtr(PcdDefaultBootArgument),
+        &BdsLoadOption
+        );
+      FreePool (BdsLoadOption);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+StartDefaultBootOnTimeout (
+  VOID
+  )
+{
+  UINTN               Size;
+  UINT16              Timeout;
+  UINT16              *TimeoutPtr;
+  EFI_EVENT           WaitList[2];
+  UINTN               WaitIndex;
+  UINT16              *BootOrder;
+  UINTN               BootOrderSize;
+  UINTN               Index;
+  CHAR16              BootVariableName[9];
+  EFI_STATUS           Status;
+
+  Size = sizeof(UINT16);
+  Timeout = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);
+  TimeoutPtr = &Timeout;
+  GetEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);
+
+  if (Timeout != 0xFFFF) {
+    if (Timeout > 0) {
+      // Create the waiting events (keystroke and 1sec timer)
+      gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[0]);
+      gBS->SetTimer (WaitList[0], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);
+      WaitList[1] = gST->ConIn->WaitForKey;
+
+      // Start the timer
+      WaitIndex = 0;
+      Print(L"The default boot selection will start in ");
+      while ((Timeout > 0) && (WaitIndex == 0)) {
+        Print(L"%3d seconds",Timeout);
+        gBS->WaitForEvent (2, WaitList, &WaitIndex);
+        if (WaitIndex == 0) {
+          Print(L"\b\b\b\b\b\b\b\b\b\b\b");
+          Timeout--;
+        }
+      }
+      gBS->CloseEvent (WaitList[0]);
+      Print(L"\n\r");
+    }
+
+    // In case of Timeout we start the default boot selection
+    if (Timeout == 0) {
+      // Get the Boot Option Order from the environment variable (a default value should have been created)
+      GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+
+      for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+        UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOrder[Index]);
+        Status = BdsStartBootOption (BootVariableName);
+        if(!EFI_ERROR(Status)){
+               // Boot option returned successfully, hence don't need to start next boot option
+               break;
+        }
+        // In case of success, we should not return from this call.
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  This function uses policy data from the platform to determine what operating 
+  system or system utility should be loaded and invoked.  This function call 
+  also optionally make the use of user input to determine the operating system 
+  or system utility to be loaded and invoked.  When the DXE Core has dispatched 
+  all the drivers on the dispatch queue, this function is called.  This 
+  function will attempt to connect the boot devices required to load and invoke 
+  the selected operating system or system utility.  During this process, 
+  additional firmware volumes may be discovered that may contain addition DXE 
+  drivers that can be dispatched by the DXE Core.   If a boot device cannot be 
+  fully connected, this function calls the DXE Service Dispatch() to allow the 
+  DXE drivers from any newly discovered firmware volumes to be dispatched.  
+  Then the boot device connection can be attempted again.  If the same boot 
+  device connection operation fails twice in a row, then that boot device has 
+  failed, and should be skipped.  This function should never return.
+
+  @param  This             The EFI_BDS_ARCH_PROTOCOL instance.
+
+  @return None.
+
+**/
+VOID
+EFIAPI
+BdsEntry (
+  IN EFI_BDS_ARCH_PROTOCOL  *This
+  )
+{
+  UINTN               Size;
+  EFI_STATUS          Status;
+
+  PERF_END   (NULL, "DXE", NULL, 0);
+
+  //
+  // Declare the Firmware Vendor
+  //
+  Size = 0x100;
+  gST->FirmwareVendor = AllocateRuntimePool (Size);
+  ASSERT (gST->FirmwareVendor != NULL);
+  UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__);
+
+  // If BootNext environment variable is defined then we just load it !
+  Status = BdsStartBootOption (L"BootNext");
+  if (Status != EFI_NOT_FOUND) {
+    // BootNext has not been succeeded launched
+    if (EFI_ERROR(Status)) {
+      Print(L"Fail to start BootNext.\n");
+    }
+
+    // Delete the BootNext environment variable
+    gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+        0, NULL);
+  }
+
+  // If Boot Order does not exist then create a default entry
+  DefineDefaultBootEntries ();
+
+  // Now we need to setup the EFI System Table with information about the console devices.
+  InitializeConsole ();
+
+  // Timer before initiating the default boot selection
+  StartDefaultBootOnTimeout ();
+
+  // Start the Boot Menu
+  Status = BootMenuMain ();
+  ASSERT_EFI_ERROR (Status);
+
+}
+
+EFI_BDS_ARCH_PROTOCOL  gBdsProtocol = {
+  BdsEntry,
+};
+
+EFI_STATUS
+EFIAPI
+BdsInitialize (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  mImageHandle = ImageHandle;
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gEfiBdsArchProtocolGuid, &gBdsProtocol,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
index dbd26aedb496ffbe3b163f1630bffc15267e2063..5749e7c61b3c111454665d974ac131147fb57119 100644 (file)
@@ -2,7 +2,7 @@
 #  
 #  Component discription file for NorFlashDxe module
 #  
-#  Copyright (c) 2010, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD License
 #  which accompanies this distribution.  The full text of the license may be found at
   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 (file)
index 62e8236..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/** @file
-*
-*  Copyright (c) 2011, ARM Limited. All rights reserved.
-*  
-*  This program and the accompanying materials                          
-*  are licensed and made available under the terms and conditions of the BSD License         
-*  which accompanies this distribution.  The full text of the license may be found at        
-*  http://opensource.org/licenses/bsd-license.php                                            
-*
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
-*
-**/
-
-#include <PiDxe.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiLib.h>
-#include <Library/PerformanceLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/PcdLib.h>
-#include <Library/BdsUnixLib.h>
-
-#include <Protocol/Bds.h>
-#include <Protocol/DevicePathToText.h>
-
-#include <Guid/GlobalVariable.h>
-
-#define MAX_CMD_LINE            256
-
-VOID
-EFIAPI
-BdsEntry (
-  IN EFI_BDS_ARCH_PROTOCOL  *This
-  );
-
-EFI_HANDLE  mBdsImageHandle = NULL;
-EFI_BDS_ARCH_PROTOCOL  gBdsProtocol = {
-  BdsEntry,
-};
-
-EFI_STATUS GetEnvironmentVariable (
-    IN  CONST CHAR16*   VariableName,
-    IN  VOID*           DefaultValue,
-    IN  UINTN           DefaultSize,
-    OUT VOID**          Value)
-{
-    EFI_STATUS  Status;
-    UINTN       Size;
-
-    // Try to get the variable size.
-    *Value = NULL;
-    Size = 0;
-    Status = gRT->GetVariable ((CHAR16 *) VariableName, &gEfiGlobalVariableGuid, NULL, &Size, *Value);
-    if (Status == EFI_NOT_FOUND) {
-        // If the environment variable does not exist yet then set it with the default value
-        Status = gRT->SetVariable (
-                      (CHAR16*)VariableName,
-                      &gEfiGlobalVariableGuid,
-                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
-                      DefaultSize,
-                      DefaultValue
-                      );
-        *Value = DefaultValue;
-    } else if (Status == EFI_BUFFER_TOO_SMALL) {
-        // Get the environment variable value
-        *Value = AllocatePool (Size);
-        if (*Value == NULL) {
-            return EFI_OUT_OF_RESOURCES;
-        }
-
-        Status = gRT->GetVariable ((CHAR16 *)VariableName, &gEfiGlobalVariableGuid, NULL, &Size, *Value);
-        if (EFI_ERROR (Status)) {
-            FreePool(*Value);
-            return EFI_INVALID_PARAMETER;
-        }
-    } else {
-        *Value = DefaultValue;
-        return Status;
-    }
-
-    return EFI_SUCCESS;
-}
-
-EFI_STATUS
-InitializeConsole (
-  VOID                   
-  )
-{
-  EFI_STATUS                Status;
-  UINTN                     NoHandles;
-  EFI_HANDLE                *Buffer;
-  BOOLEAN                   AllDriversConnected;
-
-  AllDriversConnected = FALSE;
-
-  //
-  // Now we need to setup the EFI System Table with information about the console devices.
-  // This code is normally in the console spliter driver on platforms that support multiple 
-  // consoles at the same time
-  //
-  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer);
-  if (EFI_ERROR (Status)) {
-    BdsConnectAllDrivers();
-    AllDriversConnected = TRUE;
-    Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer);
-  }
-
-  if (!EFI_ERROR (Status)) {
-    // Use the first SimpleTextOut we find and update the EFI System Table
-    gST->ConsoleOutHandle = Buffer[0];
-    gST->StandardErrorHandle = Buffer[0];
-    Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextOutProtocolGuid, (VOID **)&gST->ConOut);
-    ASSERT_EFI_ERROR (Status);
-    
-    gST->StdErr = gST->ConOut;
-    
-    FreePool (Buffer);
-  } else {
-    return Status;
-  }
-  
-  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer);
-  if (EFI_ERROR (Status) && !AllDriversConnected) {
-    BdsConnectAllDrivers();
-    Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer);
-  }
-
-  if (!EFI_ERROR (Status)) {
-    // Use the first SimpleTextIn we find and update the EFI System Table
-    gST->ConsoleInHandle = Buffer[0];
-    Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextInProtocolGuid, (VOID **)&gST->ConIn);
-    ASSERT_EFI_ERROR (Status);
-    
-    FreePool (Buffer);
-  } else {
-    return Status;
-  }
-
-  return EFI_SUCCESS;
-}
-
-EFI_STATUS
-GetHIInputAscii (
-    CHAR8   *CmdLine,
-    UINTN   MaxCmdLine
-) {
-    UINTN           CmdLineIndex;
-    UINTN           WaitIndex;
-    CHAR8           Char;
-    EFI_INPUT_KEY   Key;
-    EFI_STATUS      Status;
-
-    CmdLine[0] = '\0';
-
-    for (CmdLineIndex = 0; CmdLineIndex < MaxCmdLine; ) {
-        Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
-        ASSERT_EFI_ERROR (Status);
-
-        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-        ASSERT_EFI_ERROR (Status);
-
-        Char = (CHAR8)Key.UnicodeChar;
-        if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) {
-            CmdLine[CmdLineIndex] = '\0';
-            AsciiPrint ("\n");
-            return EFI_SUCCESS;
-        } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
-            if (CmdLineIndex != 0) {
-                CmdLineIndex--;
-                AsciiPrint ("\b \b");
-            }
-        } else {
-            CmdLine[CmdLineIndex++] = Char;
-            AsciiPrint ("%c", Char);
-        }
-    }
-
-    return EFI_SUCCESS;
-}
-
-VOID
-ListDevicePaths (
-               IN BOOLEAN      AllDrivers
-) {
-       EFI_STATUS Status;
-       UINTN                                   HandleCount;
-       EFI_HANDLE                              *HandleBuffer;
-       UINTN                                   Index;
-       EFI_DEVICE_PATH_PROTOCOL*               DevicePathProtocol;
-       CHAR16*                                                 String;
-       EFI_DEVICE_PATH_TO_TEXT_PROTOCOL*       EfiDevicePathToTextProtocol;
-
-       if (AllDrivers) {
-               BdsConnectAllDrivers();
-       }
-
-    Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&EfiDevicePathToTextProtocol);
-       if (EFI_ERROR (Status)) {
-               AsciiPrint ("Did not find the DevicePathToTextProtocol.\n");
-           return;
-       }
-
-       Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleCount, &HandleBuffer);
-       if (EFI_ERROR (Status)) {
-               AsciiPrint ("No device path found\n");
-           return;
-       }
-
-       for (Index = 0; Index < HandleCount; Index++) {
-               Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
-               String = EfiDevicePathToTextProtocol->ConvertDevicePathToText(DevicePathProtocol,TRUE,TRUE);
-               Print (L"\t- [%d] %s\n",Index, String);
-       }
-}
-
-INTN BdsComparefile (
-    IN  CHAR16        *DeviceFilePath1,
-    IN  CHAR16        *DeviceFilePath2,
-    VOID **FileImage1,VOID **FileImage2,UINTN* FileSize
-    );
-
-/**
-  This function uses policy data from the platform to determine what operating 
-  system or system utility should be loaded and invoked.  This function call 
-  also optionally make the use of user input to determine the operating system 
-  or system utility to be loaded and invoked.  When the DXE Core has dispatched 
-  all the drivers on the dispatch queue, this function is called.  This 
-  function will attempt to connect the boot devices required to load and invoke 
-  the selected operating system or system utility.  During this process, 
-  additional firmware volumes may be discovered that may contain addition DXE 
-  drivers that can be dispatched by the DXE Core.   If a boot device cannot be 
-  fully connected, this function calls the DXE Service Dispatch() to allow the 
-  DXE drivers from any newly discovered firmware volumes to be dispatched.  
-  Then the boot device connection can be attempted again.  If the same boot 
-  device connection operation fails twice in a row, then that boot device has 
-  failed, and should be skipped.  This function should never return.
-
-  @param  This             The EFI_BDS_ARCH_PROTOCOL instance.
-
-  @return None.
-
-**/
-VOID
-EFIAPI
-BdsEntry (
-  IN EFI_BDS_ARCH_PROTOCOL  *This
-  )
-{
-    EFI_STATUS          Status;
-    CHAR8               CmdLine[MAX_CMD_LINE];
-    VOID*               DefaultVariableValue;
-    UINTN               DefaultVariableSize;
-    CHAR16              *LinuxKernelDP;
-    CHAR8               *LinuxAtag;
-    CHAR16              *FdtDP;
-
-    PERF_END   (NULL, "DXE", NULL, 0);
-    PERF_START (NULL, "BDS", NULL, 0);
-
-    Status = InitializeConsole();
-    ASSERT_EFI_ERROR(Status);
-
-    while (1) {
-      // Get the Linux Kernel Device Path from Environment Variable
-      DefaultVariableValue = (VOID*)PcdGetPtr(PcdLinuxKernelDP);
-      DefaultVariableSize = StrSize((CHAR16*)DefaultVariableValue);
-      GetEnvironmentVariable(L"LinuxKernelDP",DefaultVariableValue,DefaultVariableSize,(VOID**)&LinuxKernelDP);
-
-      // Get the Linux ATAG from Environment Variable
-      DefaultVariableValue = (VOID*)PcdGetPtr(PcdLinuxAtag);
-      DefaultVariableSize = AsciiStrSize((CHAR8*)DefaultVariableValue);
-      GetEnvironmentVariable(L"LinuxAtag",DefaultVariableValue,DefaultVariableSize,(VOID**)&LinuxAtag);
-
-      // Get the FDT Device Path from Environment Variable
-      DefaultVariableValue = (VOID*)PcdGetPtr(PcdFdtDP);
-      DefaultVariableSize = StrSize((CHAR16*)DefaultVariableValue);
-      GetEnvironmentVariable(L"FdtDP",DefaultVariableValue,DefaultVariableSize,(VOID**)&FdtDP);
-
-        AsciiPrint ("1. Start EBL\n\r");
-        AsciiPrint ("2. List Device Paths of all the drivers\n");
-        AsciiPrint ("3. Start Linux\n");
-        Print (L"\t- Kernel: %s\n", LinuxKernelDP);
-        AsciiPrint ("\t- Atag: %a\n", LinuxAtag);
-        Print (L"\t- Fdt: %s\n", FdtDP);
-        AsciiPrint ("Choice: ");
-
-        Status = GetHIInputAscii(CmdLine,MAX_CMD_LINE);
-        ASSERT_EFI_ERROR (Status);
-        if (AsciiStrCmp(CmdLine,"1") == 0) {
-            // Start EBL
-            Status = BdsLoadApplication(L"Ebl");
-            if (Status == EFI_NOT_FOUND) {
-                AsciiPrint ("Error: EFI Application not found.\n");
-            } else {
-                AsciiPrint ("Error: Status Code: 0x%X\n",(UINT32)Status);
-            }
-        } else if (AsciiStrCmp(CmdLine,"2") == 0) {
-               ListDevicePaths (TRUE);
-        } else if (AsciiStrCmp(CmdLine,"3") == 0) {
-            // Start Linux Kernel
-            Status = BdsBootLinux(LinuxKernelDP,LinuxAtag,FdtDP);
-            if (EFI_ERROR(Status)) {
-                AsciiPrint ("Error: Fail to start Linux (0x%X)\n",(UINT32)Status);
-            }
-        } else {
-            AsciiPrint ("Error: Invalid choice.\n");
-        }
-    }
-}
-
-EFI_STATUS
-EFIAPI
-BdsInitialize (
-  IN EFI_HANDLE                            ImageHandle,
-  IN EFI_SYSTEM_TABLE                      *SystemTable
-  )
-{
-  EFI_STATUS  Status;
-
-  mBdsImageHandle = ImageHandle;
-
-  Status = gBS->InstallMultipleProtocolInterfaces (
-                  &mBdsImageHandle,
-                  &gEfiBdsArchProtocolGuid, &gBdsProtocol,
-                  NULL
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  return Status;
-}
diff --git a/ArmPlatformPkg/Bds/BdsHelper.c b/ArmPlatformPkg/Bds/BdsHelper.c
new file mode 100644 (file)
index 0000000..2f0cb31
--- /dev/null
@@ -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 (file)
index 0000000..9ef36a1
--- /dev/null
@@ -0,0 +1,214 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#ifndef _BDSINTERNAL_H_\r
+#define _BDSINTERNAL_H_\r
+\r
+#include <PiDxe.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BdsLib.h>\r
+#include <Library/BdsUnixLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+#include <Protocol/DevicePathFromText.h>\r
+#include <Protocol/DevicePathToText.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+\r
+#define BOOT_DEVICE_DESCRIPTION_MAX   100\r
+#define BOOT_DEVICE_FILEPATH_MAX      100\r
+#define BOOT_DEVICE_OPTION_MAX        100\r
+#define BOOT_DEVICE_ADDRESS_MAX       20\r
+\r
+typedef enum {\r
+    BDS_LOADER_EFI_APPLICATION = 0,\r
+    BDS_LOADER_KERNEL_LINUX_ATAG,\r
+    BDS_LOADER_KERNEL_LINUX_FDT,\r
+} BDS_LOADER_TYPE;\r
+\r
+typedef struct {\r
+  BDS_LOADER_TYPE   LoaderType;\r
+  CHAR8             Arguments[];\r
+} BDS_LOADER_OPTIONAL_DATA;\r
+\r
+typedef enum {\r
+  BDS_DEVICE_FILESYSTEM = 0,\r
+  BDS_DEVICE_MEMMAP,\r
+  BDS_DEVICE_PXE,\r
+  BDS_DEVICE_TFTP,\r
+  BDS_DEVICE_MAX\r
+} BDS_SUPPORTED_DEVICE_TYPE;\r
+\r
+typedef struct {\r
+  LIST_ENTRY                  Link;\r
+  CHAR16                      Description[BOOT_DEVICE_DESCRIPTION_MAX];\r
+  EFI_DEVICE_PATH_PROTOCOL*   DevicePathProtocol;\r
+  struct _BDS_LOAD_OPTION_SUPPORT*    Support;\r
+} BDS_SUPPORTED_DEVICE;\r
+\r
+#define SUPPORTED_BOOT_DEVICE_FROM_LINK(a)   BASE_CR(a, BDS_SUPPORTED_DEVICE, Link)\r
+\r
+typedef UINT8* EFI_LOAD_OPTION;\r
+\r
+typedef struct {\r
+  LIST_ENTRY                  Link;\r
+\r
+  UINT16                      LoadOptionIndex;\r
+  EFI_LOAD_OPTION             LoadOption;\r
+  UINTN                       LoadOptionSize;\r
+\r
+  UINT32                      Attributes;\r
+  UINT16                      FilePathListLength;\r
+  CHAR16                      *Description;\r
+  EFI_DEVICE_PATH_PROTOCOL    *FilePathList;\r
+  BDS_LOADER_OPTIONAL_DATA    *OptionalData;\r
+} BDS_LOAD_OPTION;\r
+\r
+typedef struct _BDS_LOAD_OPTION_SUPPORT {\r
+  BDS_SUPPORTED_DEVICE_TYPE   Type;\r
+  EFI_STATUS    (*ListDevices)(IN OUT LIST_ENTRY* BdsLoadOptionList);\r
+  BOOLEAN       (*IsSupported)(IN BDS_LOAD_OPTION* BdsLoadOption);\r
+  EFI_STATUS    (*CreateDevicePathNode)(IN  BDS_SUPPORTED_DEVICE* BdsLoadOption, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode, OUT BDS_LOADER_TYPE *BootType, OUT UINT32 *Attributes);\r
+  EFI_STATUS    (*UpdateDevicePathNode)(IN BDS_LOAD_OPTION *BootOption, OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath, OUT BDS_LOADER_TYPE *BootType, OUT UINT32 *Attributes);\r
+} BDS_LOAD_OPTION_SUPPORT;\r
+\r
+#define LOAD_OPTION_FROM_LINK(a)   BASE_CR(a, BDS_LOAD_OPTION, Link)\r
+\r
+EFI_STATUS\r
+GetEnvironmentVariable (\r
+  IN     CONST CHAR16*   VariableName,\r
+  IN     VOID*           DefaultValue,\r
+  IN OUT UINTN*          Size,\r
+  OUT    VOID**          Value\r
+  );\r
+\r
+EFI_STATUS\r
+BootDeviceListSupportedInit (\r
+  IN OUT LIST_ENTRY *SupportedDeviceList\r
+  );\r
+\r
+EFI_STATUS\r
+BootDeviceListSupportedFree (\r
+  IN LIST_ENTRY *SupportedDeviceList\r
+  );\r
+\r
+EFI_STATUS\r
+BootDeviceGetDeviceSupport (\r
+  IN  BDS_LOAD_OPTION *BootOption,\r
+  OUT BDS_LOAD_OPTION_SUPPORT**  DeviceSupport\r
+  );\r
+\r
+EFI_STATUS\r
+GetHIInputAscii (\r
+  IN OUT CHAR8   *CmdLine,\r
+  IN     UINTN   MaxCmdLine\r
+  );\r
+\r
+EFI_STATUS\r
+EditHIInputAscii (\r
+  IN OUT CHAR8   *CmdLine,\r
+  IN     UINTN   MaxCmdLine\r
+  );\r
+\r
+EFI_STATUS\r
+GetHIInputInteger (\r
+  IN OUT UINTN   *Integer\r
+  );\r
+\r
+EFI_STATUS\r
+GetHIInputIP (\r
+  OUT EFI_IP_ADDRESS   *Ip\r
+  );\r
+\r
+EFI_STATUS\r
+GetHIInputBoolean (\r
+  OUT BOOLEAN *Value\r
+  );\r
+\r
+BOOLEAN\r
+HasFilePathEfiExtension (\r
+  IN CHAR16* FilePath\r
+  );\r
+\r
+EFI_DEVICE_PATH*\r
+GetLastDevicePathNode (\r
+  IN EFI_DEVICE_PATH*  DevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+BdsStartBootOption (\r
+  IN CHAR16* BootOption\r
+  );\r
+\r
+EFI_STATUS\r
+GenerateDeviceDescriptionName (\r
+  IN  EFI_HANDLE  Handle,\r
+  IN OUT CHAR16*  Description\r
+  );\r
+\r
+EFI_STATUS\r
+BootOptionList (\r
+  IN OUT LIST_ENTRY *BootOptionList\r
+  );\r
+\r
+EFI_STATUS\r
+BootOptionParseLoadOption (\r
+  IN  EFI_LOAD_OPTION EfiLoadOption,\r
+  IN  UINTN           EfiLoadOptionSize,\r
+  OUT BDS_LOAD_OPTION **BdsLoadOption\r
+  );\r
+\r
+EFI_STATUS\r
+BootOptionStart (\r
+  IN BDS_LOAD_OPTION *BootOption\r
+  );\r
+\r
+EFI_STATUS\r
+BootOptionCreate (\r
+  IN  UINT32 Attributes,\r
+  IN  CHAR16* BootDescription,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  IN  BDS_LOADER_TYPE   BootType,\r
+  IN  CHAR8*            BootArguments,\r
+  OUT BDS_LOAD_OPTION **BdsLoadOption\r
+  );\r
+\r
+EFI_STATUS\r
+BootOptionUpdate (\r
+  IN  BDS_LOAD_OPTION *BdsLoadOption,\r
+  IN  UINT32 Attributes,\r
+  IN  CHAR16* BootDescription,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  IN  BDS_LOADER_TYPE   BootType,\r
+  IN  CHAR8*            BootArguments\r
+  );\r
+\r
+EFI_STATUS\r
+BootOptionDelete (\r
+  IN  BDS_LOAD_OPTION *BootOption\r
+  );\r
+\r
+EFI_STATUS\r
+BootMenuMain (\r
+  VOID\r
+  );\r
+\r
+#endif /* _BDSINTERNAL_H_ */\r
diff --git a/ArmPlatformPkg/Bds/BootMenu.c b/ArmPlatformPkg/Bds/BootMenu.c
new file mode 100644 (file)
index 0000000..a2360d1
--- /dev/null
@@ -0,0 +1,487 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "BdsInternal.h"\r
+\r
+extern EFI_HANDLE mImageHandle;\r
+extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r
+\r
+EFI_STATUS\r
+BootMenuAddBootOption (\r
+  IN LIST_ENTRY *BootOptionsList\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  LIST_ENTRY  SupportedDeviceList;\r
+  UINTN       SupportedDeviceCount;\r
+  BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r
+  LIST_ENTRY* Entry;\r
+  UINTN       SupportedDeviceSelected;\r
+  CHAR8       AsciiBootOption[BOOT_DEVICE_OPTION_MAX];\r
+  CHAR8       AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
+  CHAR16      *BootDescription;\r
+  UINT32      Attributes;\r
+  BDS_LOADER_TYPE   BootType;\r
+  UINTN       Index;\r
+  BDS_LOAD_OPTION *BdsLoadOption;\r
+  EFI_DEVICE_PATH*  DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
+\r
+  Attributes = 0;\r
+\r
+  //\r
+  // List the Boot Devices supported\r
+  //\r
+\r
+  // Start all the drivers first\r
+  BdsConnectAllDrivers ();\r
+\r
+  // List the supported devices\r
+  Status = BootDeviceListSupportedInit (&SupportedDeviceList);\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  SupportedDeviceCount = 0;\r
+  for (Entry = GetFirstNode (&SupportedDeviceList);\r
+       !IsNull (&SupportedDeviceList,Entry);\r
+       Entry = GetNextNode (&SupportedDeviceList,Entry)\r
+       )\r
+  {\r
+    SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
+    Print(L"[%d] %s\n",SupportedDeviceCount+1,SupportedBootDevice->Description);\r
+\r
+    DEBUG_CODE_BEGIN();\r
+      CHAR16*                           DevicePathTxt;\r
+      EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+\r
+      Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+      ASSERT_EFI_ERROR(Status);\r
+      DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(SupportedBootDevice->DevicePathProtocol,TRUE,TRUE);\r
+\r
+      Print(L"\t- %s\n",DevicePathTxt);\r
+\r
+      FreePool(DevicePathTxt);\r
+    DEBUG_CODE_END();\r
+\r
+    SupportedDeviceCount++;\r
+  }\r
+\r
+  if (SupportedDeviceCount == 0) {\r
+    Print(L"There is no supported device.\n");\r
+    Status = EFI_ABORTED;\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Select the Boot Device\r
+  //\r
+  SupportedDeviceSelected = 0;\r
+  while (SupportedDeviceSelected == 0) {\r
+    Print(L"Select the Boot Device: ");\r
+    Status = GetHIInputInteger (&SupportedDeviceSelected);\r
+    if (EFI_ERROR(Status)) {\r
+      Status = EFI_ABORTED;\r
+      goto EXIT;\r
+    } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {\r
+      Print(L"Invalid input (max %d)\n",SupportedDeviceSelected);\r
+      SupportedDeviceSelected = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get the Device Path for the selected boot device\r
+  //\r
+  Index = 1;\r
+  for (Entry = GetFirstNode (&SupportedDeviceList);\r
+       !IsNull (&SupportedDeviceList,Entry);\r
+       Entry = GetNextNode (&SupportedDeviceList,Entry)\r
+       )\r
+  {\r
+    if (Index == SupportedDeviceSelected) {\r
+      SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
+      break;\r
+    }\r
+    Index++;\r
+  }\r
+\r
+  // Create the specific device path node\r
+  Status = SupportedBootDevice->Support->CreateDevicePathNode (SupportedBootDevice, &DevicePathNode, &BootType, &Attributes);\r
+  if (EFI_ERROR(Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto EXIT;\r
+  }\r
+  // Append the Device Path node to the select device path\r
+  DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);\r
+\r
+  Print(L"Arguments to pass to the binary: ");\r
+  Status = GetHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto FREE_DEVICE_PATH;\r
+  }\r
+\r
+  Print(L"Description for this new Entry: ");\r
+  Status = GetHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto FREE_DEVICE_PATH;\r
+  }\r
+\r
+  // Convert Ascii into Unicode\r
+  BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));\r
+  AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);\r
+\r
+  // Create new entry\r
+  Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, AsciiBootOption, &BdsLoadOption);\r
+  if (!EFI_ERROR(Status)) {\r
+    InsertTailList (BootOptionsList,&BdsLoadOption->Link);\r
+  }\r
+\r
+  FreePool (BootDescription);\r
+\r
+FREE_DEVICE_PATH:\r
+  FreePool (DevicePath);\r
+\r
+EXIT:\r
+  BootDeviceListSupportedFree (&SupportedDeviceList);\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+BootMenuSelectBootOption (\r
+  IN  LIST_ENTRY *BootOptionsList,\r
+  IN  CONST CHAR16* InputStatement,\r
+  OUT BDS_LOAD_OPTION **BdsLoadOption\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  LIST_ENTRY*   Entry;\r
+  BDS_LOAD_OPTION *BootOption;\r
+  UINTN         BootOptionSelected;\r
+  UINTN         BootOptionCount;\r
+  UINTN         Index;\r
+\r
+  // Display the list of supported boot devices\r
+  BootOptionCount = 1;\r
+  for (Entry = GetFirstNode (BootOptionsList);\r
+       !IsNull (BootOptionsList,Entry);\r
+       Entry = GetNextNode (BootOptionsList,Entry)\r
+       )\r
+  {\r
+    BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
+    Print(L"[%d] %s\n",BootOptionCount,BootOption->Description);\r
+\r
+    DEBUG_CODE_BEGIN();\r
+      CHAR16*                           DevicePathTxt;\r
+      EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+\r
+      Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+      ASSERT_EFI_ERROR(Status);\r
+      DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);\r
+\r
+      Print(L"\t- %s\n",DevicePathTxt);\r
+      if ((BootOption->OptionalData != NULL) && (BootOption->OptionalData->Arguments != NULL)) {\r
+        Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);\r
+      }\r
+\r
+      FreePool(DevicePathTxt);\r
+    DEBUG_CODE_END();\r
+\r
+    BootOptionCount++;\r
+  }\r
+\r
+  // Get the index of the boot device to delete\r
+  BootOptionSelected = 0;\r
+  while (BootOptionSelected == 0) {\r
+    Print(InputStatement);\r
+    Status = GetHIInputInteger (&BootOptionSelected);\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    } else if ((BootOptionSelected == 0) || (BootOptionSelected >= BootOptionCount)) {\r
+      Print(L"Invalid input (max %d)\n",BootOptionCount);\r
+      BootOptionSelected = 0;\r
+    }\r
+  }\r
+\r
+  // Get the structure of the Boot device to delete\r
+  Index = 1;\r
+  for (Entry = GetFirstNode (BootOptionsList);\r
+       !IsNull (BootOptionsList,Entry);\r
+       Entry = GetNextNode (BootOptionsList,Entry)\r
+       )\r
+  {\r
+    if (Index == BootOptionSelected) {\r
+      *BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);\r
+      break;\r
+    }\r
+    Index++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootMenuRemoveBootOption (\r
+  IN LIST_ENTRY *BootOptionsList\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  BDS_LOAD_OPTION *BootOption;\r
+\r
+  Status = BootMenuSelectBootOption (BootOptionsList,L"Delete entry: ",&BootOption);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Delete the BDS Load option structures\r
+  BootOptionDelete (BootOption);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootMenuUpdateBootOption (\r
+  IN LIST_ENTRY *BootOptionsList\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  BDS_LOAD_OPTION *BootOption;\r
+  BDS_LOAD_OPTION_SUPPORT*  DeviceSupport;\r
+  CHAR8       AsciiBootOption[BOOT_DEVICE_OPTION_MAX];\r
+  CHAR8       AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
+  CHAR16      *BootDescription;\r
+  EFI_DEVICE_PATH* DevicePath;\r
+  UINT32      Attributes;\r
+  BDS_LOADER_TYPE   BootType;\r
+\r
+  Status = BootMenuSelectBootOption (BootOptionsList,L"Update entry: ",&BootOption);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Get the device support for this Boot Option\r
+  Status = BootDeviceGetDeviceSupport (BootOption,&DeviceSupport);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"Impossible to retrieve the supported device for the update\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = DeviceSupport->UpdateDevicePathNode (BootOption,&DevicePath,&BootType,&Attributes);\r
+  if (EFI_ERROR(Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto EXIT;\r
+  }\r
+\r
+  Print(L"Arguments to pass to the binary: ");\r
+  if (BootOption->OptionalData) {\r
+    AsciiStrnCpy(AsciiBootOption,BootOption->OptionalData->Arguments,BOOT_DEVICE_FILEPATH_MAX);\r
+  } else {\r
+    AsciiBootOption[0] = '\0';\r
+  }\r
+  Status = EditHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto FREE_DEVICE_PATH;\r
+  }\r
+\r
+  Print(L"Description for this new Entry: ");\r
+  UnicodeStrToAsciiStr (BootOption->Description,AsciiBootDescription);\r
+  Status = EditHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    Status = EFI_ABORTED;\r
+    goto FREE_DEVICE_PATH;\r
+  }\r
+\r
+  // Convert Ascii into Unicode\r
+  BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));\r
+  AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);\r
+\r
+  // Update the entry\r
+  Status = BootOptionUpdate (BootOption, Attributes, BootDescription, DevicePath, BootType, AsciiBootOption);\r
+\r
+  FreePool (BootDescription);\r
+\r
+FREE_DEVICE_PATH:\r
+  FreePool (DevicePath);\r
+\r
+EXIT:\r
+  return Status;\r
+}\r
+\r
+struct BOOT_MANAGER_ENTRY {\r
+  CONST CHAR16* Description;\r
+  EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
+} BootManagerEntries[] = {\r
+    { L"Add Boot Device Entry", BootMenuAddBootOption },\r
+    { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
+    { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
+};\r
+\r
+EFI_STATUS\r
+BootMenuManager (\r
+  IN LIST_ENTRY *BootOptionsList\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN OptionSelected;\r
+  UINTN BootManagerEntryCount;\r
+  EFI_STATUS Status;\r
+\r
+  BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
+\r
+  while (TRUE) {\r
+    // Display Boot Manager menu\r
+    for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
+      Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
+    }\r
+    Print(L"[%d] Return to main menu\n",Index+1);\r
+\r
+    // Select which entry to call\r
+    Print(L"Choice: ");\r
+    Status = GetHIInputInteger (&OptionSelected);\r
+    if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
+      return EFI_SUCCESS;\r
+    } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount))  {\r
+      Status = BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootEBL (\r
+  IN LIST_ENTRY *BootOptionsList\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  // Start EFI Shell\r
+  Status = BdsLoadApplication(mImageHandle, L"Ebl");\r
+  if (Status == EFI_NOT_FOUND) {\r
+    Print (L"Error: EFI Application not found.\n");\r
+  } else if (EFI_ERROR(Status)) {\r
+    Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+struct BOOT_MAIN_ENTRY {\r
+  CONST CHAR16* Description;\r
+  EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
+} BootMainEntries[] = {\r
+    { L"EBL", BootEBL },\r
+    { L"Boot Manager", BootMenuManager },\r
+};\r
+\r
+\r
+EFI_STATUS\r
+BootMenuMain (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY BootOptionsList;\r
+  UINTN       OptionCount;\r
+  UINTN       BootOptionCount;\r
+  EFI_STATUS  Status;\r
+  LIST_ENTRY  *Entry;\r
+  BDS_LOAD_OPTION *BootOption;\r
+  UINTN   BootOptionSelected;\r
+  UINTN   Index;\r
+  UINTN   BootMainEntryCount;\r
+\r
+  BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
+
+  // Get Boot#### list\r
+  BootOptionList (&BootOptionsList);\r
+\r
+  while (TRUE) {\r
+    OptionCount = 1;\r
+\r
+    // Display the Boot options\r
+    for (Entry = GetFirstNode (&BootOptionsList);\r
+         !IsNull (&BootOptionsList,Entry);\r
+         Entry = GetNextNode (&BootOptionsList,Entry)\r
+         )\r
+    {\r
+      BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
+\r
+      Print(L"[%d] %s\n",OptionCount,BootOption->Description);\r
+\r
+      DEBUG_CODE_BEGIN();\r
+        CHAR16*                           DevicePathTxt;\r
+        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+\r
+        Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+        ASSERT_EFI_ERROR(Status);\r
+        DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);\r
+\r
+        Print(L"\t- %s\n",DevicePathTxt);\r
+        if (BootOption->OptionalData != NULL) {\r
+          Print(L"\t- LoaderType: %d\n",BootOption->OptionalData->LoaderType);\r
+          if (BootOption->OptionalData->Arguments != NULL) {\r
+            Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);\r
+          }\r
+        }\r
+\r
+        FreePool(DevicePathTxt);\r
+      DEBUG_CODE_END();\r
+\r
+      OptionCount++;\r
+    }\r
+    BootOptionCount = OptionCount-1;\r
+\r
+    // Display the hardcoded Boot entries\r
+    for (Index = 0; Index < BootMainEntryCount; Index++) {\r
+      Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
+      OptionCount++;\r
+    }\r
+\r
+    // Request the boot entry from the user\r
+    BootOptionSelected = 0;\r
+    while (BootOptionSelected == 0) {\r
+      Print(L"Start: ");\r
+      Status = GetHIInputInteger (&BootOptionSelected);\r
+      if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
+        Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
+        BootOptionSelected = 0;\r
+      }\r
+    }\r
+\r
+    // Start the selected entry\r
+    if (BootOptionSelected > BootOptionCount) {\r
+      // Start the hardcoded entry\r
+      Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
+    } else {\r
+      // Find the selected entry from the Boot#### list\r
+      Index = 1;\r
+      for (Entry = GetFirstNode (&BootOptionsList);\r
+           !IsNull (&BootOptionsList,Entry);\r
+           Entry = GetNextNode (&BootOptionsList,Entry)\r
+           )\r
+      {\r
+        if (Index == BootOptionSelected) {\r
+          BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
+          break;\r
+        }\r
+        Index++;\r
+      }\r
+\r
+      Status = BootOptionStart (BootOption);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/ArmPlatformPkg/Bds/BootOption.c b/ArmPlatformPkg/Bds/BootOption.c
new file mode 100644 (file)
index 0000000..a8ba23f
--- /dev/null
@@ -0,0 +1,407 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "BdsInternal.h"\r
+\r
+extern EFI_HANDLE mImageHandle;\r
+\r
+EFI_STATUS\r
+BootOptionStart (\r
+  IN BDS_LOAD_OPTION *BootOption\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  EFI_DEVICE_PATH* FdtDevicePath;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  if (BootOption->OptionalData->LoaderType == BDS_LOADER_EFI_APPLICATION) {\r
+    // Need to connect every drivers to ensure no dependencies are missing for the application\r
+    BdsConnectAllDrivers();\r
+\r
+    Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList);\r
+  } else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {\r
+    Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, NULL);\r
+  } else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {\r
+    // Convert the FDT path into a Device Path\r
+    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
+    ASSERT_EFI_ERROR(Status);\r
+    FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));\r
+\r
+    Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, FdtDevicePath);\r
+    FreePool(FdtDevicePath);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BootOptionParseLoadOption (\r
+  IN  EFI_LOAD_OPTION EfiLoadOption,\r
+  IN  UINTN           EfiLoadOptionSize,\r
+  OUT BDS_LOAD_OPTION **BdsLoadOption\r
+  )\r
+{\r
+  BDS_LOAD_OPTION *LoadOption;\r
+  UINTN           FilePathListLength;\r
+  UINTN           DescriptionLength;\r
+\r
+  if (EfiLoadOption == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  LoadOption = (BDS_LOAD_OPTION*)AllocatePool(sizeof(BDS_LOAD_OPTION));\r
+  if (LoadOption == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  LoadOption->LoadOption = EfiLoadOption;\r
+  LoadOption->LoadOptionSize = EfiLoadOptionSize;\r
+\r
+  LoadOption->Attributes    = *(UINT32*)EfiLoadOption;\r
+  FilePathListLength        = *(UINT16*)(EfiLoadOption + sizeof(UINT32));\r
+  LoadOption->Description   = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));\r
+  DescriptionLength         = StrSize (LoadOption->Description);\r
+  LoadOption->FilePathList  = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);\r
+\r
+  if ((UINTN)((UINT8*)LoadOption->FilePathList + FilePathListLength - EfiLoadOption) == EfiLoadOptionSize) {\r
+    LoadOption->OptionalData = NULL;\r
+  } else {\r
+    LoadOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)((UINT8*)LoadOption->FilePathList + FilePathListLength);\r
+  }\r
+\r
+  *BdsLoadOption = LoadOption;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootOptionFromLoadOptionVariable (\r
+  IN  UINT16            LoadOptionIndex,\r
+  OUT BDS_LOAD_OPTION **BdsLoadOption\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR16      BootVariableName[9];\r
+  EFI_LOAD_OPTION     EfiLoadOption;\r
+  UINTN               EfiLoadOptionSize;\r
+\r
+  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);\r
+\r
+  Status = GetEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);\r
+  if (!EFI_ERROR(Status)) {\r
+    Status = BootOptionParseLoadOption (EfiLoadOption,EfiLoadOptionSize,BdsLoadOption);\r
+    if (!EFI_ERROR(Status)) {\r
+      (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BootOptionList (\r
+  IN OUT LIST_ENTRY *BootOptionList\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  UINTN             Index;\r
+  UINT16            *BootOrder;\r
+  UINTN             BootOrderSize;\r
+  BDS_LOAD_OPTION   *BdsLoadOption;\r
+\r
+  InitializeListHead (BootOptionList);\r
+\r
+  // Get the Boot Option Order from the environment variable\r
+  Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
+    Status = BootOptionFromLoadOptionVariable (BootOrder[Index],&BdsLoadOption);\r
+    if (!EFI_ERROR(Status)) {\r
+      InsertTailList (BootOptionList,&BdsLoadOption->Link);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINT16\r
+BootOptionAllocateBootIndex (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  UINTN             Index;\r
+  UINT32            BootIndex;\r
+  UINT16            *BootOrder;\r
+  UINTN             BootOrderSize;\r
+  BOOLEAN           Found;\r
+\r
+  // Get the Boot Option Order from the environment variable\r
+  Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+  if (!EFI_ERROR(Status)) {\r
+    for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {\r
+      Found = FALSE;\r
+      for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
+        if (BootOrder[Index] == BootIndex) {\r
+          Found = TRUE;\r
+          break;\r
+        }\r
+      }\r
+      if (!Found) {\r
+        return BootIndex;\r
+      }\r
+    }\r
+  }\r
+  // Return the first index\r
+  return 0;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+BootOptionSetFields (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  IN UINT32 Attributes,\r
+  IN CHAR16* BootDescription,\r
+  IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  IN  BDS_LOADER_TYPE   BootType,\r
+  IN  CHAR8*            BootArguments\r
+  )\r
+{\r
+  EFI_LOAD_OPTION EfiLoadOption;\r
+  UINTN           EfiLoadOptionSize;\r
+  UINTN           BootDescriptionSize;\r
+  UINTN           BootOptionalDataSize;\r
+  UINT16          FilePathListLength;\r
+  EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;\r
+  UINTN           NodeLength;\r
+  UINT8*          EfiLoadOptionPtr;\r
+\r
+  // If we are overwriting an existent Boot Option then we have to free previously allocated memory\r
+  if (BootOption->LoadOption) {\r
+    FreePool(BootOption->LoadOption);\r
+  }\r
+\r
+  BootDescriptionSize = StrSize(BootDescription);\r
+  BootOptionalDataSize = sizeof(BDS_LOADER_OPTIONAL_DATA) +\r
+      (BootArguments == NULL ? 0 : AsciiStrSize(BootArguments));\r
+\r
+  // Compute the size of the FilePath list\r
+  FilePathListLength = 0;\r
+  DevicePathNode = DevicePath;\r
+  while (!IsDevicePathEndType (DevicePathNode)) {\r
+    FilePathListLength += DevicePathNodeLength (DevicePathNode);\r
+    DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+  }\r
+  // Add the length of the DevicePath EndType\r
+  FilePathListLength += DevicePathNodeLength (DevicePathNode);\r
+\r
+  // Allocate the memory for the EFI Load Option\r
+  EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + BootOptionalDataSize;\r
+  EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);\r
+  EfiLoadOptionPtr = EfiLoadOption;\r
+\r
+  //\r
+  // Populate the EFI Load Option and BDS Boot Option structures\r
+  //\r
+\r
+  // Attributes fields\r
+  BootOption->Attributes = Attributes;\r
+  *(UINT32*)EfiLoadOptionPtr = Attributes;\r
+  EfiLoadOptionPtr += sizeof(UINT32);\r
+\r
+  // FilePath List fields\r
+  BootOption->FilePathListLength = FilePathListLength;\r
+  *(UINT16*)EfiLoadOptionPtr = FilePathListLength;\r
+  EfiLoadOptionPtr += sizeof(UINT16);\r
+\r
+  // Boot description fields\r
+  BootOption->Description = (CHAR16*)EfiLoadOptionPtr;\r
+  CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);\r
+  EfiLoadOptionPtr += BootDescriptionSize;\r
+\r
+  // File path fields\r
+  BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;\r
+  DevicePathNode = DevicePath;\r
+  while (!IsDevicePathEndType (DevicePathNode)) {\r
+    NodeLength = DevicePathNodeLength(DevicePathNode);\r
+    CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);\r
+    EfiLoadOptionPtr += NodeLength;\r
+    DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+  }\r
+\r
+  // Set the End Device Path Type\r
+  SetDevicePathEndNode (EfiLoadOptionPtr);\r
+  EfiLoadOptionPtr = (UINT8 *)EfiLoadOptionPtr + sizeof(EFI_DEVICE_PATH);\r
+\r
+  // Optional Data fields, Do unaligned writes\r
+  WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, BootType);\r
+\r
+  CopyMem (&((BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments, BootArguments, AsciiStrSize(BootArguments));\r
+  BootOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)EfiLoadOptionPtr;\r
+\r
+  // Fill the EFI Load option fields\r
+  BootOption->LoadOptionIndex = BootOptionAllocateBootIndex();\r
+  BootOption->LoadOption = EfiLoadOption;\r
+  BootOption->LoadOptionSize = EfiLoadOptionSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootOptionCreate (\r
+  IN  UINT32 Attributes,\r
+  IN  CHAR16* BootDescription,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  IN  BDS_LOADER_TYPE   BootType,\r
+  IN  CHAR8*            BootArguments,\r
+  OUT BDS_LOAD_OPTION **BdsLoadOption\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  BDS_LOAD_OPTION *BootOption;\r
+  CHAR16          BootVariableName[9];\r
+  UINT16            *BootOrder;\r
+  UINTN             BootOrderSize;\r
+\r
+  //\r
+  // Allocate and fill the memory for the BDS Load Option structure\r
+  //\r
+  BootOption = (BDS_LOAD_OPTION*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION));\r
+\r
+  InitializeListHead (&BootOption->Link);\r
+  BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);\r
+\r
+  //\r
+  // Set the related environment variables\r
+  //\r
+\r
+  // Create Boot#### environment variable\r
+  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);\r
+  Status = gRT->SetVariable (\r
+      BootVariableName,\r
+      &gEfiGlobalVariableGuid,\r
+      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+      BootOption->LoadOptionSize,\r
+      BootOption->LoadOption\r
+      );\r
+\r
+  // Add the new Boot Index to the list\r
+  Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+  if (!EFI_ERROR(Status)) {\r
+    BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);\r
+    // Add the new index at the end\r
+    BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;\r
+    BootOrderSize += sizeof(UINT16);\r
+  } else {\r
+    // BootOrder does not exist. Create it\r
+    BootOrderSize = sizeof(UINT16);\r
+    BootOrder = &(BootOption->LoadOptionIndex);\r
+  }\r
+\r
+  // Update (or Create) the BootOrder environment variable\r
+  Status = gRT->SetVariable (\r
+      L"BootOrder",\r
+      &gEfiGlobalVariableGuid,\r
+      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+      BootOrderSize,\r
+      BootOrder\r
+      );\r
+\r
+  *BdsLoadOption = BootOption;\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BootOptionUpdate (\r
+  IN  BDS_LOAD_OPTION *BdsLoadOption,\r
+  IN  UINT32 Attributes,\r
+  IN  CHAR16* BootDescription,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  IN  BDS_LOADER_TYPE   BootType,\r
+  IN  CHAR8*            BootArguments\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  BDS_LOAD_OPTION *BootOption;\r
+  CHAR16          BootVariableName[9];\r
+\r
+  // Update the BDS Load Option structure\r
+  BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);\r
+\r
+  // Update the related environment variables\r
+  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);\r
+  Status = gRT->SetVariable (\r
+      BootVariableName,\r
+      &gEfiGlobalVariableGuid,\r
+      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+      BootOption->LoadOptionSize,\r
+      BootOption->LoadOption\r
+      );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BootOptionDelete (\r
+  IN  BDS_LOAD_OPTION *BootOption\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN BootOrderSize;\r
+  UINT16* BootOrder;\r
+  UINTN BootOrderCount;\r
+  EFI_STATUS  Status;\r
+\r
+  // If the Boot Optiono was attached to a list remove it\r
+  if (!IsListEmpty (&BootOption->Link)) {\r
+    // Remove the entry from the list\r
+    RemoveEntryList (&BootOption->Link);\r
+  }\r
+\r
+  // Remove the entry from the BootOrder environment variable\r
+  Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+  if (!EFI_ERROR(Status)) {\r
+    BootOrderCount = BootOrderSize / sizeof(UINT16);\r
+\r
+    // Find the index of the removed entry\r
+    for (Index = 0; Index < BootOrderCount; Index++) {\r
+      if (BootOrder[Index] == BootOption->LoadOptionIndex) {\r
+        // If it the last entry we do not need to rearrange the BootOrder list\r
+        if (Index + 1 != BootOrderCount) {\r
+          CopyMem (&BootOrder[Index],&BootOrder[Index+1], BootOrderCount - (Index + 1));\r
+        }\r
+        break;\r
+      }\r
+    }\r
+\r
+    // Update the BootOrder environment variable\r
+    Status = gRT->SetVariable (\r
+        L"BootOrder",\r
+        &gEfiGlobalVariableGuid,\r
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+        BootOrderSize - sizeof(UINT16),\r
+        BootOrder\r
+        );\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/ArmPlatformPkg/Bds/BootOptionSupport.c b/ArmPlatformPkg/Bds/BootOptionSupport.c
new file mode 100644 (file)
index 0000000..7de2df4
--- /dev/null
@@ -0,0 +1,867 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+*\r
+*  This program and the accompanying materials\r
+*  are licensed and made available under the terms and conditions of the BSD License\r
+*  which accompanies this distribution.  The full text of the license may be found at\r
+*  http://opensource.org/licenses/bsd-license.php\r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+*\r
+**/\r
+\r
+#include "BdsInternal.h"\r
+\r
+#include <Library/NetLib.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DevicePathToText.h>\r
+#include <Protocol/PxeBaseCode.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/SimpleNetwork.h>\r
+\r
+#include <Guid/FileSystemInfo.h>\r
+\r
+#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))\r
+\r
+EFI_STATUS\r
+BdsLoadOptionFileSystemList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionFileSystemCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionFileSystemUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  );\r
+\r
+BOOLEAN\r
+BdsLoadOptionFileSystemIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionMemMapList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionMemMapCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionMemMapUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  );\r
+\r
+BOOLEAN\r
+BdsLoadOptionMemMapIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionPxeList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionPxeCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionPxeUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  );\r
+\r
+BOOLEAN\r
+BdsLoadOptionPxeIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionTftpList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionTftpCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+BdsLoadOptionTftpUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  );\r
+\r
+BOOLEAN\r
+BdsLoadOptionTftpIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  );\r
+\r
+BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {\r
+    {\r
+        BDS_DEVICE_FILESYSTEM,\r
+        BdsLoadOptionFileSystemList,\r
+        BdsLoadOptionFileSystemIsSupported,\r
+        BdsLoadOptionFileSystemCreateDevicePath,\r
+        BdsLoadOptionFileSystemUpdateDevicePath\r
+    },\r
+    {\r
+        BDS_DEVICE_MEMMAP,\r
+        BdsLoadOptionMemMapList,\r
+        BdsLoadOptionMemMapIsSupported,\r
+        BdsLoadOptionMemMapCreateDevicePath,\r
+        BdsLoadOptionMemMapUpdateDevicePath\r
+    },\r
+    {\r
+        BDS_DEVICE_PXE,\r
+        BdsLoadOptionPxeList,\r
+        BdsLoadOptionPxeIsSupported,\r
+        BdsLoadOptionPxeCreateDevicePath,\r
+        BdsLoadOptionPxeUpdateDevicePath\r
+    },\r
+    {\r
+        BDS_DEVICE_TFTP,\r
+        BdsLoadOptionTftpList,\r
+        BdsLoadOptionTftpIsSupported,\r
+        BdsLoadOptionTftpCreateDevicePath,\r
+        BdsLoadOptionTftpUpdateDevicePath\r
+    }\r
+};\r
+\r
+EFI_STATUS\r
+BootDeviceListSupportedInit (\r
+  IN OUT LIST_ENTRY *SupportedDeviceList\r
+  )\r
+{\r
+  UINTN   Index;\r
+\r
+  // Initialize list of supported devices\r
+  InitializeListHead (SupportedDeviceList);\r
+\r
+  for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {\r
+    BdsLoadOptionSupportList[Index].ListDevices(SupportedDeviceList);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootDeviceListSupportedFree (\r
+  IN LIST_ENTRY *SupportedDeviceList\r
+  )\r
+{\r
+  LIST_ENTRY  *Entry;\r
+  BDS_SUPPORTED_DEVICE* SupportedDevice;\r
+\r
+  Entry = GetFirstNode (SupportedDeviceList);\r
+  while (Entry != SupportedDeviceList) {\r
+    SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
+    Entry = RemoveEntryList (Entry);\r
+    FreePool(SupportedDevice);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BootDeviceGetDeviceSupport (\r
+  IN  BDS_LOAD_OPTION *BootOption,\r
+  OUT BDS_LOAD_OPTION_SUPPORT**  DeviceSupport\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  // Find which supported device is the most appropriate\r
+  for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {\r
+    if (BdsLoadOptionSupportList[Index].IsSupported(BootOption)) {\r
+      *DeviceSupport = &BdsLoadOptionSupportList[Index];\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+BootDeviceGetType (\r
+  IN  CHAR16* FileName,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  BOOLEAN IsEfiApp;\r
+  BOOLEAN IsBootLoader;\r
+  BOOLEAN     HasFDTSupport;\r
+\r
+  if (FileName == NULL) {\r
+    Print(L"Is an EFI Application? ");\r
+    Status = GetHIInputBoolean (&IsEfiApp);\r
+    if (EFI_ERROR(Status)) {\r
+      return EFI_ABORTED;\r
+    }\r
+  } else if (HasFilePathEfiExtension(FileName)) {\r
+    IsEfiApp = TRUE;\r
+  } else {\r
+    IsEfiApp = FALSE;\r
+  }\r
+\r
+  if (IsEfiApp) {\r
+    Print(L"Is your application is an OS loader? ");\r
+    Status = GetHIInputBoolean (&IsBootLoader);\r
+    if (EFI_ERROR(Status)) {\r
+      return EFI_ABORTED;\r
+    }\r
+    if (!IsBootLoader) {\r
+      *Attributes |= LOAD_OPTION_CATEGORY_APP;\r
+    }\r
+    *BootType = BDS_LOADER_EFI_APPLICATION;\r
+  } else {\r
+    Print(L"Has FDT support? ");\r
+    Status = GetHIInputBoolean (&HasFDTSupport);\r
+    if (EFI_ERROR(Status)) {\r
+      return EFI_ABORTED;\r
+    }\r
+    if (HasFDTSupport) {\r
+      *BootType = BDS_LOADER_KERNEL_LINUX_FDT;\r
+    } else {\r
+      *BootType = BDS_LOADER_KERNEL_LINUX_ATAG;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionFileSystemList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+  BDS_SUPPORTED_DEVICE              *SupportedDevice;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL*  FileProtocol;\r
+  EFI_FILE_HANDLE                   Fs;\r
+  UINTN                             Size;\r
+  EFI_FILE_SYSTEM_INFO*             FsInfo;\r
+  EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;\r
+\r
+  // List all the Simple File System Protocols\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
+    if (!EFI_ERROR(Status)) {\r
+      // Allocate BDS Supported Device structure\r
+      SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
+\r
+      FileProtocol = NULL;\r
+      Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileProtocol);\r
+      ASSERT_EFI_ERROR(Status);\r
+\r
+      FileProtocol->OpenVolume (FileProtocol, &Fs);\r
+\r
+      // Generate a Description from the file system\r
+      Size = 0;\r
+      FsInfo = NULL;\r
+      Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);\r
+      if (Status == EFI_BUFFER_TOO_SMALL) {\r
+        FsInfo = AllocatePool (Size);\r
+        Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);\r
+      }\r
+      UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"%s (%d MB)",FsInfo->VolumeLabel,(UINT32)(FsInfo->VolumeSize / (1024 * 1024)));\r
+      FreePool(FsInfo);\r
+      Fs->Close (Fs);\r
+\r
+      SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
+      SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_FILESYSTEM];\r
+\r
+      InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionFileSystemCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
+  CHAR8       AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
+  CHAR16      *BootFilePath;\r
+  UINTN       BootFilePathSize;\r
+\r
+  Print(L"File path of the EFI Application or the kernel: ");\r
+  Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  // Convert Ascii into Unicode\r
+  BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));\r
+  AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);\r
+  BootFilePathSize = StrSize(BootFilePath);\r
+\r
+  // Create the FilePath Device Path node\r
+  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
+  FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
+  FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
+  SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
+  CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
+  FreePool (BootFilePath);\r
+\r
+  Status = BootDeviceGetType (FilePathDevicePath->PathName, BootType, Attributes);\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool (FilePathDevicePath);\r
+  } else {\r
+    *DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionFileSystemUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR8       AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
+  CHAR16      *BootFilePath;\r
+  UINTN       BootFilePathSize;\r
+  FILEPATH_DEVICE_PATH* EndingDevicePath;\r
+  FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
+  EFI_DEVICE_PATH*  DevicePath;\r
+\r
+  DevicePath = DuplicateDevicePath (BootOption->FilePathList);\r
+  EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);\r
+\r
+  Print(L"File path of the EFI Application or the kernel: ");\r
+  UnicodeStrToAsciiStr (EndingDevicePath->PathName,AsciiBootFilePath);\r
+  Status = EditHIInputAscii(AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Convert Ascii into Unicode\r
+  BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));\r
+  AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);\r
+  BootFilePathSize = StrSize(BootFilePath);\r
+\r
+  // Create the FilePath Device Path node\r
+  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
+  FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
+  FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
+  SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
+  CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
+  FreePool (BootFilePath);\r
+\r
+  // Generate the new Device Path by replacing the last node by the updated node\r
+  SetDevicePathEndNode (EndingDevicePath);\r
+  *NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath);\r
+  FreePool(DevicePath);\r
+\r
+  return BootDeviceGetType (FilePathDevicePath->PathName, BootType, Attributes);\r
+}\r
+\r
+BOOLEAN\r
+BdsLoadOptionFileSystemIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  )\r
+{\r
+  EFI_DEVICE_PATH*  DevicePathNode;\r
+\r
+  DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);\r
+\r
+  return IS_DEVICE_PATH_NODE(DevicePathNode,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP);\r
+}\r
+\r
+STATIC\r
+BOOLEAN\r
+IsParentDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath\r
+  )\r
+{\r
+  UINTN ParentSize;\r
+  UINTN ChildSize;\r
+\r
+  ParentSize = GetDevicePathSize (ParentDevicePath);\r
+  ChildSize = GetDevicePathSize (ChildDevicePath);\r
+\r
+  if (ParentSize > ChildSize) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionMemMapList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             DevicePathHandleCount;\r
+  EFI_HANDLE                        *DevicePathHandleBuffer;\r
+  BOOLEAN                           IsParent;\r
+  UINTN                             Index;\r
+  UINTN                             Index2;\r
+  BDS_SUPPORTED_DEVICE              *SupportedDevice;\r
+  EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;\r
+  EFI_DEVICE_PATH*                  DevicePath;\r
+\r
+  // List all the BlockIo Protocols\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)\r
+    Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
+    if (!EFI_ERROR(Status)) {\r
+      // BlockIo is not part of Media Device Path\r
+      DevicePath = DevicePathProtocol;\r
+      while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {\r
+        DevicePath = NextDevicePathNode (DevicePath);\r
+      }\r
+      if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {\r
+        continue;\r
+      }\r
+\r
+      // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child\r
+      Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);\r
+      ASSERT_EFI_ERROR (Status);\r
+      IsParent = FALSE;\r
+      for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {\r
+        if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {\r
+          gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);\r
+          if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {\r
+            IsParent = TRUE;\r
+          }\r
+        }\r
+      }\r
+      if (IsParent) {\r
+        continue;\r
+      }\r
+\r
+      // Allocate BDS Supported Device structure\r
+      SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
+\r
+      Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
+      SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];\r
+\r
+      InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionMemMapCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  MEMMAP_DEVICE_PATH* MemMapDevicePath;\r
+  CHAR8       AsciiStartingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
+  CHAR8       AsciiEndingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
+\r
+  Print(L"Starting Address of the binary: ");\r
+  Status = GetHIInputAscii (AsciiStartingAddress,BOOT_DEVICE_ADDRESS_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  Print(L"Ending Address of the binary: ");\r
+  Status = GetHIInputAscii (AsciiEndingAddress,BOOT_DEVICE_ADDRESS_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  // Create the MemMap Device Path Node\r
+  MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool(sizeof(MEMMAP_DEVICE_PATH));\r
+  MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;\r
+  MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;\r
+  MemMapDevicePath->MemoryType = EfiBootServicesData;\r
+  MemMapDevicePath->StartingAddress = AsciiStrHexToUint64 (AsciiStartingAddress);\r
+  MemMapDevicePath->EndingAddress = AsciiStrHexToUint64 (AsciiEndingAddress);\r
+\r
+  Status = BootDeviceGetType (NULL, BootType, Attributes);\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool (MemMapDevicePath);\r
+  } else {\r
+    *DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionMemMapUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  )\r
+{\r
+  ASSERT(0);\r
+  //TODO: Implement me\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+BdsLoadOptionMemMapIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  )\r
+{\r
+  EFI_DEVICE_PATH*  DevicePathNode;\r
+\r
+  DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);\r
+\r
+  return IS_DEVICE_PATH_NODE(DevicePathNode,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionPxeList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+  BDS_SUPPORTED_DEVICE              *SupportedDevice;\r
+  EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL*      SimpleNet;\r
+  CHAR16                            DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
+  EFI_MAC_ADDRESS                   *Mac;\r
+\r
+  // List all the PXE Protocols\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    // We only select the handle WITH a Device Path AND the PXE Protocol\r
+    Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
+    if (!EFI_ERROR(Status)) {\r
+      // Allocate BDS Supported Device structure\r
+      SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
+\r
+      Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);\r
+      if (!EFI_ERROR(Status)) {\r
+        Mac = &SimpleNet->Mode->CurrentAddress;\r
+        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]);\r
+      } else {\r
+        Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+      UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);\r
+\r
+      SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
+      SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];\r
+\r
+      InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionPxeCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  )\r
+{\r
+  *DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);\r
+  SetDevicePathEndNode (*DevicePathNode);\r
+  *BootType = BDS_LOADER_EFI_APPLICATION;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionPxeUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  )\r
+{\r
+  ASSERT (0);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+BdsLoadOptionPxeIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE Handle;\r
+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;\r
+  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBcProtocol;\r
+\r
+  Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &Handle, &RemainingDevicePath);\r
+  if (EFI_ERROR(Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (!IsDevicePathEnd(RemainingDevicePath)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionTftpList (\r
+  IN OUT LIST_ENTRY* BdsLoadOptionList\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINTN                             HandleCount;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+  BDS_SUPPORTED_DEVICE              *SupportedDevice;\r
+  EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL*      SimpleNet;\r
+  CHAR16                            DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
+  EFI_MAC_ADDRESS                   *Mac;\r
+\r
+  // List all the PXE Protocols\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    // 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)\r
+    Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
+    if (!EFI_ERROR(Status)) {\r
+      // Allocate BDS Supported Device structure\r
+      SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
+\r
+      Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);\r
+      if (!EFI_ERROR(Status)) {\r
+        Mac = &SimpleNet->Mode->CurrentAddress;\r
+        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]);\r
+      } else {\r
+        Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+      UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFP on %s",DeviceDescription);\r
+\r
+      SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
+      SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];\r
+\r
+      InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionTftpCreateDevicePath (\r
+  IN  BDS_SUPPORTED_DEVICE* BdsLoadOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,\r
+  OUT BDS_LOADER_TYPE   *BootType,\r
+  OUT UINT32      *Attributes\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  BOOLEAN       IsDHCP;\r
+  EFI_IP_ADDRESS  LocalIp;\r
+  EFI_IP_ADDRESS  RemoteIp;\r
+  IPv4_DEVICE_PATH*   IPv4DevicePathNode;\r
+  FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
+  CHAR8       AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
+  CHAR16*     BootFilePath;\r
+  UINTN       BootFilePathSize;\r
+\r
+  Print(L"Get the IP address from DHCP: ");\r
+  Status = GetHIInputBoolean (&IsDHCP);\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  if (!IsDHCP) {\r
+    Print(L"Get the static IP address: ");\r
+    Status = GetHIInputIP (&LocalIp);\r
+    if (EFI_ERROR(Status)) {\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+\r
+  Print(L"Get the TFTP server IP address: ");\r
+  Status = GetHIInputIP (&RemoteIp);\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  Print(L"File path of the EFI Application or the kernel: ");\r
+  Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);\r
+  if (EFI_ERROR(Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  // Convert Ascii into Unicode\r
+  BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));\r
+  AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);\r
+  BootFilePathSize = StrSize(BootFilePath);\r
+\r
+  // Allocate the memory for the IPv4 + File Path Device Path Nodes\r
+  IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
+\r
+  // Create the IPv4 Device Path\r
+  IPv4DevicePathNode->Header.Type    = MESSAGING_DEVICE_PATH;\r
+  IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;\r
+  SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));\r
+  CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
+  CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
+  IPv4DevicePathNode->LocalPort  = 0;\r
+  IPv4DevicePathNode->RemotePort = 0;\r
+  IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;\r
+  IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);\r
+\r
+  // Create the FilePath Device Path node\r
+  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
+  FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
+  FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
+  SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
+  CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
+  FreePool (BootFilePath);\r
+\r
+  Status = BootDeviceGetType (NULL, BootType, Attributes);\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool (IPv4DevicePathNode);\r
+  } else {\r
+    *DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLoadOptionTftpUpdateDevicePath (\r
+  IN BDS_LOAD_OPTION *BootOption,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,\r
+  OUT BDS_LOADER_TYPE *BootType,\r
+  OUT UINT32 *Attributes\r
+  )\r
+{\r
+  ASSERT (0);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+BdsLoadOptionTftpIsSupported (\r
+  IN BDS_LOAD_OPTION* BdsLoadOption\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE Handle;\r
+  EFI_DEVICE_PATH  *RemainingDevicePath;\r
+  EFI_DEVICE_PATH  *NextDevicePath;\r
+  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBcProtocol;\r
+\r
+  Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &Handle, &RemainingDevicePath);\r
+  if (EFI_ERROR(Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  // Validate the Remaining Device Path\r
+  if (IsDevicePathEnd(RemainingDevicePath)) {\r
+    return FALSE;\r
+  }\r
+  if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&\r
+      !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {\r
+    return FALSE;\r
+  }\r
+  NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
+  if (IsDevicePathEnd(NextDevicePath)) {\r
+    return FALSE;\r
+  }\r
+  if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r