]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Bds/Bds.c
ArmPlatformPkg/Bds: Early Console Initialization
[mirror_edk2.git] / ArmPlatformPkg / Bds / Bds.c
index 5ae7bae77584cbe44bcb0adb34dce12d61b0b35a..4cea3cd531bbdc46e95625b4abe281d3dbc6168b 100644 (file)
-/** @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;
-        EFI_STATUS Status;
-       
-        Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
-        if (!EFI_ERROR(Status)) {
-          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;
-  ARM_BDS_LOADER_ARGUMENTS*           BootArguments;
-  ARM_BDS_LOADER_TYPE                 BootType;
-  EFI_DEVICE_PATH*                    InitrdPath;
-  UINTN                               CmdLineSize;
-  UINTN                               InitrdSize;
-
-  //
-  // 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) {
-    if ((PcdGetPtr(PcdDefaultBootDevicePath) == NULL) || (StrLen ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)) == 0)) {
-      return EFI_UNSUPPORTED;
-    }
-
-    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
-    if (EFI_ERROR(Status)) {
-      // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe)
-      DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathFromTextProtocol\n"));
-      return 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) {
-      BootType = (ARM_BDS_LOADER_TYPE)PcdGet32 (PcdDefaultBootType);
-
-      if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
-        CmdLineSize = AsciiStrSize ((CHAR8*)PcdGetPtr(PcdDefaultBootArgument));
-        InitrdPath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootInitrdPath));
-        InitrdSize = GetDevicePathSize (InitrdPath);
-
-        BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);
-        BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
-        BootArguments->LinuxArguments.InitrdSize = InitrdSize;
-
-        CopyMem ((VOID*)(BootArguments + 1), (CHAR8*)PcdGetPtr(PcdDefaultBootArgument), CmdLineSize);
-        CopyMem ((VOID*)((UINTN)(BootArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
-      } else {
-        BootArguments = NULL;
-      }
-
-      BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
-        (CHAR16*)PcdGetPtr(PcdDefaultBootDescription),
-        BootDevicePath,
-        BootType,
-        BootArguments,
-        &BdsLoadOption
-        );
-      FreePool (BdsLoadOption);
-    } else {
-      Status = EFI_UNSUPPORTED;
-    }
-  }
-
-  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;
-  EFI_INPUT_KEY   Key;
-
-  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--;
-        }
-      }
-      // Discard key in the buffer
-      do {
-       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-      } while(!EFI_ERROR(Status));
-      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
-  //
-  if (FixedPcdGetPtr(PcdFirmwareVendor) != NULL) {
-    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;
-}
+/** @file\r
+*\r
+*  Copyright (c) 2011-2015, 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/PcdLib.h>\r
+#include <Library/PerformanceLib.h>\r
+\r
+#include <Protocol/Bds.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#define EFI_SET_TIMER_TO_SECOND   10000000\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetConsoleDevicePathFromVariable (\r
+  IN  CHAR16*             ConsoleVarName,\r
+  IN  CHAR16*             DefaultConsolePaths,\r
+  OUT EFI_DEVICE_PATH**   DevicePaths\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     Size;\r
+  EFI_DEVICE_PATH_PROTOCOL* DevicePathInstances;\r
+  EFI_DEVICE_PATH_PROTOCOL* DevicePathInstance;\r
+  CHAR16*                   DevicePathStr;\r
+  CHAR16*                   NextDevicePathStr;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
+\r
+  Status = GetGlobalEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);\r
+  if (EFI_ERROR(Status)) {\r
+    // In case no default console device path has been defined we assume a driver handles the console (eg: SimpleTextInOutSerial)\r
+    if ((DefaultConsolePaths == NULL) || (DefaultConsolePaths[0] == L'\0')) {\r
+      *DevicePaths = NULL;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
+    ASSERT_EFI_ERROR(Status);\r
+\r
+    DevicePathInstances = NULL;\r
+\r
+    // Extract the Device Path instances from the multi-device path string\r
+    while ((DefaultConsolePaths != NULL) && (DefaultConsolePaths[0] != L'\0')) {\r
+      NextDevicePathStr = StrStr (DefaultConsolePaths, L";");\r
+      if (NextDevicePathStr == NULL) {\r
+        DevicePathStr = DefaultConsolePaths;\r
+        DefaultConsolePaths = NULL;\r
+      } else {\r
+        DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DefaultConsolePaths + 1) * sizeof(CHAR16), DefaultConsolePaths);\r
+        *(DevicePathStr + (NextDevicePathStr - DefaultConsolePaths)) = L'\0';\r
+        DefaultConsolePaths = NextDevicePathStr;\r
+        if (DefaultConsolePaths[0] == L';') {\r
+          DefaultConsolePaths++;\r
+        }\r
+      }\r
+\r
+      DevicePathInstance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);\r
+      ASSERT(DevicePathInstance != NULL);\r
+      DevicePathInstances = AppendDevicePathInstance (DevicePathInstances, DevicePathInstance);\r
+\r
+      if (NextDevicePathStr != NULL) {\r
+        FreePool (DevicePathStr);\r
+      }\r
+      FreePool (DevicePathInstance);\r
+    }\r
+\r
+    // Set the environment variable with this device path multi-instances\r
+    Size = GetDevicePathSize (DevicePathInstances);\r
+    if (Size > 0) {\r
+      gRT->SetVariable (\r
+          ConsoleVarName,\r
+          &gEfiGlobalVariableGuid,\r
+          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+          Size,\r
+          DevicePathInstances\r
+          );\r
+    } else {\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR(Status)) {\r
+    *DevicePaths = DevicePathInstances;\r
+  }\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+InitializeConsolePipe (\r
+  IN EFI_DEVICE_PATH    *ConsoleDevicePaths,\r
+  IN EFI_GUID           *Protocol,\r
+  OUT EFI_HANDLE        *Handle,\r
+  OUT VOID*             *Interface\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     Size;\r
+  UINTN                     NoHandles;\r
+  EFI_HANDLE                *Buffer;\r
+  EFI_DEVICE_PATH_PROTOCOL* DevicePath;\r
+\r
+  // Connect all the Device Path Consoles\r
+  while (ConsoleDevicePaths != NULL) {\r
+    DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size);\r
+\r
+    Status = BdsConnectDevicePath (DevicePath, Handle, NULL);\r
+    DEBUG_CODE_BEGIN();\r
+      if (EFI_ERROR(Status)) {\r
+        // We convert back to the text representation of the device Path\r
+        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+        CHAR16* DevicePathTxt;\r
+        EFI_STATUS Status;\r
+\r
+        Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+        if (!EFI_ERROR(Status)) {\r
+          DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);\r
+\r
+          DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status));\r
+\r
+          FreePool (DevicePathTxt);\r
+        }\r
+      }\r
+    DEBUG_CODE_END();\r
+\r
+    // If the console splitter driver is not supported by the platform then use the first Device Path\r
+    // instance for the console interface.\r
+    if (!EFI_ERROR(Status) && (*Interface == NULL)) {\r
+      Status = gBS->HandleProtocol (*Handle, Protocol, Interface);\r
+    }\r
+  }\r
+\r
+  // No Device Path has been defined for this console interface. We take the first protocol implementation\r
+  if (*Interface == NULL) {\r
+    Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      BdsConnectAllDrivers();\r
+      Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);\r
+    }\r
+\r
+    if (!EFI_ERROR(Status)) {\r
+      *Handle = Buffer[0];\r
+      Status = gBS->HandleProtocol (*Handle, Protocol, Interface);\r
+      ASSERT_EFI_ERROR(Status);\r
+      FreePool (Buffer);\r
+    }\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+InitializeConsole (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH*          ConOutDevicePaths;\r
+  EFI_DEVICE_PATH*          ConInDevicePaths;\r
+  EFI_DEVICE_PATH*          ConErrDevicePaths;\r
+\r
+  // By getting the Console Device Paths from the environment variables before initializing the console pipe, we\r
+  // create the 3 environment variables (ConIn, ConOut, ConErr) that allows to initialize all the console interface\r
+  // of newly installed console drivers\r
+  Status = GetConsoleDevicePathFromVariable (L"ConOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConOutDevicePaths);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths), &ConInDevicePaths);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = GetConsoleDevicePathFromVariable (L"ErrOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConErrDevicePaths);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  // Initialize the Consoles\r
+  Status = InitializeConsolePipe (ConOutDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = InitializeConsolePipe (ConInDevicePaths, &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = InitializeConsolePipe (ConErrDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr);\r
+  if (EFI_ERROR(Status)) {\r
+    // In case of error, we reuse the console output for the error output\r
+    gST->StandardErrorHandle = gST->ConsoleOutHandle;\r
+    gST->StdErr = gST->ConOut;\r
+  }\r
+\r
+  // Free Memory allocated for reading the UEFI Variables\r
+  if (ConOutDevicePaths) {\r
+    FreePool (ConOutDevicePaths);\r
+  }\r
+  if (ConInDevicePaths) {\r
+    FreePool (ConInDevicePaths);\r
+  }\r
+  if (ConErrDevicePaths) {\r
+    FreePool (ConErrDevicePaths);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DefineDefaultBootEntries (\r
+  VOID\r
+  )\r
+{\r
+  BDS_LOAD_OPTION*                    BdsLoadOption;\r
+  UINTN                               Size;\r
+  EFI_STATUS                          Status;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;\r
+  EFI_DEVICE_PATH*                    BootDevicePath;\r
+  UINTN                               CmdLineSize;\r
+  UINTN                               CmdLineAsciiSize;\r
+  CHAR16*                             DefaultBootArgument;\r
+  CHAR8*                              AsciiDefaultBootArgument;\r
+\r
+  //\r
+  // If Boot Order does not exist then create a default entry\r
+  //\r
+  Size = 0;\r
+  Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);\r
+  if (Status == EFI_NOT_FOUND) {\r
+    if ((PcdGetPtr(PcdDefaultBootDevicePath) == NULL) || (StrLen ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)) == 0)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
+    if (EFI_ERROR(Status)) {\r
+      // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe)\r
+      DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathFromTextProtocol\n"));\r
+      return Status;\r
+    }\r
+    BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath));\r
+\r
+    DEBUG_CODE_BEGIN();\r
+      // We convert back to the text representation of the device Path to see if the initial text is correct\r
+      EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+      CHAR16* DevicePathTxt;\r
+\r
+      Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+      ASSERT_EFI_ERROR(Status);\r
+      DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE);\r
+\r
+      if (StrCmp ((CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt) != 0) {\r
+        DEBUG ((EFI_D_ERROR, "Device Path given: '%s' Device Path expected: '%s'\n",\r
+            (CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt));\r
+        ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+      }\r
+\r
+      FreePool (DevicePathTxt);\r
+    DEBUG_CODE_END();\r
+\r
+    // Create the entry is the Default values are correct\r
+    if (BootDevicePath != NULL) {\r
+      // We do not support NULL pointer\r
+      ASSERT (PcdGetPtr (PcdDefaultBootArgument) != NULL);\r
+\r
+      //\r
+      // Logic to handle ASCII or Unicode default parameters\r
+      //\r
+      if (*(CHAR8*)PcdGetPtr (PcdDefaultBootArgument) == '\0') {\r
+        CmdLineSize = 0;\r
+        CmdLineAsciiSize = 0;\r
+        DefaultBootArgument = NULL;\r
+        AsciiDefaultBootArgument = NULL;\r
+      } else if (IsUnicodeString ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument))) {\r
+        // The command line is a Unicode string\r
+        DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);\r
+        CmdLineSize = StrSize (DefaultBootArgument);\r
+\r
+        // Initialize ASCII variables\r
+        CmdLineAsciiSize = CmdLineSize / 2;\r
+        AsciiDefaultBootArgument = AllocatePool (CmdLineAsciiSize);\r
+        if (AsciiDefaultBootArgument == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        UnicodeStrToAsciiStr ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument), AsciiDefaultBootArgument);\r
+      } else {\r
+        // The command line is a ASCII string\r
+        AsciiDefaultBootArgument = (CHAR8*)PcdGetPtr (PcdDefaultBootArgument);\r
+        CmdLineAsciiSize = AsciiStrSize (AsciiDefaultBootArgument);\r
+\r
+        // Initialize ASCII variables\r
+        CmdLineSize = CmdLineAsciiSize * 2;\r
+        DefaultBootArgument = AllocatePool (CmdLineSize);\r
+        if (DefaultBootArgument == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        AsciiStrToUnicodeStr (AsciiDefaultBootArgument, DefaultBootArgument);\r
+      }\r
+\r
+      BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
+        (CHAR16*)PcdGetPtr (PcdDefaultBootDescription),\r
+        BootDevicePath,\r
+        (UINT8 *)DefaultBootArgument, // OptionalData\r
+        CmdLineSize,                  // OptionalDataSize\r
+        &BdsLoadOption\r
+        );\r
+      FreePool (BdsLoadOption);\r
+\r
+      if (DefaultBootArgument == (CHAR16*)PcdGetPtr (PcdDefaultBootArgument)) {\r
+        FreePool (AsciiDefaultBootArgument);\r
+      } else if (DefaultBootArgument != NULL) {\r
+        FreePool (DefaultBootArgument);\r
+      }\r
+    } else {\r
+      Status = EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+StartDefaultBootOnTimeout (\r
+  VOID\r
+  )\r
+{\r
+  UINTN               Size;\r
+  UINT16              Timeout;\r
+  UINT16              *TimeoutPtr;\r
+  EFI_EVENT           WaitList[2];\r
+  UINTN               WaitIndex;\r
+  UINT16              *BootOrder;\r
+  UINTN               BootOrderSize;\r
+  UINTN               Index;\r
+  CHAR16              BootVariableName[9];\r
+  EFI_STATUS          Status;\r
+  EFI_INPUT_KEY       Key;\r
+\r
+  Size = sizeof(UINT16);\r
+  Timeout = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);\r
+  Status = GetGlobalEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);\r
+  if (!EFI_ERROR (Status)) {\r
+    Timeout = *TimeoutPtr;\r
+    FreePool (TimeoutPtr);\r
+  }\r
+\r
+  if (Timeout != 0xFFFF) {\r
+    if (Timeout > 0) {\r
+      // Create the waiting events (keystroke and 1sec timer)\r
+      gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[0]);\r
+      gBS->SetTimer (WaitList[0], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);\r
+      WaitList[1] = gST->ConIn->WaitForKey;\r
+\r
+      // Start the timer\r
+      WaitIndex = 0;\r
+      Print(L"The default boot selection will start in ");\r
+      while ((Timeout > 0) && (WaitIndex == 0)) {\r
+        Print(L"%3d seconds",Timeout);\r
+        gBS->WaitForEvent (2, WaitList, &WaitIndex);\r
+        if (WaitIndex == 0) {\r
+          Print(L"\b\b\b\b\b\b\b\b\b\b\b");\r
+          Timeout--;\r
+        }\r
+      }\r
+      // Discard key in the buffer\r
+      do {\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+      } while(!EFI_ERROR(Status));\r
+      gBS->CloseEvent (WaitList[0]);\r
+      Print(L"\n\r");\r
+    }\r
+\r
+    // In case of Timeout we start the default boot selection\r
+    if (Timeout == 0) {\r
+      // Get the Boot Option Order from the environment variable (a default value should have been created)\r
+      GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+\r
+      for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
+        UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOrder[Index]);\r
+        Status = BdsStartBootOption (BootVariableName);\r
+        if(!EFI_ERROR(Status)){\r
+          // Boot option returned successfully, hence don't need to start next boot option\r
+          break;\r
+        }\r
+        // In case of success, we should not return from this call.\r
+      }\r
+      FreePool (BootOrder);\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  An empty function to pass error checking of CreateEventEx ().\r
+\r
+  @param  Event                 Event whose notification function is being invoked.\r
+  @param  Context               Pointer to the notification function's context,\r
+                                which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EmptyCallbackFunction (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  return;\r
+}\r
+\r
+/**\r
+  This function uses policy data from the platform to determine what operating\r
+  system or system utility should be loaded and invoked.  This function call\r
+  also optionally make the use of user input to determine the operating system\r
+  or system utility to be loaded and invoked.  When the DXE Core has dispatched\r
+  all the drivers on the dispatch queue, this function is called.  This\r
+  function will attempt to connect the boot devices required to load and invoke\r
+  the selected operating system or system utility.  During this process,\r
+  additional firmware volumes may be discovered that may contain addition DXE\r
+  drivers that can be dispatched by the DXE Core.   If a boot device cannot be\r
+  fully connected, this function calls the DXE Service Dispatch() to allow the\r
+  DXE drivers from any newly discovered firmware volumes to be dispatched.\r
+  Then the boot device connection can be attempted again.  If the same boot\r
+  device connection operation fails twice in a row, then that boot device has\r
+  failed, and should be skipped.  This function should never return.\r
+\r
+  @param  This             The EFI_BDS_ARCH_PROTOCOL instance.\r
+\r
+  @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsEntry (\r
+  IN EFI_BDS_ARCH_PROTOCOL  *This\r
+  )\r
+{\r
+  UINTN               Size;\r
+  EFI_STATUS          Status;\r
+  UINT16             *BootNext;\r
+  UINTN               BootNextSize;\r
+  CHAR16              BootVariableName[9];\r
+  EFI_EVENT           EndOfDxeEvent;\r
+\r
+  //\r
+  // Signal EndOfDxe PI Event\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+      EVT_NOTIFY_SIGNAL,\r
+      TPL_NOTIFY,\r
+      EmptyCallbackFunction,\r
+      NULL,\r
+      &gEfiEndOfDxeEventGroupGuid,\r
+      &EndOfDxeEvent\r
+      );\r
+  if (!EFI_ERROR (Status)) {\r
+    gBS->SignalEvent (EndOfDxeEvent);\r
+  }\r
+\r
+  PERF_END   (NULL, "DXE", NULL, 0);\r
+\r
+  //\r
+  // Declare the Firmware Vendor\r
+  //\r
+  if (FixedPcdGetPtr(PcdFirmwareVendor) != NULL) {\r
+    Size = 0x100;\r
+    gST->FirmwareVendor = AllocateRuntimePool (Size);\r
+    ASSERT (gST->FirmwareVendor != NULL);\r
+    UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__);\r
+  }\r
+\r
+  //\r
+  // Fixup Table CRC after we updated Firmware Vendor\r
+  //\r
+  gST->Hdr.CRC32 = 0;\r
+  Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  // Now we need to setup the EFI System Table with information about the console devices.\r
+  InitializeConsole ();\r
+\r
+  // If BootNext environment variable is defined then we just load it !\r
+  BootNextSize = sizeof(UINT16);\r
+  Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext);\r
+  if (!EFI_ERROR(Status)) {\r
+    ASSERT(BootNextSize == sizeof(UINT16));\r
+\r
+    // Generate the requested Boot Entry variable name\r
+    UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", *BootNext);\r
+\r
+    // Set BootCurrent variable\r
+    gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
+              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+              BootNextSize, BootNext);\r
+\r
+    FreePool (BootNext);\r
+\r
+    // Start the requested Boot Entry\r
+    Status = BdsStartBootOption (BootVariableName);\r
+    if (Status != EFI_NOT_FOUND) {\r
+      // BootNext has not been succeeded launched\r
+      if (EFI_ERROR(Status)) {\r
+        Print(L"Fail to start BootNext.\n");\r
+      }\r
+\r
+      // Delete the BootNext environment variable\r
+      gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,\r
+          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+          0, NULL);\r
+    }\r
+\r
+    // Clear BootCurrent variable\r
+    gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
+        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+        0, NULL);\r
+  }\r
+\r
+  // If Boot Order does not exist then create a default entry\r
+  DefineDefaultBootEntries ();\r
+\r
+  //\r
+  // Update the CRC32 in the EFI System Table header\r
+  //\r
+  gST->Hdr.CRC32 = 0;\r
+  Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  // Timer before initiating the default boot selection\r
+  StartDefaultBootOnTimeout ();\r
+\r
+  // Start the Boot Menu\r
+  Status = BootMenuMain ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+}\r
+\r
+EFI_BDS_ARCH_PROTOCOL  gBdsProtocol = {\r
+  BdsEntry,\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BdsInitialize (\r
+  IN EFI_HANDLE                            ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                      *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ImageHandle,\r
+                  &gEfiBdsArchProtocolGuid, &gBdsProtocol,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r