]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPkg/BdsLib: Added FDT support for BdsLib
authoroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 28 Sep 2012 09:58:42 +0000 (09:58 +0000)
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 28 Sep 2012 09:58:42 +0000 (09:58 +0000)
Signed-off-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13768 6f19259b-4bc3-4df7-8a09-765794883524

13 files changed:
ArmPkg/ArmPkg.dec
ArmPkg/Library/BdsLib/BdsAppLoader.c
ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPkg/Library/BdsLib/BdsHelper.c
ArmPkg/Library/BdsLib/BdsInternal.h
ArmPkg/Library/BdsLib/BdsLib.inf
ArmPkg/Library/BdsLib/BdsLinuxAtag.c
ArmPkg/Library/BdsLib/BdsLinuxFdt.c [new file with mode: 0644]
ArmPkg/Library/BdsLib/BdsLinuxLoader.c
ArmPkg/Library/BdsLib/BdsLinuxLoader.h
ArmPlatformPkg/ArmRealViewEbPkg/ArmRealViewEb.dsc.inc
ArmPlatformPkg/ArmVExpressPkg/ArmVExpress.dsc.inc
BeagleBoardPkg/BeagleBoardPkg.dsc

index cd2578f05e6bfaf5af1b059d47a4c1980591c04d..7a4aa79933c31d366fa2071628cf77cea0b48617 100644 (file)
   # BdsLib\r
   #\r
   gArmTokenSpaceGuid.PcdArmMachineType|0|UINT32|0x0000001E\r
+  # The compressed Linux kernel is expected to load at MemStart + 0x8000 (e.g. 0x8000_8000)\r
+  gArmTokenSpaceGuid.PcdArmLinuxKernelFixedOffset|0x00008000|UINT32|0x00000027\r
   # The compressed Linux kernel is expected to be under 128MB from the beginning of the System Memory\r
   gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset|0x08000000|UINT32|0x0000001F\r
   # The Linux ATAGs are expected to be under 0x4000 (16KB) from the beginning of the System Memory\r
   gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset|0x4000|UINT32|0x00000020\r
+  # If the fixed FDT address is not available, then it should be loaded the below the kernel\r
+  # The recommandation from the Linux kernel is to have the FDT below 16KB\r
+  gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset|0x4000|UINT32|0x00000023\r
 \r
   #\r
   # ARM Architectural Timer\r
index 4f359cda10b66708b1ac1c223e85a35a4b2d06f8..2d7f96e28b413cada131f12bb3fbecc92b226b3a 100644 (file)
@@ -1,6 +1,6 @@
 /** @file
 *
-*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  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
index 88596c7c6a30bab1b2c05c137b0d822bded083ea..a8b77a3d22712f26f14943faed2e593c7e813f55 100644 (file)
@@ -1,6 +1,6 @@
 /** @file
 *
-*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  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         
index bd1fa005e83e257943d19e2c31a412508774df1d..29cc12bd33d6c522b8c25dc8111a534cc1ea4ad4 100644 (file)
@@ -1,6 +1,6 @@
 /** @file
 *
-*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  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         
@@ -44,6 +44,7 @@ ShutdownUefiBootServices (
   MemoryMap = NULL;
   MemoryMapSize = 0;
   Pages = 0;
+
   do {
     Status = gBS->GetMemoryMap (
                     &MemoryMapSize,
index 880d7809946e648fe93f3bab19aa4b162d6c8cf3..85f9f41598cfadf11f0933f03dcd00ddb27e3ed6 100644 (file)
@@ -1,6 +1,6 @@
 /** @file
 *
-*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  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         
@@ -31,6 +31,7 @@
 #include <Library/PrintLib.h>
 #include <Library/UefiRuntimeServicesTableLib.h>
 
+#include <Guid/ArmMpCoreInfo.h>
 #include <Guid/GlobalVariable.h>
 #include <Guid/FileInfo.h>
 
@@ -41,7 +42,7 @@
 #include <Protocol/LoadFile.h>
 #include <Protocol/PxeBaseCode.h>
 
-#include "BdsLinuxLoader.h"
+#include <Uefi.h>
 
 typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) (
   IN EFI_DEVICE_PATH            *DevicePath,
@@ -94,13 +95,4 @@ BdsLoadImage (
   OUT    UINTN                 *FileSize
   );
 
-EFI_STATUS
-PrepareAtagList (
-  IN  CONST CHAR8*          CommandLineString,
-  IN  EFI_PHYSICAL_ADDRESS  InitrdImage,
-  IN  UINTN                 InitrdImageSize,
-  OUT EFI_PHYSICAL_ADDRESS  *AtagBase,
-  OUT UINT32                *AtagSize
-  );
-
 #endif
index 20644f1f7cdcdca9a4369f2dbe268a2ec31464e7..9dee03a7957ee981eb3b5141110c3da7900e7784 100644 (file)
@@ -1,5 +1,6 @@
 #/* @file
-#  Copyright (c) 2011, ARM Limited. All rights reserved.
+#  
+#  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         
@@ -27,6 +28,7 @@
 
   BdsLinuxLoader.c
   BdsLinuxAtag.c
+  BdsLinuxFdt.c
 
 [Packages]
   MdePkg/MdePkg.dec
   HobLib
   PerformanceLib
   SerialPortLib
+  FdtLib
 
 [Guids]
   gEfiFileInfoGuid
+  gArmMpCoreInfoGuid
 
 [Protocols]
   gEfiBdsArchProtocolGuid                       
   gArmTokenSpaceGuid.PcdSystemMemorySize
 
   gArmTokenSpaceGuid.PcdArmMachineType
+  gArmTokenSpaceGuid.PcdArmLinuxFdtMaxOffset
+  gArmTokenSpaceGuid.PcdArmLinuxKernelFixedOffset
   gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset
   gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset
   
-[Pcd]
-  
 [Depex]
   TRUE
index 8c16bc0ec315542b90cd5385ef375909fbcd2c49..b59df07622e0e33453a3d912b687ee27040cdf73 100644 (file)
@@ -1,6 +1,6 @@
 /** @file
 *
-*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  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         
@@ -13,6 +13,7 @@
 **/
 
 #include "BdsInternal.h"
+#include "BdsLinuxLoader.h"
 
 // Point to the current ATAG
 STATIC LINUX_ATAG *mLinuxKernelCurrentAtag;
@@ -78,6 +79,22 @@ SetupCmdlineTag (
   }
 }
 
+STATIC
+VOID
+SetupInitrdTag (
+  IN UINT32 InitrdImage,
+  IN UINT32 InitrdImageSize
+  )
+{
+  mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_INITRD2);
+  mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2;
+
+  mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage;
+  mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize;
+
+  // Move pointer to next tag
+  mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
+}
 STATIC
 VOID
 SetupEndTag (
@@ -114,7 +131,7 @@ PrepareAtagList (
   AtagStartAddress = LINUX_ATAG_MAX_OFFSET;
   Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress);
   if (EFI_ERROR(Status)) {
-    DEBUG ((EFI_D_ERROR,"Failed to allocate Atag at 0x%lX (%r)\n",AtagStartAddress,Status));
+    DEBUG ((EFI_D_WARN, "Warning: Failed to allocate Atag at 0x%lX (%r). The Atag will be allocated somewhere else in System Memory.\n", AtagStartAddress, Status));
     Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress);
     ASSERT_EFI_ERROR(Status);
   }
@@ -141,14 +158,7 @@ PrepareAtagList (
   }
 
   if (InitrdImageSize > 0 && InitrdImage != 0) {
-    mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_INITRD2);
-    mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2;
-
-    mLinuxKernelCurrentAtag->body.initrd2_tag.start = (UINT32)InitrdImage;
-    mLinuxKernelCurrentAtag->body.initrd2_tag.size = (UINT32)InitrdImageSize;
-
-    // Move pointer to next tag
-    mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag);
+    SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize);
   }
 
   // End of tags
diff --git a/ArmPkg/Library/BdsLib/BdsLinuxFdt.c b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c
new file mode 100644 (file)
index 0000000..fa06287
--- /dev/null
@@ -0,0 +1,368 @@
+/** @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 <Library/PcdLib.h>\r
+#include <libfdt.h>\r
+\r
+#include "BdsInternal.h"\r
+#include "BdsLinuxLoader.h"\r
+\r
+#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))\r
+#define PALIGN(p, a)    ((void *)(ALIGN((unsigned long)(p), (a))))\r
+#define GET_CELL(p)     (p += 4, *((const UINT32 *)(p-4)))\r
+\r
+STATIC\r
+UINTN\r
+IsPrintableString (\r
+  IN CONST VOID* data,\r
+  IN UINTN len\r
+  )\r
+{\r
+  CONST CHAR8 *s = data;\r
+  CONST CHAR8 *ss;\r
+\r
+  // Zero length is not\r
+  if (len == 0) {\r
+    return 0;\r
+  }\r
+\r
+  // Must terminate with zero\r
+  if (s[len - 1] != '\0') {\r
+    return 0;\r
+  }\r
+\r
+  ss = s;\r
+  while (*s/* && isprint(*s)*/) {\r
+    s++;\r
+  }\r
+\r
+  // Not zero, or not done yet\r
+  if (*s != '\0' || (s + 1 - ss) < len) {\r
+    return 0;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+STATIC\r
+VOID\r
+PrintData (\r
+  IN CONST CHAR8* data,\r
+  IN UINTN len\r
+  )\r
+{\r
+  UINTN i;\r
+  CONST CHAR8 *p = data;\r
+\r
+  // No data, don't print\r
+  if (len == 0)\r
+    return;\r
+\r
+  if (IsPrintableString (data, len)) {\r
+    Print(L" = \"%a\"", (const char *)data);\r
+  } else if ((len % 4) == 0) {\r
+    Print(L" = <");\r
+    for (i = 0; i < len; i += 4) {\r
+      Print(L"0x%08x%a", fdt32_to_cpu(GET_CELL(p)),i < (len - 4) ? " " : "");\r
+    }\r
+    Print(L">");\r
+  } else {\r
+    Print(L" = [");\r
+    for (i = 0; i < len; i++)\r
+      Print(L"%02x%a", *p++, i < len - 1 ? " " : "");\r
+    Print(L"]");\r
+  }\r
+}\r
+\r
+VOID\r
+DebugDumpFdt (\r
+  IN VOID*                FdtBlob\r
+  )\r
+{\r
+  struct fdt_header *bph;\r
+  UINT32 off_dt;\r
+  UINT32 off_str;\r
+  CONST CHAR8* p_struct;\r
+  CONST CHAR8* p_strings;\r
+  CONST CHAR8* p;\r
+  CONST CHAR8* s;\r
+  CONST CHAR8* t;\r
+  UINT32 tag;\r
+  UINTN sz;\r
+  UINTN depth;\r
+  UINTN shift;\r
+  UINT32 version;\r
+\r
+  depth = 0;\r
+  shift = 4;\r
+\r
+  bph = FdtBlob;\r
+  off_dt = fdt32_to_cpu(bph->off_dt_struct);\r
+  off_str = fdt32_to_cpu(bph->off_dt_strings);\r
+  p_struct = (CONST CHAR8*)FdtBlob + off_dt;\r
+  p_strings = (CONST CHAR8*)FdtBlob + off_str;\r
+  version = fdt32_to_cpu(bph->version);\r
+\r
+  p = p_struct;\r
+  while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {\r
+    if (tag == FDT_BEGIN_NODE) {\r
+      s = p;\r
+      p = PALIGN(p + AsciiStrLen (s) + 1, 4);\r
+\r
+      if (*s == '\0')\r
+              s = "/";\r
+\r
+      Print(L"%*s%a {\n", depth * shift, L" ", s);\r
+\r
+      depth++;\r
+      continue;\r
+    }\r
+\r
+    if (tag == FDT_END_NODE) {\r
+      depth--;\r
+\r
+      Print(L"%*s};\n", depth * shift, L" ");\r
+      continue;\r
+    }\r
+\r
+    if (tag == FDT_NOP) {\r
+      Print(L"%*s// [NOP]\n", depth * shift, L" ");\r
+      continue;\r
+    }\r
+\r
+    if (tag != FDT_PROP) {\r
+      Print(L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);\r
+      break;\r
+    }\r
+    sz = fdt32_to_cpu(GET_CELL(p));\r
+    s = p_strings + fdt32_to_cpu(GET_CELL(p));\r
+    if (version < 16 && sz >= 8)\r
+            p = PALIGN(p, 8);\r
+    t = p;\r
+\r
+    p = PALIGN(p + sz, 4);\r
+\r
+    Print(L"%*s%a", depth * shift, L" ", s);\r
+    PrintData(t, sz);\r
+    Print(L";\n");\r
+  }\r
+}\r
+\r
+typedef struct {\r
+  UINTN   Base;\r
+  UINTN   Size;\r
+} FdtRegion;\r
+\r
+EFI_STATUS\r
+PrepareFdt (\r
+  IN     CONST CHAR8*         CommandLineArguments,\r
+  IN     EFI_PHYSICAL_ADDRESS InitrdImage,\r
+  IN     UINTN                InitrdImageSize,\r
+  IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,\r
+  IN OUT UINT32               *FdtBlobSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  NewFdtBlobBase;\r
+  UINTN                 NewFdtBlobSize;\r
+  VOID*                 fdt;\r
+  INTN                  err;\r
+  INTN                  node;\r
+  INTN                  cpu_node;\r
+  INTN                  lenp;\r
+  CONST VOID*           BootArg;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImageStart;\r
+  EFI_PHYSICAL_ADDRESS  InitrdImageEnd;\r
+  FdtRegion             Region;\r
+  UINTN                 Index;\r
+  CHAR8                 Name[10];\r
+  LIST_ENTRY            ResourceList;\r
+  BDS_SYSTEM_MEMORY_RESOURCE  *Resource;\r
+  ARM_PROCESSOR_TABLE   *ArmProcessorTable;\r
+  ARM_CORE_INFO         *ArmCoreInfoTable;\r
+  UINT32                MpId;\r
+  UINT32                ClusterId;\r
+  UINT32                CoreId;\r
+  UINT64                CpuReleaseAddr;\r
+\r
+  err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase));\r
+  if (err != 0) {\r
+    Print (L"ERROR: Device Tree header not valid (err:%d)\n", err);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for the new FDT\r
+  //\r
+  NewFdtBlobSize = fdt_totalsize((VOID*)(UINTN)(*FdtBlobBase)) + FDT_ADDITIONAL_ENTRIES_SIZE;\r
+\r
+  // Try below a watermark address\r
+  Status = EFI_NOT_FOUND;\r
+  if (PcdGet32(PcdArmLinuxFdtMaxOffset) != 0) {\r
+    NewFdtBlobBase = LINUX_FDT_MAX_OFFSET;\r
+    Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((EFI_D_WARN, "Warning: Failed to load FDT below address 0x%lX (%r). Will try again at a random address anywhere.\n", NewFdtBlobBase, Status));\r
+    }\r
+  }\r
+\r
+  // Try anywhere there is available space\r
+  if (EFI_ERROR(Status)) {\r
+    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);\r
+    if (EFI_ERROR(Status)) {\r
+      ASSERT_EFI_ERROR(Status);\r
+      goto FAIL_NEW_FDT;\r
+    } else {\r
+      DEBUG ((EFI_D_WARN, "WARNING: Loaded FDT at random address 0x%lX.\nWARNING: There is a risk of accidental overwriting by other code/data.\n", NewFdtBlobBase));\r
+    }\r
+  }\r
+\r
+  // Load the Original FDT tree into the new region\r
+  fdt = (VOID*)(UINTN)NewFdtBlobBase;\r
+  err = fdt_open_into((VOID*)(UINTN)(*FdtBlobBase), fdt, NewFdtBlobSize);\r
+  if (err) {\r
+    DEBUG((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror(err)));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto FAIL_NEW_FDT;\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN();\r
+    //DebugDumpFdt (fdt);\r
+  DEBUG_CODE_END();\r
+\r
+  node = fdt_subnode_offset(fdt, 0, "chosen");\r
+  if (node < 0) {\r
+    // The 'chosen' node does not exist, create it\r
+    node = fdt_add_subnode(fdt, 0, "chosen");\r
+    if (node < 0) {\r
+      DEBUG((EFI_D_ERROR,"Error on finding 'chosen' node\n"));\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto FAIL_NEW_FDT;\r
+    }\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN();\r
+    BootArg = fdt_getprop(fdt, node, "bootargs", &lenp);\r
+    if (BootArg != NULL) {\r
+      DEBUG((EFI_D_ERROR,"BootArg: %a\n",BootArg));\r
+    }\r
+  DEBUG_CODE_END();\r
+\r
+  // Set Linux CmdLine\r
+  if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) {\r
+    err = fdt_setprop(fdt, node, "bootargs", CommandLineArguments, AsciiStrSize(CommandLineArguments));\r
+    if (err) {\r
+      DEBUG((EFI_D_ERROR,"Fail to set new 'bootarg' (err:%d)\n",err));\r
+    }\r
+  }\r
+\r
+  // Set Linux Initrd\r
+  if (InitrdImageSize != 0) {\r
+    InitrdImageStart = cpu_to_fdt64 (InitrdImage);\r
+    err = fdt_setprop(fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof(EFI_PHYSICAL_ADDRESS));\r
+    if (err) {\r
+      DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err));\r
+    }\r
+    InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize);\r
+    err = fdt_setprop(fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof(EFI_PHYSICAL_ADDRESS));\r
+    if (err) {\r
+      DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err));\r
+    }\r
+  }\r
+\r
+  // Set Physical memory setup if does not exist\r
+  node = fdt_subnode_offset(fdt, 0, "memory");\r
+  if (node < 0) {\r
+    // The 'memory' node does not exist, create it\r
+    node = fdt_add_subnode(fdt, 0, "memory");\r
+    if (node >= 0) {\r
+      fdt_setprop_string(fdt, node, "name", "memory");\r
+      fdt_setprop_string(fdt, node, "device_type", "memory");\r
+      \r
+      GetSystemMemoryResources (&ResourceList);\r
+      Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink;\r
+      \r
+      if (sizeof(UINTN) == sizeof(UINT32)) {\r
+        Region.Base = cpu_to_fdt32((UINTN)Resource->PhysicalStart);\r
+        Region.Size = cpu_to_fdt32((UINTN)Resource->ResourceLength);\r
+      } else {\r
+        Region.Base = cpu_to_fdt64((UINTN)Resource->PhysicalStart);\r
+        Region.Size = cpu_to_fdt64((UINTN)Resource->ResourceLength);\r
+      }\r
+\r
+      err = fdt_setprop(fdt, node, "reg", &Region, sizeof(Region));\r
+      if (err) {\r
+        DEBUG((EFI_D_ERROR,"Fail to set new 'memory region' (err:%d)\n",err));\r
+      }\r
+    }\r
+  }\r
+\r
+  // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms\r
+  for (Index=0; Index < gST->NumberOfTableEntries; Index++) {\r
+    // Check for correct GUID type\r
+    if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
+      MpId = ArmReadMpidr ();\r
+      ClusterId = GET_CLUSTER_ID(MpId);\r
+      CoreId    = GET_CORE_ID(MpId);\r
+\r
+      node = fdt_subnode_offset(fdt, 0, "cpus");\r
+      if (node < 0) {\r
+        // Create the /cpus node\r
+        node = fdt_add_subnode(fdt, 0, "cpus");\r
+        fdt_setprop_string(fdt, node, "name", "cpus");\r
+        fdt_setprop_cell(fdt, node, "#address-cells", 1);\r
+        fdt_setprop_cell(fdt, node, "#size-cells", 0);\r
+      }\r
+\r
+      // Get pointer to ARM processor table\r
+      ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable;\r
+      ArmCoreInfoTable = ArmProcessorTable->ArmCpus;\r
+\r
+      for (Index = 0; Index < ArmProcessorTable->NumberOfEntries; Index++) {\r
+        AsciiSPrint (Name, 10, "cpu@%d", Index);\r
+        cpu_node = fdt_subnode_offset(fdt, node, Name);\r
+        if (cpu_node < 0) {\r
+          cpu_node = fdt_add_subnode(fdt, node, Name);\r
+          fdt_setprop_string(fdt, cpu_node, "device-type", "cpu");\r
+          fdt_setprop(fdt, cpu_node, "reg", &Index, sizeof(Index));\r
+        }\r
+\r
+        fdt_setprop_string(fdt, cpu_node, "enable-method", "spin-table");\r
+        CpuReleaseAddr = cpu_to_fdt64(ArmCoreInfoTable[Index].MailboxSetAddress);\r
+        fdt_setprop(fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof(CpuReleaseAddr));\r
+\r
+        // If it is not the primary core than the cpu should be disabled\r
+        if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) {\r
+          fdt_setprop_string(fdt, cpu_node, "status", "disabled");\r
+        }\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN();\r
+    //DebugDumpFdt (fdt);\r
+  DEBUG_CODE_END();\r
+\r
+  *FdtBlobBase = NewFdtBlobBase;\r
+  *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));\r
+  return EFI_SUCCESS;\r
+\r
+FAIL_NEW_FDT:\r
+  *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase));\r
+  // Return success even if we failed to update the FDT blob. The original one is still valid.\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
index a3ba58023adc8d8da4eef5564456baf9c2f4412c..901781f2f852bc158e6ef64e9c40edefed00b85e 100644 (file)
@@ -64,9 +64,15 @@ StartLinux (
   // This is necessary because the ARM Linux kernel requires
   // the FTD / ATAG List to reside entirely inside the first 1MB of
   // physical memory.
-  if ((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) {
-    //Note: There is no requirement on the alignment
-    KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize);
+  //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) {
@@ -135,14 +141,14 @@ EFI_STATUS
 BdsBootLinuxAtag (
   IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
   IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
-  IN  CONST CHAR8*              Arguments
+  IN  CONST CHAR8*              CommandLineArguments
   )
 {
   EFI_STATUS            Status;
   UINT32                LinuxImageSize;
   UINT32                InitrdImageSize = 0;
-  UINT32                KernelParamsSize;
-  EFI_PHYSICAL_ADDRESS  KernelParamsAddress;
+  UINT32                AtagSize;
+  EFI_PHYSICAL_ADDRESS  AtagBase;
   EFI_PHYSICAL_ADDRESS  LinuxImage;
   EFI_PHYSICAL_ADDRESS  InitrdImage;
 
@@ -181,13 +187,13 @@ BdsBootLinuxAtag (
   //
  
   // By setting address=0 we leave the memory allocation to the function
-  Status = PrepareAtagList (Arguments, InitrdImage, InitrdImageSize, &KernelParamsAddress, &KernelParamsSize);
+  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, KernelParamsAddress, KernelParamsSize, PcdGet32(PcdArmMachineType));
+  return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType));
 }
 
 /**
@@ -206,21 +212,18 @@ EFI_STATUS
 BdsBootLinuxFdt (
   IN  EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath,
   IN  EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath,
-  IN  CONST CHAR8*              Arguments,
+  IN  CONST CHAR8*              CommandLineArguments,
   IN  EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath
   )
 {
   EFI_STATUS            Status;
   UINT32                LinuxImageSize;
   UINT32                InitrdImageSize = 0;
-  UINT32                KernelParamsSize;
-  EFI_PHYSICAL_ADDRESS  KernelParamsAddress;
-  UINT32                FdtMachineType;
+  UINT32                FdtBlobSize;
+  EFI_PHYSICAL_ADDRESS  FdtBlobBase;
   EFI_PHYSICAL_ADDRESS  LinuxImage;
   EFI_PHYSICAL_ADDRESS  InitrdImage;
 
-  FdtMachineType = 0xFFFFFFFF;
-
   PERF_START (NULL, "BDS", NULL, 0);
 
   // Load the Linux kernel from a device path
@@ -250,13 +253,22 @@ BdsBootLinuxFdt (
     }
   }
 
-  // Load the FDT binary from a device path
-  KernelParamsAddress = LINUX_ATAG_MAX_OFFSET;
-  Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &KernelParamsAddress, &KernelParamsSize);
+  // 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;
   }
-  return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, FdtMachineType);
+
+  // 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);
 }
 
index 8d58ce103a1a829eafdc26849ba8d3b012fcdb27..a9b7037d19cd080bc40b1f80e6cb9cddb9fcc723 100644 (file)
 #define __BDSLINUXLOADER_H
 
 #define LINUX_UIMAGE_SIGNATURE    0x56190527
-
-#define LINUX_ATAG_MAX_OFFSET     (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset))
 #define LINUX_KERNEL_MAX_OFFSET   (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxKernelMaxOffset))
+#define LINUX_ATAG_MAX_OFFSET     (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset))
+#define LINUX_FDT_MAX_OFFSET      (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxFdtMaxOffset))
 
-#define ATAG_MAX_SIZE       0x3000
+// Additional size that could be used for FDT entries added by the UEFI OS Loader
+// Estimation based on: EDID (300bytes) + bootargs (200bytes) + initrd region (20bytes)
+//                      + system memory region (20bytes) + mp_core entries (200 bytes)
+#define FDT_ADDITIONAL_ENTRIES_SIZE     0x300
+
+#define ARM_FDT_MACHINE_TYPE            0xFFFFFFFF
+
+typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase);
+
+//
+// ATAG Definitions
+//
+
+#define ATAG_MAX_SIZE        0x3000
 
 /* ATAG : list of possible tags */
 #define ATAG_NONE            0x00000000
@@ -35,7 +48,9 @@
 #define ATAG_CMDLINE         0x54410009
 #define ATAG_ARM_MP_CORE     0x5441000A
 
-/* structures for each atag */
+#define next_tag_address(t)  ((LINUX_ATAG*)((UINT32)(t) + (((t)->header.size) << 2) ))
+#define tag_size(type)       ((UINT32)((sizeof(LINUX_ATAG_HEADER) + sizeof(type)) >> 2))
+
 typedef struct {
   UINT32  size; /* length of tag in words including this header */
   UINT32  type;  /* tag type */
@@ -120,9 +135,22 @@ typedef struct {
   } body;
 } LINUX_ATAG;
 
-typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase);
-
-#define next_tag_address(t)     ((LINUX_ATAG*)((UINT32)(t) + (((t)->header.size) << 2) ))
-#define tag_size(type)          ((UINT32)((sizeof(LINUX_ATAG_HEADER) + sizeof(type)) >> 2))
+EFI_STATUS
+PrepareAtagList (
+  IN  CONST CHAR8*          CommandLineString,
+  IN  EFI_PHYSICAL_ADDRESS  InitrdImage,
+  IN  UINTN                 InitrdImageSize,
+  OUT EFI_PHYSICAL_ADDRESS  *AtagBase,
+  OUT UINT32                *AtagSize
+  );
+
+EFI_STATUS
+PrepareFdt (
+  IN     CONST CHAR8*         CommandLineArguments,
+  IN     EFI_PHYSICAL_ADDRESS InitrdImage,
+  IN     UINTN                InitrdImageSize,
+  IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase,
+  IN OUT UINT32               *FdtBlobSize
+  );
 
 #endif
index 27413fe5a349f181010f079fb7dff1ecb1917399..385d296dbb1a11c71bb1f3bffba0c198ac3ad384 100644 (file)
@@ -99,6 +99,7 @@
 \r
   # BDS Libraries\r
   BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf\r
+  FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf\r
 \r
 [LibraryClasses.common.SEC]\r
   ArmPlatformSecExtraActionLib|ArmPlatformPkg/Library/DebugSecExtraActionLib/DebugSecExtraActionLib.inf\r
index fdff40da6310747c98e6f4739f1e60e3b5a20d80..1af5490b912a6497ee1e177485b8f9e4e8491ffd 100644 (file)
 \r
   # BDS Libraries\r
   BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf\r
+  FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf\r
 \r
 [LibraryClasses.common.SEC]\r
   ArmPlatformSecExtraActionLib|ArmPlatformPkg/Library/DebugSecExtraActionLib/DebugSecExtraActionLib.inf\r
index db6ba895ca3b06a7fa6f4018616512a4f3cec607..4e00c034521f6bcfd74dbccad0b9918f61897df4 100644 (file)
   DmaLib|ArmPkg/Library/ArmDmaLib/ArmDmaLib.inf\r
 \r
   BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf\r
+  FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf\r
 \r
 [LibraryClasses.common.SEC]\r
   ArmLib|ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf\r