diff options
Diffstat (limited to 'EmbeddedPkg/Library/FdtLib')
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/0001-EmbeddedPkg-Added-libfdt-port.patch | 220 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/0002-ArmPkg-BdsLib-Added-support-for-modifying-the-passed.patch | 489 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/0003-ArmPlatformPkg-EblCmdLib-Add-dumpfdt-EBL-command.patch | 300 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/FdtLib.inf | 38 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/Makefile.libfdt | 10 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/TODO | 3 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt.c | 222 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c | 84 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt_ro.c | 575 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt_rw.c | 495 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt_strerror.c | 96 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt_sw.c | 256 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/fdt_wip.c | 118 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/libfdt_internal.h | 95 | ||||
-rw-r--r-- | EmbeddedPkg/Library/FdtLib/version.lds | 54 |
15 files changed, 2046 insertions, 1009 deletions
diff --git a/EmbeddedPkg/Library/FdtLib/0001-EmbeddedPkg-Added-libfdt-port.patch b/EmbeddedPkg/Library/FdtLib/0001-EmbeddedPkg-Added-libfdt-port.patch deleted file mode 100644 index ae06b6f396..0000000000 --- a/EmbeddedPkg/Library/FdtLib/0001-EmbeddedPkg-Added-libfdt-port.patch +++ /dev/null @@ -1,220 +0,0 @@ -From 669778eab2092ef85ed5b5e537203721cfb1215d Mon Sep 17 00:00:00 2001 -From: Olivier Martin <olivier.martin@arm.com> -Date: Thu, 16 Feb 2012 15:44:35 +0000 -Subject: [PATCH 1/3] EmbeddedPkg: Added libfdt port - -This port is based on the 'libfdt' project (dual licensed BSD/GPL). - -Prior to apply this patch you must execute the following steps: - -1. Clone the dtc into a temporary directory: -cd EmbeddedPkg/Library -git clone git://git.jdl.com/software/dtc.git - -2. Copy the content of 'libfdt' into EmbeddedPkg/Library/FdtLib/ -cd dtc -cp -a libfdt ../FdtLib - -3. Copy the libfdt headers: -mv ../FdtLib/libfdt.h ../../Include/ -mv ../FdtLib/fdt.h ../../Include/ -rm ../FdtLib/libfdt_env.h ---- - EmbeddedPkg/EmbeddedPkg.dsc | 1 + - EmbeddedPkg/Include/libfdt_env.h | 77 +++++++++++++++++++++++++++++++++ - EmbeddedPkg/Library/FdtLib/FdtLib.inf | 38 ++++++++++++++++ - EmbeddedPkg/Library/FdtLib/README.txt | 38 ++++++++++++++++ - 4 files changed, 154 insertions(+), 0 deletions(-) - mode change 100644 => 100755 EmbeddedPkg/EmbeddedPkg.dsc - create mode 100755 EmbeddedPkg/Include/libfdt_env.h - create mode 100755 EmbeddedPkg/Library/FdtLib/FdtLib.inf - create mode 100755 EmbeddedPkg/Library/FdtLib/README.txt - -diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc -old mode 100644 -new mode 100755 -index 8862f3d..c3a2464 ---- a/EmbeddedPkg/EmbeddedPkg.dsc -+++ b/EmbeddedPkg/EmbeddedPkg.dsc -@@ -97,6 +97,7 @@ - - EblNetworkLib|EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf - -+ FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf - - [LibraryClasses.common.DXE_DRIVER] - PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf -diff --git a/EmbeddedPkg/Include/libfdt_env.h b/EmbeddedPkg/Include/libfdt_env.h -new file mode 100755 -index 0000000..8c4f1c7 ---- /dev/null -+++ b/EmbeddedPkg/Include/libfdt_env.h -@@ -0,0 +1,77 @@ -+/** @file -+* -+* Copyright (c) 2011, ARM Limited. All rights reserved. -+* -+* This program and the accompanying materials -+* are licensed and made available under the terms and conditions of the BSD License -+* which accompanies this distribution. The full text of the license may be found at -+* http://opensource.org/licenses/bsd-license.php -+* -+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -+* -+**/ -+ -+#ifndef _LIBFDT_ENV_H -+#define _LIBFDT_ENV_H -+ -+#include <Library/BaseLib.h> -+#include <Library/BaseMemoryLib.h> -+ -+typedef UINT8 uint8_t; -+typedef UINT16 uint16_t; -+typedef UINT32 uint32_t; -+typedef UINT64 uint64_t; -+typedef UINTN uintptr_t; -+typedef UINTN size_t; -+ -+static inline uint16_t fdt16_to_cpu(uint16_t x) -+{ -+ return SwapBytes16 (x); -+} -+#define cpu_to_fdt16(x) fdt16_to_cpu(x) -+ -+static inline uint32_t fdt32_to_cpu(uint32_t x) -+{ -+ return SwapBytes32 (x); -+} -+#define cpu_to_fdt32(x) fdt32_to_cpu(x) -+ -+static inline uint64_t fdt64_to_cpu(uint64_t x) -+{ -+ return SwapBytes64 (x); -+} -+#define cpu_to_fdt64(x) fdt64_to_cpu(x) -+ -+static inline void* memcpy(void* dest, const void* src, size_t len) { -+ return CopyMem (dest, src, len); -+} -+ -+static inline void *memmove(void *dest, const void *src, size_t n) { -+ return CopyMem (dest, src, n); -+} -+ -+static inline void *memset(void *s, int c, size_t n) { -+ return SetMem (s, n, c); -+} -+ -+static inline int memcmp(const void* dest, const void* src, int len) { -+ return CompareMem (dest, src, len); -+} -+ -+static inline void *memchr(const void *s, int c, size_t n) { -+ return ScanMem8 (s, n, c); -+} -+ -+static inline size_t strlen (const char* str) { -+ return AsciiStrLen (str); -+} -+ -+static inline char *strchr(const char *s, int c) { -+ char pattern[2]; -+ pattern[0] = c; -+ pattern[1] = 0; -+ return AsciiStrStr (s, pattern); -+} -+ -+#endif /* _LIBFDT_ENV_H */ -diff --git a/EmbeddedPkg/Library/FdtLib/FdtLib.inf b/EmbeddedPkg/Library/FdtLib/FdtLib.inf -new file mode 100755 -index 0000000..9753ed8 ---- /dev/null -+++ b/EmbeddedPkg/Library/FdtLib/FdtLib.inf -@@ -0,0 +1,38 @@ -+#/* @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.
-+#
-+#*/
-+
-+[Defines]
-+ INF_VERSION = 0x00010005
-+ BASE_NAME = FdtLib
-+ FILE_GUID = 6b2478c0-be23-11e0-a28c-0002a5d5c51b
-+ MODULE_TYPE = BASE
-+ VERSION_STRING = 1.0
-+ LIBRARY_CLASS = FdtLib
-+
-+#
-+# The following information is for reference only and not required by the build tools.
-+#
-+# VALID_ARCHITECTURES = ARM
-+#
-+
-+[Sources]
-+ fdt_ro.c
-+ fdt_rw.c
-+ fdt_strerror.c
-+ fdt_sw.c
-+ fdt_wip.c
-+ fdt.c
-+
-+[Packages]
-+ MdePkg/MdePkg.dec
-+ EmbeddedPkg/EmbeddedPkg.dec
-diff --git a/EmbeddedPkg/Library/FdtLib/README.txt b/EmbeddedPkg/Library/FdtLib/README.txt -new file mode 100755 -index 0000000..c74db7a ---- /dev/null -+++ b/EmbeddedPkg/Library/FdtLib/README.txt -@@ -0,0 +1,38 @@ -+Credits
-+-------
-+Principal original author: David Gibson (david AT gibson.dropbear.id.au)
-+Maintainer: Jon Loeliger (jdl AT jdl.com)
-+
-+
-+Licensing:
-+----------
-+libfdt is GPL/BSD dual-licensed.
-+
-+
-+Current version:
-+----------------
-+
-+# Latest commit in dtc.git repository :
-+commit a31e3ef83bfce62d07695355e5f06cd4d0e44b86
-+Author: Minghuan Lian <Minghuan.Lian@freescale.com>
-+Date: Mon Dec 5 12:22:07 2011 +1100
-+
-+# Latest commit in libfdt :
-+commit a31e3ef83bfce62d07695355e5f06cd4d0e44b86
-+Author: Minghuan Lian <Minghuan.Lian@freescale.com>
-+Date: Mon Dec 5 12:22:07 2011 +1100
-+
-+
-+How to update EmbeddedPkg/Library/FdtLib
-+----------------------------------------
-+1. Clone the dtc into a temporary directory:
-+git clone git://git.jdl.com/software/dtc.git
-+
-+2. Copy the content of 'libfdt' into EmbeddedPkg/Library/FdtLib/
-+cd dtc
-+cp -a libfdt/* $(EDK2_ROOT)/EmbeddedPkg/Library/FdtLib/
-+
-+3. Copy the libfdt headers:
-+mv $(EDK2_ROOT)/EmbeddedPkg/Library/FdtLib/libfdt.h $(EDK2_ROOT)/EmbeddedPkg/Include/
-+mv $(EDK2_ROOT)/EmbeddedPkg/Library/FdtLib/fdt.h $(EDK2_ROOT)/EmbeddedPkg/Include/
-+rm $(EDK2_ROOT)/EmbeddedPkg/Library/FdtLib/libfdt_env.h
--- -1.7.0.4 - diff --git a/EmbeddedPkg/Library/FdtLib/0002-ArmPkg-BdsLib-Added-support-for-modifying-the-passed.patch b/EmbeddedPkg/Library/FdtLib/0002-ArmPkg-BdsLib-Added-support-for-modifying-the-passed.patch deleted file mode 100644 index 66ea902875..0000000000 --- a/EmbeddedPkg/Library/FdtLib/0002-ArmPkg-BdsLib-Added-support-for-modifying-the-passed.patch +++ /dev/null @@ -1,489 +0,0 @@ -From 9c16a23fba659cdf0ce798aa085a4fb8c3bd47d1 Mon Sep 17 00:00:00 2001 -From: Olivier Martin <olivier.martin@arm.com> -Date: Thu, 16 Feb 2012 15:50:59 +0000 -Subject: [PATCH 2/3] ArmPkg/BdsLib: Added support for modifying the passed FDT blob - -- Add Linux CmdLine if not defined -- Add initrd if not defined -- Add CPU parking address if not defined -- Add System Memory info if not defined ---- - ArmPkg/ArmPkg.dsc | 1 + - ArmPkg/Library/BdsLib/BdsInternal.h | 9 + - ArmPkg/Library/BdsLib/BdsLib.inf | 3 + - ArmPkg/Library/BdsLib/BdsLinuxFdt.c | 353 ++++++++++++++++++++++++++++++++ - ArmPkg/Library/BdsLib/BdsLinuxLoader.c | 8 + - ArmPkg/Library/BdsLib/BdsLinuxLoader.h | 10 +- - 6 files changed, 383 insertions(+), 1 deletions(-) - mode change 100644 => 100755 ArmPkg/ArmPkg.dsc - mode change 100644 => 100755 ArmPkg/Library/BdsLib/BdsInternal.h - mode change 100644 => 100755 ArmPkg/Library/BdsLib/BdsLib.inf - create mode 100755 ArmPkg/Library/BdsLib/BdsLinuxFdt.c - -diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc -old mode 100644 -new mode 100755 -index f4989a6..07c825d ---- a/ArmPkg/ArmPkg.dsc -+++ b/ArmPkg/ArmPkg.dsc -@@ -72,6 +72,7 @@ - SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf - - BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf -+ FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf - - IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf - -diff --git a/ArmPkg/Library/BdsLib/BdsInternal.h b/ArmPkg/Library/BdsLib/BdsInternal.h -old mode 100644 -new mode 100755 -index 880d780..80d21b2 ---- a/ArmPkg/Library/BdsLib/BdsInternal.h -+++ b/ArmPkg/Library/BdsLib/BdsInternal.h -@@ -103,4 +103,13 @@ PrepareAtagList ( - OUT UINT32 *AtagSize - ); - -+EFI_STATUS -+PrepareFdt ( -+ IN CONST CHAR8* CommandLineString, -+ IN EFI_PHYSICAL_ADDRESS InitrdImage, -+ IN UINTN InitrdImageSize, -+ IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase, -+ IN OUT UINT32 *FdtBlobSize -+ ); -+ - #endif -diff --git a/ArmPkg/Library/BdsLib/BdsLib.inf b/ArmPkg/Library/BdsLib/BdsLib.inf -old mode 100644 -new mode 100755 -index 20644f1..b3cab21 ---- a/ArmPkg/Library/BdsLib/BdsLib.inf -+++ b/ArmPkg/Library/BdsLib/BdsLib.inf -@@ -27,6 +27,7 @@ - - BdsLinuxLoader.c - BdsLinuxAtag.c -+ BdsLinuxFdt.c - - [Packages] - MdePkg/MdePkg.dec -@@ -41,9 +42,11 @@ - HobLib - PerformanceLib - SerialPortLib -+ FdtLib - - [Guids] - gEfiFileInfoGuid -+ gArmMpCoreInfoGuid - - [Protocols] - gEfiBdsArchProtocolGuid -diff --git a/ArmPkg/Library/BdsLib/BdsLinuxFdt.c b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c -new file mode 100755 -index 0000000..5c14b65 ---- /dev/null -+++ b/ArmPkg/Library/BdsLib/BdsLinuxFdt.c -@@ -0,0 +1,353 @@ -+/** @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 <Library/PcdLib.h> -+#include <libfdt.h> -+ -+#include "BdsInternal.h" -+ -+#define LINUX_FDT_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset)) -+ -+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) -+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) -+#define GET_CELL(p) (p += 4, *((const UINT32 *)(p-4))) -+ -+STATIC -+UINTN -+IsPrintableString ( -+ IN CONST VOID* data, -+ IN UINTN len -+ ) -+{ -+ CONST CHAR8 *s = data; -+ CONST CHAR8 *ss; -+ -+ // zero length is not -+ if (len == 0) { -+ return 0; -+ } -+ -+ // must terminate with zero -+ if (s[len - 1] != '\0') { -+ return 0; -+ } -+ -+ ss = s; -+ while (*s/* && isprint(*s)*/) { -+ s++; -+ } -+ -+ // not zero, or not done yet -+ if (*s != '\0' || (s + 1 - ss) < len) { -+ return 0; -+ } -+ -+ return 1; -+} -+ -+STATIC -+VOID -+PrintData ( -+ IN CONST CHAR8* data, -+ IN UINTN len -+ ) -+{ -+ UINTN i; -+ CONST CHAR8 *p = data; -+ -+ // no data, don't print -+ if (len == 0) -+ return; -+ -+ if (IsPrintableString (data, len)) { -+ Print(L" = \"%a\"", (const char *)data); -+ } else if ((len % 4) == 0) { -+ Print(L" = <"); -+ for (i = 0; i < len; i += 4) { -+ Print(L"0x%08x%a", fdt32_to_cpu(GET_CELL(p)),i < (len - 4) ? " " : ""); -+ } -+ Print(L">"); -+ } else { -+ Print(L" = ["); -+ for (i = 0; i < len; i++) -+ Print(L"%02x%a", *p++, i < len - 1 ? " " : ""); -+ Print(L"]"); -+ } -+} -+ -+VOID -+DebugDumpFdt ( -+ IN VOID* FdtBlob -+ ) -+{ -+ struct fdt_header *bph; -+ UINT32 off_dt; -+ UINT32 off_str; -+ CONST CHAR8* p_struct; -+ CONST CHAR8* p_strings; -+ CONST CHAR8* p; -+ CONST CHAR8* s; -+ CONST CHAR8* t; -+ UINT32 tag; -+ UINTN sz; -+ UINTN depth; -+ UINTN shift; -+ UINT32 version; -+ -+ depth = 0; -+ shift = 4; -+ -+ bph = FdtBlob; -+ off_dt = fdt32_to_cpu(bph->off_dt_struct); -+ off_str = fdt32_to_cpu(bph->off_dt_strings); -+ p_struct = (CONST CHAR8*)FdtBlob + off_dt; -+ p_strings = (CONST CHAR8*)FdtBlob + off_str; -+ version = fdt32_to_cpu(bph->version); -+ -+ p = p_struct; -+ while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { -+ -+ //printf("tag: 0x%08x (%d)\n", tag, p - p_struct); -+ -+ if (tag == FDT_BEGIN_NODE) { -+ s = p; -+ p = PALIGN(p + AsciiStrLen (s) + 1, 4); -+ -+ if (*s == '\0') -+ s = "/"; -+ -+ Print(L"%*s%a {\n", depth * shift, L" ", s); -+ -+ depth++; -+ continue; -+ } -+ -+ if (tag == FDT_END_NODE) { -+ depth--; -+ -+ Print(L"%*s};\n", depth * shift, L" "); -+ continue; -+ } -+ -+ if (tag == FDT_NOP) { -+ Print(L"%*s// [NOP]\n", depth * shift, L" "); -+ continue; -+ } -+ -+ if (tag != FDT_PROP) { -+ Print(L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag); -+ break; -+ } -+ sz = fdt32_to_cpu(GET_CELL(p)); -+ s = p_strings + fdt32_to_cpu(GET_CELL(p)); -+ if (version < 16 && sz >= 8) -+ p = PALIGN(p, 8); -+ t = p; -+ -+ p = PALIGN(p + sz, 4); -+ -+ Print(L"%*s%a", depth * shift, L" ", s); -+ PrintData(t, sz); -+ Print(L";\n"); -+ } -+} -+ -+typedef struct { -+ UINTN Base; -+ UINTN Size; -+} FdtRegion; -+ -+EFI_STATUS -+PrepareFdt ( -+ IN CONST CHAR8* CommandLineString, -+ IN EFI_PHYSICAL_ADDRESS InitrdImage, -+ IN UINTN InitrdImageSize, -+ IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase, -+ IN OUT UINT32 *FdtBlobSize -+ ) -+{ -+ EFI_STATUS Status; -+ EFI_PHYSICAL_ADDRESS NewFdtBlobBase; -+ UINTN NewFdtBlobSize; -+ VOID* fdt; -+ INTN err; -+ INTN node; -+ INTN cpu_node; -+ INTN lenp; -+ CONST VOID* BootArg; -+ EFI_PHYSICAL_ADDRESS InitrdImageStart; -+ EFI_PHYSICAL_ADDRESS InitrdImageEnd; -+ FdtRegion Region; -+ UINTN Index; -+ CHAR8 Name[10]; -+ LIST_ENTRY ResourceList; -+ BDS_SYSTEM_MEMORY_RESOURCE *Resource; -+ ARM_PROCESSOR_TABLE *ArmProcessorTable; -+ ARM_CORE_INFO *ArmCoreInfoTable; -+ UINT32 MpId; -+ UINT32 ClusterId; -+ UINT32 CoreId; -+ UINT64 CpuReleaseAddr; -+ -+ err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase)); -+ if (err != 0) { -+ Print (L"ERROR: Device Tree header not valid (err:%d)\n", err); -+ return EFI_INVALID_PARAMETER; -+ } -+ -+ // Allocate memory for the new FDT -+ NewFdtBlobBase = LINUX_FDT_MAX_OFFSET; -+ NewFdtBlobSize = *FdtBlobSize + FDT_ADDITIONAL_ENTRIES_SIZE; -+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase); -+ if (EFI_ERROR(Status)) { -+ DEBUG ((EFI_D_WARN, "Warning: Failed to allocate Fdt below 0x%lX (%r). The Fdt will be allocated somewhere else in System Memory.\n",NewFdtBlobBase,Status)); -+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase); -+ ASSERT_EFI_ERROR(Status); -+ goto FAIL_NEW_FDT; -+ } -+ -+ // Load the Original FDT tree into the new region -+ fdt = (VOID*)(UINTN)NewFdtBlobBase; -+ err = fdt_open_into((VOID*)(UINTN)(*FdtBlobBase), fdt, NewFdtBlobSize); -+ if (err) { -+ DEBUG((EFI_D_ERROR, "fdt_open_into(): %a\n", fdt_strerror(err))); -+ Status = EFI_INVALID_PARAMETER; -+ goto FAIL_NEW_FDT; -+ } -+ -+ DEBUG_CODE_BEGIN(); -+ DebugDumpFdt (fdt); -+ DEBUG_CODE_END(); -+ -+ node = fdt_subnode_offset(fdt, 0, "chosen"); -+ if (node < 0) { -+ // The 'chosen' node does not exist, create it -+ node = fdt_add_subnode(fdt, 0, "chosen"); -+ if (node < 0) { -+ DEBUG((EFI_D_ERROR,"Error on finding 'chosen' node\n")); -+ Status = EFI_INVALID_PARAMETER; -+ goto FAIL_NEW_FDT; -+ } -+ } -+ -+ DEBUG_CODE_BEGIN(); -+ BootArg = fdt_getprop(fdt, node, "bootargs", &lenp); -+ if (BootArg != NULL) { -+ DEBUG((EFI_D_ERROR,"BootArg: %a\n",BootArg)); -+ } -+ DEBUG_CODE_END(); -+ -+ // Set Linux CmdLine -+ if ((CommandLineString != NULL) && (AsciiStrLen (CommandLineString) > 0)) { -+ err = fdt_setprop(fdt, node, "bootargs", CommandLineString, AsciiStrSize(CommandLineString)); -+ if (err) { -+ DEBUG((EFI_D_ERROR,"Fail to set new 'bootarg' (err:%d)\n",err)); -+ } -+ } -+ -+ // Set Linux Initrd -+ if (InitrdImageSize != 0) { -+ InitrdImageStart = cpu_to_fdt64 (InitrdImage); -+ err = fdt_setprop(fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof(EFI_PHYSICAL_ADDRESS)); -+ if (err) { -+ DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err)); -+ } -+ InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize); -+ err = fdt_setprop(fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof(EFI_PHYSICAL_ADDRESS)); -+ if (err) { -+ DEBUG((EFI_D_ERROR,"Fail to set new 'linux,initrd-start' (err:%d)\n",err)); -+ } -+ } -+ -+ // Set Physical memory setup if does not exist -+ node = fdt_subnode_offset(fdt, 0, "memory"); -+ if (node < 0) { -+ // The 'chosen' node does not exist, create it -+ node = fdt_add_subnode(fdt, 0, "memory"); -+ if (node >= 0) { -+ fdt_setprop_string(fdt, node, "name", "memory"); -+ fdt_setprop_string(fdt, node, "device_type", "memory"); -+ -+ GetSystemMemoryResources (&ResourceList); -+ Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink; -+ -+ if (sizeof(UINTN) == sizeof(UINT32)) { -+ Region.Base = cpu_to_fdt32((UINTN)Resource->PhysicalStart); -+ Region.Size = cpu_to_fdt32((UINTN)Resource->ResourceLength); -+ } else { -+ Region.Base = cpu_to_fdt64((UINTN)Resource->PhysicalStart); -+ Region.Size = cpu_to_fdt64((UINTN)Resource->ResourceLength); -+ } -+ -+ err = fdt_setprop(fdt, node, "reg", &Region, sizeof(Region)); -+ if (err) { -+ DEBUG((EFI_D_ERROR,"Fail to set new 'memory region' (err:%d)\n",err)); -+ } -+ } -+ } -+ -+ // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms -+ for (Index=0; Index < gST->NumberOfTableEntries; Index++) { -+ // Check for correct GUID type -+ if (CompareGuid (&gArmMpCoreInfoGuid, &(gST->ConfigurationTable[Index].VendorGuid))) { -+ MpId = ArmReadMpidr (); -+ ClusterId = GET_CLUSTER_ID(MpId); -+ CoreId = GET_CORE_ID(MpId); -+ -+ node = fdt_subnode_offset(fdt, 0, "cpus"); -+ if (node < 0) { -+ // Create the /cpus node -+ node = fdt_add_subnode(fdt, 0, "cpus"); -+ fdt_setprop_string(fdt, node, "name", "cpus"); -+ fdt_setprop_cell(fdt, node, "#address-cells", 1); -+ fdt_setprop_cell(fdt, node, "#size-cells", 0); -+ } -+ -+ // Get pointer to ARM processor table -+ ArmProcessorTable = (ARM_PROCESSOR_TABLE *)gST->ConfigurationTable[Index].VendorTable; -+ ArmCoreInfoTable = ArmProcessorTable->ArmCpus; -+ -+ for (Index = 0; Index < ArmProcessorTable->NumberOfEntries; Index++) { -+ if (((ArmCoreInfoTable[Index].ClusterId != ClusterId) || (ArmCoreInfoTable[Index].CoreId != CoreId))) { -+ AsciiSPrint (Name, 10, "cpu@%d", Index); -+ cpu_node = fdt_subnode_offset(fdt, node, Name); -+ if (cpu_node < 0) { -+ cpu_node = fdt_add_subnode(fdt, node, Name); -+ } -+ fdt_setprop_string(fdt, cpu_node, "device-type", "cpu"); -+ fdt_setprop_string(fdt, cpu_node, "enable-method", "spin-table"); -+ fdt_setprop_string(fdt, cpu_node, "status", "disabled"); -+ CpuReleaseAddr = cpu_to_fdt64(ArmCoreInfoTable[Index].MailboxSetAddress); -+ fdt_setprop(fdt, cpu_node, "cpu-release-addr", &CpuReleaseAddr, sizeof(CpuReleaseAddr)); -+ } -+ } -+ break; -+ } -+ } -+ -+ DEBUG_CODE_BEGIN(); -+ DebugDumpFdt (fdt); -+ DEBUG_CODE_END(); -+ -+ *FdtBlobBase = NewFdtBlobBase; -+ *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase));; -+ return EFI_SUCCESS; -+ -+FAIL_NEW_FDT: -+ *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase)); -+ // Return success even if we failed to update the FDT blob. The original one is still valid. -+ return EFI_SUCCESS; -+} -+ -+ -diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c -index 12a8862..82fa811 100755 ---- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c -+++ b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c -@@ -241,6 +241,14 @@ BdsBootLinuxFdt ( - Print (L"ERROR: Did not find Device Tree blob.\n"); - return Status; - } -+ -+ // By setting address=0 we leave the memory allocation to the function -+ Status = PrepareFdt (Arguments, InitrdImage, InitrdImageSize, &KernelParamsAddress, &KernelParamsSize); -+ if (EFI_ERROR(Status)) { -+ Print(L"ERROR: Can not load Linux kernel with Device Tree. Status=0x%X\n", Status); -+ return Status; -+ } -+ - return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, FdtMachineType); - } - -diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.h b/ArmPkg/Library/BdsLib/BdsLinuxLoader.h -index 8d58ce1..9e45e03 100755 ---- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.h -+++ b/ArmPkg/Library/BdsLib/BdsLinuxLoader.h -@@ -15,12 +15,20 @@ - #ifndef __BDSLINUXLOADER_H - #define __BDSLINUXLOADER_H - -+#include <Guid/ArmMpCoreInfo.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 ATAG_MAX_SIZE 0x3000 -+// Size allocated for the Atag list -+#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 - - /* ATAG : list of possible tags */ - #define ATAG_NONE 0x00000000 --- -1.7.0.4 - diff --git a/EmbeddedPkg/Library/FdtLib/0003-ArmPlatformPkg-EblCmdLib-Add-dumpfdt-EBL-command.patch b/EmbeddedPkg/Library/FdtLib/0003-ArmPlatformPkg-EblCmdLib-Add-dumpfdt-EBL-command.patch deleted file mode 100644 index 98fc8fcb13..0000000000 --- a/EmbeddedPkg/Library/FdtLib/0003-ArmPlatformPkg-EblCmdLib-Add-dumpfdt-EBL-command.patch +++ /dev/null @@ -1,300 +0,0 @@ -From 82540f3a4b280133f2d1a58cb8baba01c1f09690 Mon Sep 17 00:00:00 2001 -From: Olivier Martin <olivier.martin@arm.com> -Date: Thu, 16 Feb 2012 15:56:40 +0000 -Subject: [PATCH 3/3] ArmPlatformPkg/EblCmdLib: Add 'dumpfdt' EBL command - -This command dumps the FDT blob pointed by the Device Path defined in the -command argument or used the Platform specifc FDT defined by its Device Path -in the UEFI Variable 'Fdt' or the PcdFdtDevicePath PCD. ---- - ArmPlatformPkg/Library/EblCmdLib/EblCmdFdt.c | 206 ++++++++++++++++++++++++ - ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c | 12 ++ - ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf | 6 + - 3 files changed, 224 insertions(+), 0 deletions(-) - create mode 100755 ArmPlatformPkg/Library/EblCmdLib/EblCmdFdt.c - mode change 100644 => 100755 ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c - mode change 100644 => 100755 ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf - -diff --git a/ArmPlatformPkg/Library/EblCmdLib/EblCmdFdt.c b/ArmPlatformPkg/Library/EblCmdLib/EblCmdFdt.c -new file mode 100755 -index 0000000..3c5eb8e ---- /dev/null -+++ b/ArmPlatformPkg/Library/EblCmdLib/EblCmdFdt.c -@@ -0,0 +1,206 @@ -+#include <Base.h> -+#include <Uefi.h> -+#include <Library/MemoryAllocationLib.h> -+#include <Library/BdsLib.h> -+#include <Library/DebugLib.h> -+#include <Library/PcdLib.h> -+#include <Library/PrintLib.h> -+#include <Library/UefiLib.h> -+#include <Library/UefiApplicationEntryPoint.h> -+#include <Library/UefiBootServicesTableLib.h> -+#include <Library/UefiRuntimeServicesTableLib.h> -+ -+#include <Protocol/DevicePathFromText.h> -+ -+#include <Guid/GlobalVariable.h> -+ -+#include <libfdt.h> -+ -+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) -+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) -+#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) -+ -+STATIC -+UINTN -+IsPrintableString ( -+ IN CONST VOID* data, -+ IN UINTN len -+ ) -+{ -+ CONST CHAR8 *s = data; -+ CONST CHAR8 *ss; -+ -+ /* zero length is not */ -+ if (len == 0) { -+ return 0; -+ } -+ -+ /* must terminate with zero */ -+ if (s[len - 1] != '\0') { -+ return 0; -+ } -+ -+ ss = s; -+ while (*s/* && isprint(*s)*/) { -+ s++; -+ } -+ -+ /* not zero, or not done yet */ -+ if (*s != '\0' || (s + 1 - ss) < len) { -+ return 0; -+ } -+ -+ return 1; -+} -+ -+STATIC -+VOID -+PrintData ( -+ IN CONST CHAR8* data, -+ IN UINTN len -+ ) -+{ -+ UINTN i; -+ CONST CHAR8 *p = data; -+ -+ /* no data, don't print */ -+ if (len == 0) -+ return; -+ -+ if (IsPrintableString (data, len)) { -+ Print(L" = \"%a\"", (const char *)data); -+ } else if ((len % 4) == 0) { -+ Print(L" = <"); -+ for (i = 0; i < len; i += 4) { -+ Print(L"0x%08x%a", fdt32_to_cpu(GET_CELL(p)),i < (len - 4) ? " " : ""); -+ } -+ Print(L">"); -+ } else { -+ Print(L" = ["); -+ for (i = 0; i < len; i++) -+ Print(L"%02x%a", *p++, i < len - 1 ? " " : ""); -+ Print(L"]"); -+ } -+} -+ -+VOID -+DumpFdt ( -+ IN VOID* FdtBlob -+ ) -+{ -+ struct fdt_header *bph; -+ UINT32 off_dt; -+ UINT32 off_str; -+ CONST CHAR8* p_struct; -+ CONST CHAR8* p_strings; -+ CONST CHAR8* p; -+ CONST CHAR8* s; -+ CONST CHAR8* t; -+ UINT32 tag; -+ UINTN sz; -+ UINTN depth; -+ UINTN shift; -+ UINT32 version; -+ -+ depth = 0; -+ shift = 4; -+ -+ bph = FdtBlob; -+ off_dt = fdt32_to_cpu(bph->off_dt_struct); -+ off_str = fdt32_to_cpu(bph->off_dt_strings); -+ p_struct = (CONST CHAR8*)FdtBlob + off_dt; -+ p_strings = (CONST CHAR8*)FdtBlob + off_str; -+ version = fdt32_to_cpu(bph->version); -+ -+ p = p_struct; -+ while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { -+ -+ /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ -+ -+ if (tag == FDT_BEGIN_NODE) { -+ s = p; -+ p = PALIGN(p + strlen(s) + 1, 4); -+ -+ if (*s == '\0') -+ s = "/"; -+ -+ Print(L"%*s%a {\n", depth * shift, L" ", s); -+ -+ depth++; -+ continue; -+ } -+ -+ if (tag == FDT_END_NODE) { -+ depth--; -+ -+ Print(L"%*s};\n", depth * shift, L" "); -+ continue; -+ } -+ -+ if (tag == FDT_NOP) { -+ Print(L"%*s// [NOP]\n", depth * shift, L" "); -+ continue; -+ } -+ -+ if (tag != FDT_PROP) { -+ Print(L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag); -+ break; -+ } -+ sz = fdt32_to_cpu(GET_CELL(p)); -+ s = p_strings + fdt32_to_cpu(GET_CELL(p)); -+ if (version < 16 && sz >= 8) -+ p = PALIGN(p, 8); -+ t = p; -+ -+ p = PALIGN(p + sz, 4); -+ -+ Print(L"%*s%a", depth * shift, L" ", s); -+ PrintData(t, sz); -+ Print(L";\n"); -+ } -+} -+ -+EFI_STATUS -+EblDumpFdt ( -+ IN UINTN Argc, -+ IN CHAR8 **Argv -+ ) -+{ -+ EFI_STATUS Status; -+ EFI_DEVICE_PATH* FdtDevicePath; -+ VOID* FdtBlob; -+ UINTN FdtBlobSize; -+ UINTN Ret; -+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; -+ -+ // If no FDT file is passed to the argument then get the one from the platform -+ if (Argc < 2) { -+ Status = GetEnvironmentVariable (L"Fdt",NULL,NULL,(VOID**)&FdtDevicePath); -+ if (Status == EFI_NOT_FOUND) { -+ // No set yet, get the Default Device Path -+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); -+ ASSERT_EFI_ERROR(Status); -+ FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath)); -+ } -+ } else { -+ return EFI_NOT_FOUND; -+ } -+ -+ Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, (EFI_PHYSICAL_ADDRESS*)&FdtBlob, &FdtBlobSize); -+ if (EFI_ERROR(Status)) { -+ Print (L"ERROR: Did not find the Fdt Blob.\n"); -+ return Status; -+ } -+ -+ Ret = fdt_check_header(FdtBlob); -+ if (Ret != 0) { -+ Print (L"ERROR: Device Tree header not valid (err:%d)\n",Ret); -+ return Status; -+ } -+ -+ DumpFdt (FdtBlob); -+ -+ FreePool (FdtDevicePath); -+ -+ return EFI_SUCCESS; -+} -diff --git a/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c -old mode 100644 -new mode 100755 -index b75dbfb..327a794 ---- a/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c -+++ b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.c -@@ -42,6 +42,12 @@ EblDumpMmu ( - IN UINTN Argc,
- IN CHAR8 **Argv
- );
-+
-+EFI_STATUS
-+EblDumpFdt (
-+ IN UINTN Argc,
-+ IN CHAR8 **Argv
-+ );
-
- /**
- Simple arm disassembler via a library
-@@ -416,6 +422,12 @@ GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mLibCmdTemplate[] = - " list all the Device Paths",
- NULL,
- EblDevicePaths
-+ },
-+ {
-+ "dumpfdt",
-+ " dump the current fdt or the one defined in the arguments",
-+ NULL,
-+ EblDumpFdt
- }
- };
-
-diff --git a/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf -old mode 100644 -new mode 100755 -index 0eb71a0..9f84c07 ---- a/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf -+++ b/ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf -@@ -30,12 +30,14 @@ - [Sources.common]
- EblCmdLib.c
- EblCmdMmu.c
-+ EblCmdFdt.c
-
- [Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- ArmPkg/ArmPkg.dec
-+ ArmPlatformPkg/ArmPlatformPkg.dec
-
- [LibraryClasses]
- BaseLib
-@@ -45,6 +47,7 @@ - PerformanceLib
- TimerLib
- BdsLib
-+ FdtLib
-
- [Protocols]
- gEfiDebugSupportProtocolGuid
-@@ -53,3 +56,6 @@ -
- [Guids]
- gEfiDebugImageInfoTableGuid
-+
-+[Pcd]
-+ gArmPlatformTokenSpaceGuid.PcdFdtDevicePath
--- -1.7.0.4 - diff --git a/EmbeddedPkg/Library/FdtLib/FdtLib.inf b/EmbeddedPkg/Library/FdtLib/FdtLib.inf new file mode 100644 index 0000000000..aee99bd997 --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/FdtLib.inf @@ -0,0 +1,38 @@ +#/* @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.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FdtLib
+ FILE_GUID = 6b2478c0-be23-11e0-a28c-0002a5d5c51b
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FdtLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = ARM
+#
+
+[Sources]
+ fdt_ro.c
+ fdt_rw.c
+ fdt_strerror.c
+ fdt_sw.c
+ fdt_wip.c
+ fdt.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
diff --git a/EmbeddedPkg/Library/FdtLib/Makefile.libfdt b/EmbeddedPkg/Library/FdtLib/Makefile.libfdt new file mode 100644 index 0000000000..91126c000a --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/Makefile.libfdt @@ -0,0 +1,10 @@ +# Makefile.libfdt +# +# This is not a complete Makefile of itself. Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c +LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/EmbeddedPkg/Library/FdtLib/TODO b/EmbeddedPkg/Library/FdtLib/TODO new file mode 100644 index 0000000000..288437e394 --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/TODO @@ -0,0 +1,3 @@ +- Tree traversal functions +- Graft function +- Complete libfdt.h documenting comments diff --git a/EmbeddedPkg/Library/FdtLib/fdt.c b/EmbeddedPkg/Library/FdtLib/fdt.c new file mode 100644 index 0000000000..e56833ae9b --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt.c @@ -0,0 +1,222 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_check_header(const void *fdt) +{ + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (fdt_size_dt_struct(fdt) == 0) + return -FDT_ERR_BADSTATE; + } else { + return -FDT_ERR_BADMAGIC; + } + + return 0; +} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) +{ + const char *p; + + if (fdt_version(fdt) >= 0x11) + if (((offset + len) < offset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; + + p = _fdt_offset_ptr(fdt, offset); + + if (p + len < p) + return NULL; + return p; +} + +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) +{ + const uint32_t *tagp, *lenp; + uint32_t tag; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); + if (!tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu(*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) { + case FDT_BEGIN_NODE: + /* skip name */ + do { + p = fdt_offset_ptr(fdt, offset++, 1); + } while (p && (*p != '\0')); + if (!p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN(offset); + return tag; +} + +int _fdt_check_node_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int _fdt_check_prop_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) + return nextoffset; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; +} + +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) +{ + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp(p, s, len) == 0) + return p; + return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_totalsize(fdt) > bufsize) + return -FDT_ERR_NOSPACE; + + memmove(buf, fdt, fdt_totalsize(fdt)); + return 0; +} diff --git a/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c b/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c new file mode 100644 index 0000000000..f72d13b1d1 --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c @@ -0,0 +1,84 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} + diff --git a/EmbeddedPkg/Library/FdtLib/fdt_ro.c b/EmbeddedPkg/Library/FdtLib/fdt_ro.c new file mode 100644 index 0000000000..95fdbeadd4 --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt_ro.c @@ -0,0 +1,575 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_nodename_eq(const void *fdt, int offset, + const char *s, int len) +{ + const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); + + if (! p) + /* short match */ + return 0; + + if (memcmp(p, s, len) != 0) + return 0; + + if (p[len] == '\0') + return 1; + else if (!memchr(s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; +} + +const char *fdt_string(const void *fdt, int stroffset) +{ + return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; +} + +static int _fdt_string_eq(const void *fdt, int stroffset, + const char *s, int len) +{ + const char *p = fdt_string(fdt, stroffset); + + return (strlen(p) == len) && (memcmp(p, s, len) == 0); +} + +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ + FDT_CHECK_HEADER(fdt); + *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); + *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); + return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ + int i = 0; + + while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) + i++; + return i; +} + +static int _nextprop(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset_namelen(const void *fdt, int offset, + const char *name, int namelen) +{ + int depth; + + FDT_CHECK_HEADER(fdt); + + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && _fdt_nodename_eq(fdt, offset, name, namelen)) + return offset; + + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, + const char *name) +{ + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset(const void *fdt, const char *path) +{ + const char *end = path + strlen(path); + const char *p = path; + int offset = 0; + + FDT_CHECK_HEADER(fdt); + + /* see if we have an alias */ + if (*path != '/') { + const char *q = strchr(path, '/'); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } + + while (*p) { + const char *q; + + while (*p == '/') + p++; + if (! *p) + return offset; + q = strchr(p, '/'); + if (! q) + q = end; + + offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); + if (offset < 0) + return offset; + + p = q; + } + + return offset; +} + +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ + const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); + int err; + + if (((err = fdt_check_header(fdt)) != 0) + || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) + goto fail; + + if (len) + *len = strlen(nh->name); + + return nh->name; + + fail: + if (len) + *len = err; + return NULL; +} + +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) +{ + int err; + const struct fdt_property *prop; + + if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } + + prop = _fdt_offset_ptr(fdt, offset); + + if (lenp) + *lenp = fdt32_to_cpu(prop->len); + + return prop; +} + +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) { + offset = -FDT_ERR_INTERNAL; + break; + } + if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), + name, namelen)) + return prop; + } + + if (lenp) + *lenp = offset; + return NULL; +} + +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); + if (! prop) + return NULL; + + return prop->data; +} + +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ + const uint32_t *php; + int len; + + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } + + return fdt32_to_cpu(*php); +} + +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) +{ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_CHECK_HEADER(fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth) +{ + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; + + FDT_CHECK_HEADER(fdt); + + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; + + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; + + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ + int nodedepth; + int err; + + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); + if (err) + return (err < 0) ? err : -FDT_ERR_INTERNAL; + return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ + int nodedepth = fdt_node_depth(fdt, nodeoffset); + + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset(fdt, nodeoffset, + nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen) +{ + int offset; + const void *val; + int len; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) +{ + int offset; + + if ((phandle == 0) || (phandle == (uint32_t)-1)) + return -FDT_ERR_BADPHANDLE; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +static int _fdt_stringlist_contains(const char *strlist, int listlen, + const char *str) +{ + int len = strlen(str); + const char *p; + + while (listlen >= len) { + if (memcmp(str, strlist, len+1) == 0) + return 1; + p = memchr(strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p-strlist) + 1; + strlist = p + 1; + } + return 0; +} + +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) +{ + const void *prop; + int len; + + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; + if (_fdt_stringlist_contains(prop, len, compatible)) + return 0; + else + return 1; +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible) +{ + int offset, err; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} diff --git a/EmbeddedPkg/Library/FdtLib/fdt_rw.c b/EmbeddedPkg/Library/FdtLib/fdt_rw.c new file mode 100644 index 0000000000..878a775a7b --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt_rw.c @@ -0,0 +1,495 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_blocks_misordered(const void *fdt, + int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + +static int _fdt_rw_check_header(void *fdt) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; + if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (fdt_version(fdt) > 17) + fdt_set_version(fdt, 17); + + return 0; +} + +#define FDT_RW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_rw_check_header(fdt)) != 0) \ + return err; \ + } + +static inline int _fdt_data_size(void *fdt) +{ + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) +{ + char *p = splicepoint; + char *end = (char *)fdt + _fdt_data_size(fdt); + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, end - p - oldlen); + return 0; +} + +static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof(*p); + int err; + err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_struct(void *fdt, void *p, + int oldlen, int newlen) +{ + int delta = newlen - oldlen; + int err; + + err = _fdt_splice(fdt, p, oldlen, newlen); + if (err) + return err; + + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_string(void *fdt, int newlen) +{ + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; + + err = _fdt_splice(fdt, p, 0, newlen); + if (err) + return err; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; + char *new; + int len = strlen(s) + 1; + int err; + + p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); + err = _fdt_splice_string(fdt, len); + if (err) + return err; + + memcpy(new, s, len); + return (new - strtab); +} + +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); + err = _fdt_splice_mem_rsv(fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ + struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); + int err; + + FDT_RW_CHECK_HEADER(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + + err = _fdt_splice_mem_rsv(fdt, re, 1, 0); + if (err) + return err; + return 0; +} + +static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int oldlen; + int err; + + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (! (*prop)) + return oldlen; + + err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)); + if (err) + return err; + + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int proplen; + int nextoffset; + int namestroff; + int err; + + if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = _fdt_find_add_string(fdt, name); + if (namestroff < 0) + return namestroff; + + *prop = _fdt_offset_ptr_w(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + + err = _fdt_splice_struct(fdt, *prop, 0, proplen); + if (err) + return err; + + (*prop)->tag = cpu_to_fdt32(FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32(namestroff); + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; + + memcpy(namep, name, newlen+1); + return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + + memcpy(prop->data, val, len); + return 0; +} + +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len, proplen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (! prop) + return len; + + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return _fdt_splice_struct(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen) +{ + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + uint32_t *endtag; + + FDT_RW_CHECK_HEADER(fdt); + + offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = _fdt_offset_ptr_w(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + + err = _fdt_splice_struct(fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); + memcpy(nh->name, name, namelen); + endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32(FDT_END_NODE); + + return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ + return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ + int endoffset; + + FDT_RW_CHECK_HEADER(fdt); + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), + endoffset - nodeoffset, 0); +} + +static void _fdt_packblocks(const char *old, char *new, + int mem_rsv_size, int struct_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); + + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); + + memmove(new + strings_off, old + fdt_off_dt_strings(old), + fdt_size_dt_strings(old)); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) +{ + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; + + FDT_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + + if (fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } + + if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + + return 0; +} + +int fdt_pack(void *fdt) +{ + int mem_rsv_size; + + FDT_RW_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_set_totalsize(fdt, _fdt_data_size(fdt)); + + return 0; +} diff --git a/EmbeddedPkg/Library/FdtLib/fdt_strerror.c b/EmbeddedPkg/Library/FdtLib/fdt_strerror.c new file mode 100644 index 0000000000..e6c3ceee8c --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt_strerror.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +struct fdt_errtabent { + const char *str; +}; + +#define FDT_ERRTABENT(val) \ + [(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), +}; +#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +const char *fdt_strerror(int errval) +{ + if (errval > 0) + return "<valid offset/length>"; + else if (errval == 0) + return "<no error>"; + else if (errval > -FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return "<unknown error>"; +} diff --git a/EmbeddedPkg/Library/FdtLib/fdt_sw.c b/EmbeddedPkg/Library/FdtLib/fdt_sw.c new file mode 100644 index 0000000000..55ebebf1eb --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt_sw.c @@ -0,0 +1,256 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_sw_check_header(void *fdt) +{ + if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + /* FIXME: should check more details about the header state */ + return 0; +} + +#define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_sw_check_header(fdt)) != 0) \ + return err; \ + } + +static void *_fdt_grab_space(void *fdt, size_t len) +{ + int offset = fdt_size_dt_struct(fdt); + int spaceleft; + + spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) + - fdt_size_dt_strings(fdt); + + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; + + fdt_set_size_dt_struct(fdt, offset + len); + return _fdt_offset_ptr_w(fdt, offset); +} + +int fdt_create(void *buf, int bufsize) +{ + void *fdt = buf; + + if (bufsize < sizeof(struct fdt_header)) + return -FDT_ERR_NOSPACE; + + memset(buf, 0, bufsize); + + fdt_set_magic(fdt, FDT_SW_MAGIC); + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_totalsize(fdt, bufsize); + + fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry))); + fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); + fdt_set_off_dt_strings(fdt, bufsize); + + return 0; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int offset; + + FDT_SW_CHECK_HEADER(fdt); + + if (fdt_size_dt_struct(fdt)) + return -FDT_ERR_BADSTATE; + + offset = fdt_off_dt_struct(fdt); + if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + + re = (struct fdt_reserve_entry *)((char *)fdt + offset); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); + + fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + + return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ + return fdt_add_reservemap_entry(fdt, 0, 0); +} + +int fdt_begin_node(void *fdt, const char *name) +{ + struct fdt_node_header *nh; + int namelen = strlen(name) + 1; + + FDT_SW_CHECK_HEADER(fdt); + + nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memcpy(nh->name, name, namelen); + return 0; +} + +int fdt_end_node(void *fdt) +{ + uint32_t *en; + + FDT_SW_CHECK_HEADER(fdt); + + en = _fdt_grab_space(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; + + *en = cpu_to_fdt32(FDT_END_NODE); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_totalsize(fdt); + const char *p; + int strtabsize = fdt_size_dt_strings(fdt); + int len = strlen(s) + 1; + int struct_top, offset; + + p = _fdt_find_string(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + + /* Add it */ + offset = -strtabsize - len; + struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + if (fdt_totalsize(fdt) + offset < struct_top) + return 0; /* no more room :( */ + + memcpy(strtab + offset, s, len); + fdt_set_size_dt_strings(fdt, strtabsize + len); + return offset; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ + struct fdt_property *prop; + int nameoff; + + FDT_SW_CHECK_HEADER(fdt); + + nameoff = _fdt_find_add_string(fdt, name); + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) + return -FDT_ERR_NOSPACE; + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); + memcpy(prop->data, val, len); + return 0; +} + +int fdt_finish(void *fdt) +{ + char *p = (char *)fdt; + uint32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_CHECK_HEADER(fdt); + + /* Add terminator */ + end = _fdt_grab_space(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); + newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = + _fdt_offset_ptr_w(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); + nameoff += fdt_size_dt_strings(fdt); + prop->nameoff = cpu_to_fdt32(nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); + fdt_set_magic(fdt, FDT_MAGIC); + return 0; +} diff --git a/EmbeddedPkg/Library/FdtLib/fdt_wip.c b/EmbeddedPkg/Library/FdtLib/fdt_wip.c new file mode 100644 index 0000000000..6025fa1fe8 --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/fdt_wip.c @@ -0,0 +1,118 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + if (! propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + + memcpy(propval, val, len); + return 0; +} + +static void _fdt_nop_region(void *start, int len) +{ + uint32_t *p; + + for (p = start; (char *)p < ((char *)start + len); p++) + *p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len; + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (! prop) + return len; + + _fdt_nop_region(prop, len + sizeof(*prop)); + + return 0; +} + +int _fdt_node_end_offset(void *fdt, int offset) +{ + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ + int endoffset; + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; +} diff --git a/EmbeddedPkg/Library/FdtLib/libfdt_internal.h b/EmbeddedPkg/Library/FdtLib/libfdt_internal.h new file mode 100644 index 0000000000..381133ba81 --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/libfdt_internal.h @@ -0,0 +1,95 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <fdt.h> + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +#define FDT_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = fdt_check_header(fdt)) != 0) \ + return err; \ + } + +int _fdt_check_node_offset(const void *fdt, int offset); +int _fdt_check_prop_offset(const void *fdt, int offset); +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset(void *fdt, int nodeoffset); + +static inline const void *_fdt_offset_ptr(const void *fdt, int offset) +{ + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *_fdt_offset_ptr_w(void *fdt, int offset) +{ + return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); +} + +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + + return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) +{ + return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); +} + +#define FDT_SW_MAGIC (~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ diff --git a/EmbeddedPkg/Library/FdtLib/version.lds b/EmbeddedPkg/Library/FdtLib/version.lds new file mode 100644 index 0000000000..3c3994e27f --- /dev/null +++ b/EmbeddedPkg/Library/FdtLib/version.lds @@ -0,0 +1,54 @@ +LIBFDT_1.2 { + global: + fdt_next_node; + fdt_check_header; + fdt_move; + fdt_string; + fdt_num_mem_rsv; + fdt_get_mem_rsv; + fdt_subnode_offset_namelen; + fdt_subnode_offset; + fdt_path_offset; + fdt_get_name; + fdt_get_property_namelen; + fdt_get_property; + fdt_getprop_namelen; + fdt_getprop; + fdt_get_phandle; + fdt_get_alias_namelen; + fdt_get_alias; + fdt_get_path; + fdt_supernode_atdepth_offset; + fdt_node_depth; + fdt_parent_offset; + fdt_node_offset_by_prop_value; + fdt_node_offset_by_phandle; + fdt_node_check_compatible; + fdt_node_offset_by_compatible; + fdt_setprop_inplace; + fdt_nop_property; + fdt_nop_node; + fdt_create; + fdt_add_reservemap_entry; + fdt_finish_reservemap; + fdt_begin_node; + fdt_property; + fdt_end_node; + fdt_finish; + fdt_open_into; + fdt_pack; + fdt_add_mem_rsv; + fdt_del_mem_rsv; + fdt_set_name; + fdt_setprop; + fdt_delprop; + fdt_add_subnode_namelen; + fdt_add_subnode; + fdt_del_node; + fdt_strerror; + fdt_offset_ptr; + fdt_next_tag; + + local: + *; +}; |