]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/BdsLib/BdsLinuxLoader.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsLinuxLoader.c
index 901781f2f852bc158e6ef64e9c40edefed00b85e..e3249e130775d7f0fe4282651e2a14b5b3d514e5 100644 (file)
-/** @file
-*
-*  Copyright (c) 2011-2012, 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 "BdsLinuxLoader.h"
-
-#define ALIGN32_BELOW(addr)   ALIGN_POINTER(addr - 32,32)
-
-STATIC
-EFI_STATUS
-PreparePlatformHardware (
-  VOID
-  )
-{
-  //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.
-
-  // Clean, invalidate, disable data cache
-  ArmDisableDataCache();
-  ArmCleanInvalidateDataCache();
-
-  // Invalidate and disable the Instruction cache
-  ArmDisableInstructionCache ();
-  ArmInvalidateInstructionCache ();
-
-  // Turn off MMU
-  ArmDisableMmu();
-
-  return EFI_SUCCESS;
-}
-
-STATIC
-EFI_STATUS
-StartLinux (
-  IN  EFI_PHYSICAL_ADDRESS  LinuxImage,
-  IN  UINTN                 LinuxImageSize,
-  IN  EFI_PHYSICAL_ADDRESS  KernelParamsAddress,
-  IN  UINTN                 KernelParamsSize,
-  IN  UINT32                MachineType
-  )
-{
-  EFI_STATUS            Status;
-  LINUX_KERNEL          LinuxKernel;
-
-  // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on
-  // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event.
-  Status = ShutdownUefiBootServices ();
-  if(EFI_ERROR(Status)) {
-    DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));
-    goto Exit;
-  }
-
-  // Move the kernel parameters to any address inside the first 1MB.
-  // This is necessary because the ARM Linux kernel requires
-  // the FTD / ATAG List to reside entirely inside the first 1MB of
-  // physical memory.
-  //Note: There is no requirement on the alignment
-  if (MachineType != ARM_FDT_MACHINE_TYPE) {
-    if (((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxAtagMaxOffset))) {
-      KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);
-    }
-  } else {
-    if (((UINTN)KernelParamsAddress > LINUX_FDT_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxFdtMaxOffset))) {
-      KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_FDT_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);
-    }
-  }
-
-  if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) {
-    //Note: There is no requirement on the alignment
-    LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize);
-  } else {
-    LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage;
-  }
-
-  // Check if the Linux Image is a uImage
-  if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) {
-    // Assume the Image Entry Point is just after the uImage header (64-byte size)
-    LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64);
-    LinuxImageSize -= 64;
-  }
-
-  //TODO: Check there is no overlapping between kernel and Atag
-
-  //
-  // Switch off interrupts, caches, mmu, etc
-  //
-  Status = PreparePlatformHardware ();
-  ASSERT_EFI_ERROR(Status);
-
-  // Register and print out performance information
-  PERF_END (NULL, "BDS", NULL, 0);
-  if (PerformanceMeasurementEnabled ()) {
-    PrintPerformance ();
-  }
-
-  //
-  // Start the Linux Kernel
-  //
-
-  // Outside BootServices, so can't use Print();
-  DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n"));
-
-  // Jump to kernel with register set
-  LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress);
-
-  // Kernel should never exit
-  // After Life services are not provided
-  ASSERT(FALSE);
-
-Exit:
-  // Only be here if we fail to start Linux
-  Print (L"ERROR  : Can not start the kernel. Status=0x%X\n", Status);
-
-  // Free Runtimee Memory (kernel and FDT)
-  return Status;
-}
-
-/**
-  Start a Linux kernel from a Device Path
-
-  @param  LinuxKernel           Device Path to the Linux Kernel
-  @param  Parameters            Linux kernel arguments
-  @param  Fdt                   Device Path to the Flat Device Tree
-
-  @retval EFI_SUCCESS           All drivers have been connected
-  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found
-  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.
-
-**/
-EFI_STATUS
-BdsBootLinuxAtag (
-  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
-  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
-  IN  CONST CHAR8*              CommandLineArguments
-  )
-{
-  EFI_STATUS            Status;
-  UINT32                LinuxImageSize;
-  UINT32                InitrdImageSize = 0;
-  UINT32                AtagSize;
-  EFI_PHYSICAL_ADDRESS  AtagBase;
-  EFI_PHYSICAL_ADDRESS  LinuxImage;
-  EFI_PHYSICAL_ADDRESS  InitrdImage;
-
-  PERF_START (NULL, "BDS", NULL, 0);
-
-  // Load the Linux kernel from a device path
-  LinuxImage = LINUX_KERNEL_MAX_OFFSET;
-  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);
-  if (EFI_ERROR(Status)) {
-    Print (L"ERROR: Did not find Linux kernel.\n");
-    return Status;
-  }
-
-  if (InitrdDevicePath) {
-    // Load the initrd near to the Linux kernel
-    InitrdImage = LINUX_KERNEL_MAX_OFFSET;
-    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize);
-    if (Status == EFI_OUT_OF_RESOURCES) {
-      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize);
-    }
-    if (EFI_ERROR(Status)) {
-      Print (L"ERROR: Did not find initrd image.\n");
-      return Status;
-    }
-    
-    // Check if the initrd is a uInitrd
-    if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) {
-      // Skip the 64-byte image header
-      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64);
-      InitrdImageSize -= 64;
-    }
-  }
-
-  //
-  // Setup the Linux Kernel Parameters
-  //
-  // By setting address=0 we leave the memory allocation to the function
-  Status = PrepareAtagList (CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize);
-  if (EFI_ERROR(Status)) {
-    Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status);
-    return Status;
-  }
-
-  return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType));
-}
-
-/**
-  Start a Linux kernel from a Device Path
-
-  @param  LinuxKernel           Device Path to the Linux Kernel
-  @param  Parameters            Linux kernel arguments
-  @param  Fdt                   Device Path to the Flat Device Tree
-
-  @retval EFI_SUCCESS           All drivers have been connected
-  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found
-  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.
-
-**/
-EFI_STATUS
-BdsBootLinuxFdt (
-  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
-  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
-  IN  CONST CHAR8*              CommandLineArguments,
-  IN  EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath
-  )
-{
-  EFI_STATUS            Status;
-  UINT32                LinuxImageSize;
-  UINT32                InitrdImageSize = 0;
-  UINT32                FdtBlobSize;
-  EFI_PHYSICAL_ADDRESS  FdtBlobBase;
-  EFI_PHYSICAL_ADDRESS  LinuxImage;
-  EFI_PHYSICAL_ADDRESS  InitrdImage;
-
-  PERF_START (NULL, "BDS", NULL, 0);
-
-  // Load the Linux kernel from a device path
-  LinuxImage = LINUX_KERNEL_MAX_OFFSET;
-  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);
-  if (EFI_ERROR(Status)) {
-    Print (L"ERROR: Did not find Linux kernel.\n");
-    return Status;
-  }
-
-  if (InitrdDevicePath) {
-    InitrdImage = LINUX_KERNEL_MAX_OFFSET;
-    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize);
-    if (Status == EFI_OUT_OF_RESOURCES) {
-      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize);
-    }
-    if (EFI_ERROR(Status)) {
-      Print (L"ERROR: Did not find initrd image.\n");
-      return Status;
-    }
-
-    // Check if the initrd is a uInitrd
-    if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) {
-      // Skip the 64-byte image header
-      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64);
-      InitrdImageSize -= 64;
-    }
-  }
-
-  // Load the FDT binary from a device path. The FDT will be reloaded later to a more appropriate location for the Linux kernel.
-  FdtBlobBase = 0;
-  Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);
-  if (EFI_ERROR(Status)) {
-    Print (L"ERROR: Did not find Device Tree blob.\n");
-    return Status;
-  }
-
-  // Update the Fdt with the Initrd information. The FDT will increase in size.
-  // By setting address=0 we leave the memory allocation to the function
-  Status = PrepareFdt (CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize);
-  if (EFI_ERROR(Status)) {
-    Print(L"ERROR: Can not load kernel with FDT. Status=%r\n", Status);
-    return Status;
-  }
-
-  return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE);
-}
-
+/** @file\r
+*\r
+*  Copyright (c) 2011-2012, 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
+#include "BdsLinuxLoader.h"\r
+\r
+#define ALIGN32_BELOW(addr)   ALIGN_POINTER(addr - 32,32)\r
+\r
+STATIC\r
+EFI_STATUS\r
+PreparePlatformHardware (\r
+  VOID\r
+  )\r
+{\r
+  //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.\r
+\r
+  // Clean, invalidate, disable data cache\r
+  ArmDisableDataCache();\r
+  ArmCleanInvalidateDataCache();\r
+\r
+  // Invalidate and disable the Instruction cache\r
+  ArmDisableInstructionCache ();\r
+  ArmInvalidateInstructionCache ();\r
+\r
+  // Turn off MMU\r
+  ArmDisableMmu();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+StartLinux (\r
+  IN  EFI_PHYSICAL_ADDRESS  LinuxImage,\r
+  IN  UINTN                 LinuxImageSize,\r
+  IN  EFI_PHYSICAL_ADDRESS  KernelParamsAddress,\r
+  IN  UINTN                 KernelParamsSize,\r
+  IN  UINT32                MachineType\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  LINUX_KERNEL          LinuxKernel;\r
+\r
+  // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on\r
+  // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event.\r
+  Status = ShutdownUefiBootServices ();\r
+  if(EFI_ERROR(Status)) {\r
+    DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status));\r
+    goto Exit;\r
+  }\r
+\r
+  // Move the kernel parameters to any address inside the first 1MB.\r
+  // This is necessary because the ARM Linux kernel requires\r
+  // the FTD / ATAG List to reside entirely inside the first 1MB of\r
+  // physical memory.\r
+  //Note: There is no requirement on the alignment\r
+  if (MachineType != ARM_FDT_MACHINE_TYPE) {\r
+    if (((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxAtagMaxOffset))) {\r
+      KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);\r
+    }\r
+  } else {\r
+    if (((UINTN)KernelParamsAddress > LINUX_FDT_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxFdtMaxOffset))) {\r
+      KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_FDT_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);\r
+    }\r
+  }\r
+\r
+  if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) {\r
+    //Note: There is no requirement on the alignment\r
+    LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize);\r
+  } else {\r
+    LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage;\r
+  }\r
+\r
+  // Check if the Linux Image is a uImage\r
+  if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) {\r
+    // Assume the Image Entry Point is just after the uImage header (64-byte size)\r
+    LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64);\r
+    LinuxImageSize -= 64;\r
+  }\r
+\r
+  //TODO: Check there is no overlapping between kernel and Atag\r
+\r
+  //\r
+  // Switch off interrupts, caches, mmu, etc\r
+  //\r
+  Status = PreparePlatformHardware ();\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  // Register and print out performance information\r
+  PERF_END (NULL, "BDS", NULL, 0);\r
+  if (PerformanceMeasurementEnabled ()) {\r
+    PrintPerformance ();\r
+  }\r
+\r
+  //\r
+  // Start the Linux Kernel\r
+  //\r
+\r
+  // Outside BootServices, so can't use Print();\r
+  DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n"));\r
+\r
+  // Jump to kernel with register set\r
+  LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress);\r
+\r
+  // Kernel should never exit\r
+  // After Life services are not provided\r
+  ASSERT(FALSE);\r
+\r
+Exit:\r
+  // Only be here if we fail to start Linux\r
+  Print (L"ERROR  : Can not start the kernel. Status=0x%X\n", Status);\r
+\r
+  // Free Runtimee Memory (kernel and FDT)\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param  LinuxKernel           Device Path to the Linux Kernel\r
+  @param  Parameters            Linux kernel arguments\r
+  @param  Fdt                   Device Path to the Flat Device Tree\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsBootLinuxAtag (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  CONST CHAR8*              CommandLineArguments\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT32                LinuxImageSize;\r
+  UINT32                InitrdImageSize = 0;\r
+  UINT32                AtagSize;\r
+  EFI_PHYSICAL_ADDRESS  AtagBase;\r
+  EFI_PHYSICAL_ADDRESS  LinuxImage;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImage;\r
+\r
+  PERF_START (NULL, "BDS", NULL, 0);\r
+\r
+  // Load the Linux kernel from a device path\r
+  LinuxImage = LINUX_KERNEL_MAX_OFFSET;\r
+  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);\r
+  if (EFI_ERROR(Status)) {\r
+    Print (L"ERROR: Did not find Linux kernel.\n");\r
+    return Status;\r
+  }\r
+\r
+  if (InitrdDevicePath) {\r
+    // Load the initrd near to the Linux kernel\r
+    InitrdImage = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize);\r
+    if (Status == EFI_OUT_OF_RESOURCES) {\r
+      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize);\r
+    }\r
+    if (EFI_ERROR(Status)) {\r
+      Print (L"ERROR: Did not find initrd image.\n");\r
+      return Status;\r
+    }\r
+    \r
+    // Check if the initrd is a uInitrd\r
+    if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) {\r
+      // Skip the 64-byte image header\r
+      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64);\r
+      InitrdImageSize -= 64;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Setup the Linux Kernel Parameters\r
+  //\r
\r
+  // By setting address=0 we leave the memory allocation to the function\r
+  Status = PrepareAtagList (CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status);\r
+    return Status;\r
+  }\r
+\r
+  return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType));\r
+}\r
+\r
+/**\r
+  Start a Linux kernel from a Device Path\r
+\r
+  @param  LinuxKernel           Device Path to the Linux Kernel\r
+  @param  Parameters            Linux kernel arguments\r
+  @param  Fdt                   Device Path to the Flat Device Tree\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsBootLinuxFdt (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,\r
+  IN  CONST CHAR8*              CommandLineArguments,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT32                LinuxImageSize;\r
+  UINT32                InitrdImageSize = 0;\r
+  UINT32                FdtBlobSize;\r
+  EFI_PHYSICAL_ADDRESS  FdtBlobBase;\r
+  EFI_PHYSICAL_ADDRESS  LinuxImage;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImage;\r
+\r
+  PERF_START (NULL, "BDS", NULL, 0);\r
+\r
+  // Load the Linux kernel from a device path\r
+  LinuxImage = LINUX_KERNEL_MAX_OFFSET;\r
+  Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize);\r
+  if (EFI_ERROR(Status)) {\r
+    Print (L"ERROR: Did not find Linux kernel.\n");\r
+    return Status;\r
+  }\r
+\r
+  if (InitrdDevicePath) {\r
+    InitrdImage = LINUX_KERNEL_MAX_OFFSET;\r
+    Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize);\r
+    if (Status == EFI_OUT_OF_RESOURCES) {\r
+      Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize);\r
+    }\r
+    if (EFI_ERROR(Status)) {\r
+      Print (L"ERROR: Did not find initrd image.\n");\r
+      return Status;\r
+    }\r
+\r
+    // Check if the initrd is a uInitrd\r
+    if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) {\r
+      // Skip the 64-byte image header\r
+      InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64);\r
+      InitrdImageSize -= 64;\r
+    }\r
+  }\r
+\r
+  // Load the FDT binary from a device path. The FDT will be reloaded later to a more appropriate location for the Linux kernel.\r
+  FdtBlobBase = 0;\r
+  Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
+  if (EFI_ERROR(Status)) {\r
+    Print (L"ERROR: Did not find Device Tree blob.\n");\r
+    return Status;\r
+  }\r
+\r
+  // Update the Fdt with the Initrd information. The FDT will increase in size.\r
+  // By setting address=0 we leave the memory allocation to the function\r
+  Status = PrepareFdt (CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"ERROR: Can not load kernel with FDT. Status=%r\n", Status);\r
+    return Status;\r
+  }\r
+\r
+  return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE);\r
+}\r
+\r