All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 5/7] add imported "FDT" module for flattened device tree operations
@ 2013-03-24 17:01 Leif Lindholm
  2013-03-30 16:53 ` Francesco Lavra
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Leif Lindholm @ 2013-03-24 17:01 UTC (permalink / raw)
  To: grub-devel

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: 0005-fdt-support.patch --]
[-- Type: application/octet-stream, Size: 116457 bytes --]

=== modified file '.bzrignore'
--- .bzrignore	2013-01-12 15:17:31 +0000
+++ .bzrignore	2013-03-24 13:24:52 +0000
@@ -174,3 +174,5 @@
 po/LINGUAS
 include/grub/gcrypt/gcrypt.h
 include/grub/gcrypt/g10lib.h
+grub-core/lib/dtc-grub
+grub-core/Makefile.libfdt.def

=== modified file 'autogen.sh'
--- autogen.sh	2013-01-12 15:14:09 +0000
+++ autogen.sh	2013-03-24 13:24:52 +0000
@@ -30,6 +30,9 @@
     ln -s generic/"$x" grub-core/lib/libgcrypt-grub/mpi/"$x"
 done
 
+echo "Importing libfdt..."
+python util/import_libfdt.py grub-core/lib/dtc/ grub-core
+
 echo "Creating Makefile.tpl..."
 python gentpl.py | sed -e '/^$/{N;/^\n$/D;}' > Makefile.tpl
 
@@ -43,7 +46,7 @@
 fi
 
 UTIL_DEFS='Makefile.util.def Makefile.utilgcry.def'
-CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def'
+CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def grub-core/Makefile.libfdt.def'
 
 for extra in contrib/*/Makefile.util.def; do
   if test -e "$extra"; then

=== modified file 'conf/Makefile.common'
--- conf/Makefile.common	2013-03-24 13:06:12 +0000
+++ conf/Makefile.common	2013-03-24 13:24:52 +0000
@@ -117,6 +117,8 @@
 CFLAGS_POSIX = -fno-builtin
 CPPFLAGS_POSIX = -I$(top_srcdir)/grub-core/lib/posix_wrap
 
+CPPFLAGS_LIBFDT = -I$(top_srcdir)/grub-core/lib/dtc-grub/libfdt $(CPPFLAGS_POSIX)
+
 CFLAGS_GCRY = -Wno-error -Wno-missing-field-initializers $(CFLAGS_POSIX)
 CPPFLAGS_GCRY = -I$(top_srcdir)/grub-core/lib/libgcrypt_wrap $(CPPFLAGS_POSIX) -D_GCRYPT_IN_LIBGCRYPT=1 -I$(top_srcdir)/include/grub/gcrypt
 

=== modified file 'conf/Makefile.extra-dist'
--- conf/Makefile.extra-dist	2012-02-28 11:58:57 +0000
+++ conf/Makefile.extra-dist	2013-03-24 13:24:52 +0000
@@ -18,6 +18,7 @@
 
 EXTRA_DIST += grub-core/Makefile.core.def
 EXTRA_DIST += grub-core/Makefile.gcry.def
+EXTRA_DIST += grub-core/Makefile.libfdt.def
 
 EXTRA_DIST += grub-core/genmoddep.awk
 EXTRA_DIST += grub-core/genmod.sh.in
@@ -27,6 +28,7 @@
 EXTRA_DIST += grub-core/genemuinitheader.sh
 
 EXTRA_DIST += grub-core/lib/libgcrypt/cipher
+EXTRA_DIST += grub-core/lib/dtc
 EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h')
 EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h')
 EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/gnulib -name '*.h')

=== modified file 'docs/grub.texi'
--- docs/grub.texi	2013-03-07 07:17:24 +0000
+++ docs/grub.texi	2013-03-24 13:24:52 +0000
@@ -3372,6 +3372,7 @@
 * cpuid::                       Check for CPU features
 * crc::                         Calculate CRC32 checksums
 * date::                        Display or set current date and time
+* devicetree::                  Load a device tree blob
 * drivemap::                    Map a drive to another
 * echo::                        Display a line of text
 * export::                      Export an environment variable
@@ -3571,6 +3572,17 @@
 @end deffn
 
 
+@node devicetree
+@subsection linux
+
+@deffn Command devicetree file
+Load a device tree blob (.dtb) from a filesystem, for later use by a Linux
+kernel. Does not perform merging with any device tree supplied by firmware,
+but rather replaces it completely.
+@ref{GNU/Linux}.
+@end deffn
+
+
 @node drivemap
 @subsection drivemap
 

=== added directory 'grub-core/lib/dtc'
=== added directory 'grub-core/lib/dtc/libfdt'
=== added file 'grub-core/lib/dtc/libfdt-grub.diff'
--- grub-core/lib/dtc/libfdt-grub.diff	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt-grub.diff	2013-03-24 14:38:08 +0000
@@ -0,0 +1,45 @@
+diff -purN libfdt.orig/fdt_rw.c libfdt/fdt_rw.c
+--- libfdt.orig/fdt_rw.c	2011-05-08 20:45:39.000000000 +0100
++++ libfdt/fdt_rw.c	2012-10-19 15:33:11.085523185 +0100
+@@ -88,9 +88,9 @@ static int _fdt_rw_check_header(void *fd
+ 
+ #define FDT_RW_CHECK_HEADER(fdt) \
+ 	{ \
+-		int err; \
+-		if ((err = _fdt_rw_check_header(fdt)) != 0) \
+-			return err; \
++		int macro_err; \
++		if ((macro_err = _fdt_rw_check_header(fdt)) != 0) \
++			return macro_err; \
+ 	}
+ 
+ static inline int
+diff -purN libfdt.orig/libfdt_env.h libfdt/libfdt_env.h
+--- libfdt.orig/libfdt_env.h	2011-05-08 20:45:39.000000000 +0100
++++ libfdt/libfdt_env.h	2012-10-19 16:13:19.051344173 +0100
+@@ -7,6 +7,9 @@
+ #include <stddef.h>
+ #include <stdint.h>
+ #include <string.h>
++#pragma GCC diagnostic ignored "-Wcast-align"
++#pragma GCC diagnostic ignored "-Wsign-compare"
++typedef grub_addr_t uintptr_t;
+ 
+ #define _B(n)	((unsigned long long)((uint8_t *)&x)[n])
+ static inline uint32_t
+diff -purN libfdt.orig/libfdt_internal.h libfdt/libfdt_internal.h
+--- libfdt.orig/libfdt_internal.h	2011-05-08 20:45:39.000000000 +0100
++++ libfdt/libfdt_internal.h	2012-10-19 15:33:11.105524731 +0100
+@@ -60,9 +60,9 @@
+ 
+ #define FDT_CHECK_HEADER(fdt) \
+ 	{ \
+-		int err; \
+-		if ((err = fdt_check_header(fdt)) != 0) \
+-			return err; \
++		int macro_err; \
++		if ((macro_err = fdt_check_header(fdt)) != 0) \
++			return macro_err; \
+ 	}
+ 
+ int _fdt_check_node_offset (const void *fdt, int offset);

=== added file 'grub-core/lib/dtc/libfdt/Makefile.libfdt'
--- grub-core/lib/dtc/libfdt/Makefile.libfdt	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/Makefile.libfdt	2013-03-24 13:24:52 +0000
@@ -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_VERSION = version.lds
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)

=== added file 'grub-core/lib/dtc/libfdt/TODO'
--- grub-core/lib/dtc/libfdt/TODO	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/TODO	2013-03-24 13:24:52 +0000
@@ -0,0 +1,3 @@
+- Tree traversal functions
+- Graft function
+- Complete libfdt.h documenting comments

=== added file 'grub-core/lib/dtc/libfdt/fdt.c'
--- grub-core/lib/dtc/libfdt/fdt.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt.c	2013-03-24 13:24:52 +0000
@@ -0,0 +1,241 @@
+/*
+ * 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;
+}

=== added file 'grub-core/lib/dtc/libfdt/fdt.h'
--- grub-core/lib/dtc/libfdt/fdt.h	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt.h	2013-03-24 13:24:52 +0000
@@ -0,0 +1,64 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header
+{
+  uint32_t magic;		/* magic word FDT_MAGIC */
+  uint32_t totalsize;		/* total size of DT block */
+  uint32_t off_dt_struct;	/* offset to structure */
+  uint32_t off_dt_strings;	/* offset to strings */
+  uint32_t off_mem_rsvmap;	/* offset to memory reserve map */
+  uint32_t version;		/* format version */
+  uint32_t last_comp_version;	/* last compatible version */
+
+  /* version 2 fields below */
+  uint32_t boot_cpuid_phys;	/* Which physical CPU id we're
+				   booting on */
+  /* version 3 fields below */
+  uint32_t size_dt_strings;	/* size of the strings block */
+
+  /* version 17 fields below */
+  uint32_t size_dt_struct;	/* size of the structure block */
+};
+
+struct fdt_reserve_entry
+{
+  uint64_t address;
+  uint64_t size;
+};
+
+struct fdt_node_header
+{
+  uint32_t tag;
+  char name[0];
+};
+
+struct fdt_property
+{
+  uint32_t tag;
+  uint32_t len;
+  uint32_t nameoff;
+  char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE	0x1	/* Start node: full name */
+#define FDT_END_NODE	0x2	/* End node */
+#define FDT_PROP	0x3	/* Property: name off,
+				   size, content */
+#define FDT_NOP		0x4	/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(uint32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */

=== added file 'grub-core/lib/dtc/libfdt/fdt_ro.c'
--- grub-core/lib/dtc/libfdt/fdt_ro.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt_ro.c	2013-03-24 13:24:52 +0000
@@ -0,0 +1,608 @@
+/*
+ * 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;
+
+      if (!(prop = fdt_get_property_by_offset (fdt, offset, lenp)))
+	{
+	  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 == -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() */
+}

=== added file 'grub-core/lib/dtc/libfdt/fdt_rw.c'
--- grub-core/lib/dtc/libfdt/fdt_rw.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt_rw.c	2013-03-24 13:24:52 +0000
@@ -0,0 +1,490 @@
+/*
+ * 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;
+
+  if ((err = _fdt_splice (fdt, p, oldlen, newlen)))
+    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;
+
+  if ((err = _fdt_splice (fdt, p, 0, newlen)))
+    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;
+
+  if ((err = _fdt_splice_struct (fdt, (*prop)->data, FDT_TAGALIGN (oldlen),
+				 FDT_TAGALIGN (len))))
+    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_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;
+}

=== added file 'grub-core/lib/dtc/libfdt/fdt_strerror.c'
--- grub-core/lib/dtc/libfdt/fdt_strerror.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt_strerror.c	2013-03-24 13:24:52 +0000
@@ -0,0 +1,100 @@
+/*
+ * 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>";
+}

=== added file 'grub-core/lib/dtc/libfdt/fdt_sw.c'
--- grub-core/lib/dtc/libfdt/fdt_sw.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt_sw.c	2013-03-24 13:24:52 +0000
@@ -0,0 +1,267 @@
+/*
+ * 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;
+}

=== added file 'grub-core/lib/dtc/libfdt/fdt_wip.c'
--- grub-core/lib/dtc/libfdt/fdt_wip.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/fdt_wip.c	2013-03-24 13:24:52 +0000
@@ -0,0 +1,123 @@
+/*
+ * 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;
+}

=== added file 'grub-core/lib/dtc/libfdt/libfdt.h'
--- grub-core/lib/dtc/libfdt/libfdt.h	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/libfdt.h	2013-03-24 13:24:52 +0000
@@ -0,0 +1,1239 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_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 <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attemped to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+	 * value.  phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+#define FDT_ERR_MAX		13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+const void *fdt_offset_ptr (const void *fdt, int offset,
+			    unsigned int checklen);
+static inline void *
+fdt_offset_ptr_w (void *fdt, int offset, int checklen)
+{
+  return (void *) (uintptr_t) fdt_offset_ptr (fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag (const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node (const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = (struct fdt_header*)fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+__fdt_set_hdr (magic);
+__fdt_set_hdr (totalsize);
+__fdt_set_hdr (off_dt_struct);
+__fdt_set_hdr (off_dt_strings);
+__fdt_set_hdr (off_mem_rsvmap);
+__fdt_set_hdr (version);
+__fdt_set_hdr (last_comp_version);
+__fdt_set_hdr (boot_cpuid_phys);
+__fdt_set_hdr (size_dt_strings);
+__fdt_set_hdr (size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header (const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move (const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string (const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv (const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv (const void *fdt, int n, uint64_t * address,
+		     uint64_t * size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen (const void *fdt, int parentoffset,
+				const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset (const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset (const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name (const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ *	structure block offset of the property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested node has no properties
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset (const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset.  This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ *	structure block offset of the next property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the given property is the last in its node
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset (const void *fdt, int offset);
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset.  If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset (const void *fdt,
+						       int offset, int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property_namelen(), but only examine the first
+ * namelen characters of name for matching the property name.
+ */
+const struct fdt_property *fdt_get_property_namelen (const void *fdt,
+						     int nodeoffset,
+						     const char *name,
+						     int namelen, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property (const void *fdt, int nodeoffset,
+					     const char *name, int *lenp);
+static inline struct fdt_property *
+fdt_get_property_w (void *fdt, int nodeoffset, const char *name, int *lenp)
+{
+  return (struct fdt_property *) (uintptr_t)
+    fdt_get_property (fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @ffset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value).  If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.  If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *		if namep is non-NULL *namep contiains a pointer to the property
+ *		name.
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop_by_offset (const void *fdt, int offset,
+				   const char **namep, int *lenp);
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const void *fdt_getprop_namelen (const void *fdt, int nodeoffset,
+				 const char *name, int namelen, int *lenp);
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop (const void *fdt, int nodeoffset,
+			 const char *name, int *lenp);
+static inline void *
+fdt_getprop_w (void *fdt, int nodeoffset, const char *name, int *lenp)
+{
+  return (void *) (uintptr_t) fdt_getprop (fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle (const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+const char *fdt_get_alias_namelen (const void *fdt,
+				   const char *name, int namelen);
+
+/**
+ * fdt_get_alias - retreive the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias.  That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ *	a pointer to the expansion of the alias named 'name', of it exists
+ *	NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias (const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path (const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset (const void *fdt, int nodeoffset,
+				  int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth (const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	structure block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset (const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value (const void *fdt, int startoffset,
+				   const char *propname,
+				   const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle (const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible (const void *fdt, int nodeoffset,
+			       const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible (const void *fdt, int startoffset,
+				   const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace (void *fdt, int nodeoffset, const char *name,
+			 const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary.  This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+  *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int
+fdt_setprop_inplace_cell (void *fdt, int nodeoffset,
+			  const char *name, uint32_t val)
+{
+  val = cpu_to_fdt32 (val);
+  return fdt_setprop_inplace (fdt, nodeoffset, name, &val, sizeof (val));
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property (void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node (void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create (void *buf, int bufsize);
+int fdt_add_reservemap_entry (void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap (void *fdt);
+int fdt_begin_node (void *fdt, const char *name);
+int fdt_property (void *fdt, const char *name, const void *val, int len);
+static inline int
+fdt_property_cell (void *fdt, const char *name, uint32_t val)
+{
+  val = cpu_to_fdt32 (val);
+  return fdt_property (fdt, name, &val, sizeof (val));
+}
+
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node (void *fdt);
+int fdt_finish (void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_open_into (const void *fdt, void *buf, int bufsize);
+int fdt_pack (void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv (void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv (void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name (void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop (void *fdt, int nodeoffset, const char *name,
+		 const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int
+fdt_setprop_cell (void *fdt, int nodeoffset, const char *name, uint32_t val)
+{
+  val = cpu_to_fdt32 (val);
+  return fdt_setprop (fdt, nodeoffset, name, &val, sizeof (val));
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop (void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen (void *fdt, int parentoffset,
+			     const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode (void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node (void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror (int errval);
+
+#endif /* _LIBFDT_H */

=== added file 'grub-core/lib/dtc/libfdt/libfdt_env.h'
--- grub-core/lib/dtc/libfdt/libfdt_env.h	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/libfdt_env.h	2013-03-24 13:24:52 +0000
@@ -0,0 +1,27 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#define _B(n)	((unsigned long long)((uint8_t *)&x)[n])
+static inline uint32_t
+fdt32_to_cpu (uint32_t x)
+{
+  return (_B (0) << 24) | (_B (1) << 16) | (_B (2) << 8) | _B (3);
+}
+
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t
+fdt64_to_cpu (uint64_t x)
+{
+  return (_B (0) << 56) | (_B (1) << 48) | (_B (2) << 40) | (_B (3) << 32)
+    | (_B (4) << 24) | (_B (5) << 16) | (_B (6) << 8) | _B (7);
+}
+
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+#endif /* _LIBFDT_ENV_H */

=== added file 'grub-core/lib/dtc/libfdt/libfdt_internal.h'
--- grub-core/lib/dtc/libfdt/libfdt_internal.h	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/libfdt_internal.h	2013-03-24 13:24:52 +0000
@@ -0,0 +1,100 @@
+#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 */

=== added file 'grub-core/lib/dtc/libfdt/version.lds'
--- grub-core/lib/dtc/libfdt/version.lds	1970-01-01 00:00:00 +0000
+++ grub-core/lib/dtc/libfdt/version.lds	2013-03-24 13:24:52 +0000
@@ -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:
+		*;
+};

=== added file 'util/import_libfdt.py'
--- util/import_libfdt.py	1970-01-01 00:00:00 +0000
+++ util/import_libfdt.py	2013-03-24 13:24:52 +0000
@@ -0,0 +1,103 @@
+#*
+#*  GRUB  --  GRand Unified Bootloader
+#*  Copyright (C) 2013  Free Software Foundation, Inc.
+#*
+#*  GRUB 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 3 of the License, or
+#*  (at your option) any later version.
+#*
+#*  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+#*
+
+import re
+import sys
+import os
+import codecs
+import datetime
+
+if len (sys.argv) < 3:
+    print ("Usage: %s SOURCE DESTINATION" % sys.argv[0])
+    exit (0)
+dtcdir = sys.argv[1]
+indir = os.path.join (dtcdir, "libfdt/")
+outdir = os.path.join (sys.argv[2], "lib/dtc-grub/libfdt/")
+try:
+    os.makedirs (outdir)
+except:
+    print ("WARNING: %s already exists" % outdir)
+
+conf = codecs.open (os.path.join ("grub-core/", "Makefile.libfdt.def"), "w", "utf-8")
+conf.write ("AutoGen definitions Makefile.tpl;\n\n")
+conf.write ("module = {\n")
+conf.write ("  name = fdt;\n")
+conf.write ("  common = lib/dtc-grub/libfdt/fdt.c;\n")
+conf.write ("  common = lib/dtc-grub/libfdt/fdt_ro.c;\n")
+conf.write ("  common = lib/dtc-grub/libfdt/fdt_rw.c;\n")
+conf.write ("  common = lib/dtc-grub/libfdt/fdt_strerror.c;\n")
+conf.write ("  common = lib/dtc-grub/libfdt/fdt_sw.c;\n")
+conf.write ("  common = lib/dtc-grub/libfdt/fdt_wip.c;\n")
+conf.write ("  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_LIBFDT)';\n")
+conf.write ("\n")
+conf.write ("  enable = fdt;\n")
+conf.write ("};\n")
+
+conf.close ();
+
+
+libfdt_files = sorted (os.listdir (indir))
+chlog = ""
+
+for libfdt_file in libfdt_files:
+    infile = os.path.join (indir, (libfdt_file))
+    outfile = os.path.join (outdir, (libfdt_file))
+
+    if not re.match (".*\.[ch]$", libfdt_file):
+        chlog = "%s	* %s: Removed\n" % (chlog, libfdt_file)
+        continue
+
+#    print ("file: %s, infile: %s, outfile: %s" % (libfdt_file, infile, outfile))
+
+    f = codecs.open (infile, "r", "utf-8")
+    fw = codecs.open (outfile, "w", "utf-8")
+
+    lineno = 1
+
+    fw.write ("/* This file was automatically imported with \n")
+    fw.write ("   import_libfdt.py. Please don't modify it */\n")
+    fw.write ("#include <grub/dl.h>\n")
+
+    # libfdt is dual-licensed: BSD or GPLv2+
+    if re.match (".*\.c$", libfdt_file):
+        fw.write ("GRUB_MOD_LICENSE (\"GPLv2+\");\n")
+
+    lines = f.readlines()
+
+    for line in lines:
+        fw.write (line)
+        
+    f.close ()
+    fw.close ()
+
+patchfile = os.path.join (dtcdir, "libfdt-grub.diff")
+#print "Patchfile: %s\n" % patchfile
+ret = os.system("patch -d %s -p1 < %s" % (outdir, patchfile))
+if ret:
+    chlog = "%s	* Applied Grub build patch\n" % chlog
+
+
+dt = datetime.date.today ()
+fw = codecs.open (os.path.join (outdir, "ImportLog"), "w", "utf-8")
+fw.write ("%04d-%02d-%02d  Automatic import tool\n" % \
+          (dt.year,dt.month, dt.day))
+fw.write ("\n")
+fw.write ("	Imported libfdt to GRUB\n")
+fw.write ("\n")
+fw.write (chlog)
+fw.close ()


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-03-24 17:01 [PATCH 5/7] add imported "FDT" module for flattened device tree operations Leif Lindholm
@ 2013-03-30 16:53 ` Francesco Lavra
  2013-04-01  2:16 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-04-02 20:39 ` Phillip Susi
  2 siblings, 0 replies; 14+ messages in thread
From: Francesco Lavra @ 2013-03-30 16:53 UTC (permalink / raw)
  To: grub-devel

On 03/24/2013 06:01 PM, Leif Lindholm wrote:
> === modified file 'docs/grub.texi'
> --- docs/grub.texi	2013-03-07 07:17:24 +0000
> +++ docs/grub.texi	2013-03-24 13:24:52 +0000
> @@ -3372,6 +3372,7 @@
>  * cpuid::                       Check for CPU features
>  * crc::                         Calculate CRC32 checksums
>  * date::                        Display or set current date and time
> +* devicetree::                  Load a device tree blob
>  * drivemap::                    Map a drive to another
>  * echo::                        Display a line of text
>  * export::                      Export an environment variable
> @@ -3571,6 +3572,17 @@
>  @end deffn
>  
>  
> +@node devicetree
> +@subsection linux
> +
> +@deffn Command devicetree file
> +Load a device tree blob (.dtb) from a filesystem, for later use by a Linux
> +kernel. Does not perform merging with any device tree supplied by firmware,
> +but rather replaces it completely.
> +@ref{GNU/Linux}.
> +@end deffn

It should be mentioned that this command is only available on ARM systems.

--
Francesco


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-03-24 17:01 [PATCH 5/7] add imported "FDT" module for flattened device tree operations Leif Lindholm
  2013-03-30 16:53 ` Francesco Lavra
@ 2013-04-01  2:16 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-04-01 16:42   ` Francesco Lavra
  2013-04-02 20:39 ` Phillip Susi
  2 siblings, 1 reply; 14+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-04-01  2:16 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Could you put the library itself into a separate tar rather than patch?


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 294 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-01  2:16 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-04-01 16:42   ` Francesco Lavra
  2013-04-07 21:28     ` Francesco Lavra
                       ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Francesco Lavra @ 2013-04-01 16:42 UTC (permalink / raw)
  To: grub-devel; +Cc: leif.lindholm

[-- Attachment #1: Type: text/plain, Size: 851 bytes --]

On 04/01/2013 04:16 AM, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> Could you put the library itself into a separate tar rather than patch?

I recall you saying a few months ago that you'd prefer rather without
libfdt. In fact, libfdt contains much more than what is needed by GRUB.
I rewrote the FDT-related functions needed by GRUB (using GRUB's naming
convention) and put them in the standalone files grub-core/lib/fdt.c and
include/grub/fdt.h. The .c file would need to be included in the linux
loader module. I also changed loader/arm/linux.c to use the new functions.
Attached are the needed files; the loader code already contains the
changes which I proposed in my review of Leif's patch, but supports EFI
only, not U-Boot. Also, my code is not completely tested yet, I just
wanted to send it out to get your feedback.

Regards,
Francesco

[-- Attachment #2: fdt.c --]
[-- Type: text/x-csrc, Size: 13399 bytes --]

/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2013  Free Software Foundation, Inc.
 *
 *  GRUB 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/fdt.h>
#include <grub/misc.h>
#include <grub/mm.h>

#define FDT_SUPPORTED_VERSION	17

#define FDT_BEGIN_NODE	0x00000001
#define FDT_END_NODE	0x00000002
#define FDT_PROP	0x00000003
#define FDT_NOP		0x00000004
#define FDT_END		0x00000009

#define struct_end(fdt)	\
	((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)	\
	 + grub_fdt_get_size_dt_struct(fdt))

/* Size needed by a node entry: 2 tokens (FDT_BEGIN_NODE and FDT_END_NODE), plus
   the NULL-terminated string containing the name, plus padding if needed. */
#define node_entry_size(node_name)	\
	(2 * sizeof(grub_uint32_t)	\
	+ ALIGN_UP (grub_strlen (name) + 1, sizeof(grub_uint32_t)))

/* Size needed by a property entry: 1 token (FDT_PROPERTY), plus len and nameoff
   fields, plus the property value, plus padding if needed. */
#define prop_entry_size(prop_len)	\
	(3 * sizeof(grub_uint32_t) + ALIGN_UP(prop_len, sizeof(grub_uint32_t)))

static grub_uint32_t *get_next_node (const void *fdt, char *node_name)
{
  grub_uint32_t *end = (void *) struct_end (fdt);
  grub_uint32_t *token;

  if (node_name >= (char *) end)
    return NULL;
  while (*node_name)
  {
    if (++node_name >= (char *) end)
  	  return NULL;
  }
  token = (grub_uint32_t *) ALIGN_UP ((grub_addr_t) node_name, 4);
  while (token < end)
  {
    switch (grub_be_to_cpu32(*token))
    {
      case FDT_BEGIN_NODE:
        token = get_next_node (fdt, (char *) (token + 1));
        if (!token)
          return NULL;
        break;
      case FDT_END_NODE:
        token++;
        if (token >= end)
          return NULL;
        return token;
      case FDT_PROP:
        /* Skip property token and following data (len, nameoff and property
           value). */
        token += 3 + grub_be_to_cpu32 (*(token + 1));
        break;
      case FDT_NOP:
        token++;
        break;
      default:
        return NULL;
    }
  }
  return NULL;
}

static int get_mem_rsvmap_size (const void *fdt)
{
  int size = 0;
  grub_uint64_t *ptr = (void *) ((grub_addr_t) fdt
                                 + grub_fdt_get_off_mem_rsvmap (fdt));

  do
  {
    size += 2 * sizeof(*ptr);
    if (!*ptr && !*(ptr + 1))
      return size;
    ptr += 2;
  } while ((grub_addr_t) ptr <= (grub_addr_t) fdt + grub_fdt_get_totalsize (fdt)
                                  - 2 * sizeof(grub_uint64_t));
  return -1;
}

static grub_uint32_t get_free_space (void *fdt)
{
  int mem_rsvmap_size = get_mem_rsvmap_size (fdt);

  if (mem_rsvmap_size < 0)
    /* invalid memory reservation block */
    return 0;
  return (grub_fdt_get_totalsize (fdt) - sizeof(grub_fdt_header_t)
          - mem_rsvmap_size - grub_fdt_get_size_dt_strings (fdt)
          - grub_fdt_get_size_dt_struct (fdt));
}

static int add_subnode (void *fdt, int parentoffset, const char *name)
{
  grub_uint32_t *begin = (void *) ((grub_addr_t) fdt
                                   + grub_fdt_get_off_dt_struct(fdt)
                                   + parentoffset);
  grub_uint32_t *end = (void *) struct_end (fdt);
  unsigned int entry_size = node_entry_size (name);
  grub_uint32_t *token = begin;

  /* Insert the new subnode just after the properties of the parent node (if
     any).*/
  while (1)
  {
    if (token >= end)
      return -1;
    switch (grub_be_to_cpu32(*token))
    {
      case FDT_PROP:
        /* Skip len and nameoff. */
        token += 2;
        break;
      case FDT_BEGIN_NODE:
      case FDT_END_NODE:
        goto insert;
      case FDT_NOP:
        break;
      default:
        /* invalid token */
        return -1;
    }
    token++;
  }
insert:
  grub_memmove (token + entry_size, token,
                (grub_addr_t) end - (grub_addr_t) token);
  *token = grub_cpu_to_be32(FDT_BEGIN_NODE);
  token[entry_size / sizeof(*token) - 2] = 0;	/* padding bytes */
  grub_strcpy((char *) (token + 1), name);
  token += entry_size / sizeof(*token) - 1;
  *token = grub_cpu_to_be32(FDT_END_NODE);
  return ((grub_addr_t) token - (grub_addr_t) fdt
          - grub_fdt_get_off_dt_struct(fdt));
}

/* Rearrange FDT blocks in the canonical order: first the memory reservation
   block (just after the FDT header), then the structure block and finally the
   strings block. No free space is left between the first and the second block,
   while the space between the second and the third block is given by the
   clearance argument. */
static int rearrange_blocks (void *fdt, unsigned int clearance)
{
  grub_uint32_t off_mem_rsvmap = ALIGN_UP(sizeof(grub_fdt_header_t), 8);
  grub_uint32_t off_dt_struct = off_mem_rsvmap + get_mem_rsvmap_size (fdt);
  grub_uint32_t off_dt_strings = off_dt_struct
                                 + grub_fdt_get_size_dt_struct (fdt)
                                 + clearance;
  grub_uint8_t *fdt_ptr = fdt;
  grub_uint8_t *tmp_fdt;

  if ((grub_fdt_get_off_mem_rsvmap (fdt) == off_mem_rsvmap)
      && (grub_fdt_get_off_dt_struct (fdt) == off_dt_struct))
  {
    /* No need to allocate memory for a temporary FDT, just move the strings
       block if needed. */
    if (grub_fdt_get_off_dt_strings (fdt) != off_dt_strings)
      grub_memmove(fdt_ptr + off_dt_strings,
                   fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
                   grub_fdt_get_size_dt_strings (fdt));
    return 0;
  }
  tmp_fdt = grub_malloc (grub_fdt_get_totalsize (fdt));
  if (!tmp_fdt)
    return -1;
  grub_memcpy (tmp_fdt + off_mem_rsvmap,
              fdt_ptr + grub_fdt_get_off_mem_rsvmap (fdt),
              get_mem_rsvmap_size (fdt));
  grub_fdt_set_off_mem_rsvmap (fdt, off_mem_rsvmap);
  grub_memcpy (tmp_fdt + off_dt_struct,
              fdt_ptr + grub_fdt_get_off_dt_struct (fdt),
              grub_fdt_get_size_dt_struct (fdt));
  grub_fdt_set_off_dt_struct (fdt, off_dt_struct);
  grub_memcpy (tmp_fdt + off_dt_strings,
              fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
              grub_fdt_get_size_dt_strings (fdt));
  grub_fdt_set_off_dt_strings (fdt, off_dt_strings);

  /* Copy reordered blocks back to fdt. */
  memcpy (fdt_ptr + off_mem_rsvmap, tmp_fdt + off_mem_rsvmap,
         grub_fdt_get_totalsize (fdt) - off_mem_rsvmap);

  grub_free(tmp_fdt);
  return 0;
}

static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
				 const char *name)
{
  grub_uint32_t *prop = (void *) ((grub_addr_t) fdt
                                 + grub_fdt_get_off_dt_struct (fdt)
                                 + nodeoffset);
  grub_uint32_t nameoff;

  do
  {
    if (grub_be_to_cpu32(*prop) == FDT_PROP)
      {
        nameoff = grub_be_to_cpu32(*(prop + 2));
        if ((nameoff + grub_strlen (name) < grub_fdt_get_size_dt_strings (fdt))
            && !grub_strcmp (name, (char *) fdt +
                             grub_fdt_get_off_dt_strings (fdt) + nameoff))
        	return prop;
        prop += prop_entry_size(grub_be_to_cpu32(*prop + 1)) / sizeof (*prop);
      }
    else if (grub_be_to_cpu32(*prop) != FDT_NOP)
      return NULL;
    prop++;
  } while ((grub_addr_t) prop < ((grub_addr_t) fdt
                                 + grub_fdt_get_off_dt_struct (fdt)
                                 + grub_fdt_get_size_dt_struct (fdt)));
  return NULL;
}

/* Check the FDT header for consistency and adjust the totalsize field to match
   the size allocated for the FDT; if this function is called before the other
   functions in this file and returns success, the other functions are
   guaranteed not to access memory locations outside the allocated memory. */
int grub_fdt_check_header (void *fdt, unsigned int size)
{
  if (((grub_addr_t) fdt & 0x7) || (grub_fdt_get_magic (fdt) != FDT_MAGIC)
      || (grub_fdt_get_totalsize (fdt) > size)
      || (grub_fdt_get_version (fdt) < FDT_SUPPORTED_VERSION)
      || (grub_fdt_get_last_comp_version (fdt) > FDT_SUPPORTED_VERSION)
      || (grub_fdt_get_off_dt_struct (fdt) & 0x00000003)
      || (grub_fdt_get_size_dt_struct (fdt) & 0x00000003)
      || (grub_fdt_get_off_dt_struct (fdt) + grub_fdt_get_size_dt_struct (fdt)
          > grub_fdt_get_totalsize (fdt))
      || (grub_fdt_get_off_dt_strings (fdt) + grub_fdt_get_size_dt_strings (fdt)
          > grub_fdt_get_totalsize (fdt))
      || (grub_fdt_get_off_mem_rsvmap (fdt) & 0x00000007)
      || (grub_fdt_get_off_mem_rsvmap (fdt)
          > grub_fdt_get_totalsize (fdt) - 2 * sizeof(grub_uint64_t)))
    return -1;
  return 0;
}

/* Find a direct sub-node of a given parent node. */
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
			   const char *name)
{
  grub_uint32_t *token, *end;
  char *node_name;

  if (parentoffset & 0x3)
    return -1;
  token = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
                    + parentoffset);
  end = (void *) struct_end (fdt);
  while (token < end)
  {
    switch (grub_be_to_cpu32(*token))
    {
      case FDT_BEGIN_NODE:
        node_name = (char *) (token + 1);
        if (node_name + grub_strlen (name) >= (char *) end)
          return -1;
        if (!grub_strcmp (node_name, name))
          return (int) ((grub_addr_t) token
                        + ALIGN_UP(grub_strlen (name) + 1, 4)
                        - grub_fdt_get_off_dt_struct (fdt));
        token = get_next_node (fdt, node_name);
        if (!token)
          return -1;
        break;
      case FDT_END_NODE:
        return -1;
      case FDT_PROP:
        /* Skip property token and following data (len, nameoff and property
           value). */
        token += 3 + grub_be_to_cpu32 (*(token + 1));
        break;
      case FDT_NOP:
        token++;
        break;
      default:
        return -1;
    }
  }
  return -1;
}

int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
			  const char *name)
{
  unsigned int entry_size = node_entry_size(name);

  if ((parentoffset & 0x3) || (get_free_space (fdt) < entry_size))
    return -1;

  /* The new node entry will increase the size of the structure block: rearrange
     blocks such that there is sufficient free space between the structure and
     the strings block, then add the new node entry. */
  if (rearrange_blocks (fdt, entry_size) < 0)
    return -1;
  return add_subnode (fdt, parentoffset, name);
}

int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
		       const void *val, grub_uint32_t len)
{
  grub_uint32_t *prop;
  int prop_name_present = 0;
  grub_uint32_t nameoff = 0;

  if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3))
    return -1;
  prop = find_prop (fdt, nodeoffset, name);
  if (prop)
    {
	  grub_uint32_t prop_len = ALIGN_UP(grub_be_to_cpu32 (*(prop + 1)),
                                        sizeof(grub_uint32_t));
	  grub_uint32_t i;

      prop_name_present = 1;
	  for (i = 0; i < prop_len / sizeof(grub_uint32_t); i++)
        *(prop + 3 + i) = grub_cpu_to_be32 (FDT_NOP);
      if (len > prop_len)
        {
          /* Length of new property value is greater than the space allocated
             for the current value: a new entry needs to be created, so save the
             nameoff field of the current entry and replace the current entry
             with NOP tokens. */
          nameoff = grub_be_to_cpu32 (*(prop + 2));
    	  *prop = *(prop + 1) = *(prop + 2) = grub_cpu_to_be32 (FDT_NOP);
          prop = NULL;
        }
    }
  if (!prop || !prop_name_present) {
    unsigned int needed_space = 0;

    if (!prop)
      needed_space = prop_entry_size(len);
    if (!prop_name_present)
      needed_space += grub_strlen (name) + 1;
    if (needed_space > get_free_space (fdt))
      return -1;
    if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0)
      return -1;
  }
  if (!prop_name_present) {
    /* Append the property name at the end of the strings block. */
    nameoff = grub_fdt_get_size_dt_strings (fdt);
    grub_strcpy ((char *) fdt + grub_fdt_get_off_dt_strings (fdt) + nameoff,
                 name);
    grub_fdt_set_size_dt_strings (fdt, grub_fdt_get_size_dt_strings (fdt)
                                  + grub_strlen (name) + 1);
  }
  if (!prop) {
    prop = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt)
                     + nodeoffset);
    grub_memmove (prop + prop_entry_size(len), prop,
                  grub_fdt_get_size_dt_struct (fdt) - nodeoffset);
    *prop = grub_cpu_to_be32 (FDT_PROP);
    *(prop + 1) = grub_cpu_to_be32 (len);
    *(prop + 2) = grub_cpu_to_be32 (nameoff);

    /* Insert padding bytes at the end of the value; if they are not needed,
      they will be overwritten by the follozing memcpy. */
    *(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0;

    grub_memcpy (prop + 3, val, len);
  }
  return 0;
}

[-- Attachment #3: fdt.h --]
[-- Type: text/x-chdr, Size: 3738 bytes --]

/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2013  Free Software Foundation, Inc.
 *
 *  GRUB 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef GRUB_FDT_HEADER
#define GRUB_FDT_HEADER	1

#include <grub/types.h>

#define FDT_MAGIC 0xD00DFEED

typedef struct {
	grub_uint32_t magic;
	grub_uint32_t totalsize;
	grub_uint32_t off_dt_struct;
	grub_uint32_t off_dt_strings;
	grub_uint32_t off_mem_rsvmap;
	grub_uint32_t version;
	grub_uint32_t last_comp_version;
	grub_uint32_t boot_cpuid_phys;
	grub_uint32_t size_dt_strings;
	grub_uint32_t size_dt_struct;
} grub_fdt_header_t;

#define grub_fdt_get_header(fdt, field)	\
	grub_be_to_cpu32(((const grub_fdt_header_t *)(fdt))->field)
#define grub_fdt_set_header(fdt, field, value)	\
	((grub_fdt_header_t *)(fdt))->field = grub_cpu_to_be32(value)

#define grub_fdt_get_magic(fdt)	\
	grub_fdt_get_header(fdt, magic)
#define grub_fdt_set_magic(fdt, value)	\
	grub_fdt_set_header(fdt, magic, value)
#define grub_fdt_get_totalsize(fdt)	\
	grub_fdt_get_header(fdt, totalsize)
#define grub_fdt_set_totalsize(fdt, value)	\
	grub_fdt_set_header(fdt, totalsize, value)
#define grub_fdt_get_off_dt_struct(fdt)	\
	grub_fdt_get_header(fdt, off_dt_struct)
#define grub_fdt_set_off_dt_struct(fdt, value)	\
	grub_fdt_set_header(fdt, off_dt_struct, value)
#define grub_fdt_get_off_dt_strings(fdt)	\
	grub_fdt_get_header(fdt, off_dt_strings)
#define grub_fdt_set_off_dt_strings(fdt, value)	\
	grub_fdt_set_header(fdt, off_dt_strings, value)
#define grub_fdt_get_off_mem_rsvmap(fdt)	\
	grub_fdt_get_header(fdt, off_mem_rsvmap)
#define grub_fdt_set_off_mem_rsvmap(fdt, value)	\
	grub_fdt_set_header(fdt, off_mem_rsvmap, value)
#define grub_fdt_get_version(fdt)	\
	grub_fdt_get_header(fdt, version)
#define grub_fdt_set_version(fdt, value)	\
	grub_fdt_set_header(fdt, version, value)
#define grub_fdt_get_last_comp_version(fdt)	\
	grub_fdt_get_header(fdt, last_comp_version)
#define grub_fdt_set_last_comp_version(fdt, value)	\
	grub_fdt_set_header(fdt, last_comp_version, value)
#define grub_fdt_get_boot_cpuid_phys(fdt)	\
	grub_fdt_get_header(fdt, boot_cpuid_phys)
#define grub_fdt_set_boot_cpuid_phys(fdt, value)	\
	grub_fdt_set_header(fdt, boot_cpuid_phys, value)
#define grub_fdt_get_size_dt_strings(fdt)	\
	grub_fdt_get_header(fdt, size_dt_strings)
#define grub_fdt_set_size_dt_strings(fdt, value)	\
	grub_fdt_set_header(fdt, size_dt_strings, value)
#define grub_fdt_get_size_dt_struct(fdt)	\
	grub_fdt_get_header(fdt, size_dt_struct)
#define grub_fdt_set_size_dt_struct(fdt, value)	\
	grub_fdt_set_header(fdt, size_dt_struct, value)

int grub_fdt_check_header (void *fdt, unsigned int size);
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
			   const char *name);
int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
			  const char *name);

int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
		      const void *val, grub_uint32_t len);
#define grub_fdt_set_prop32(fdt, nodeoffset, name, val)	\
({ \
  grub_uint32_t _val = grub_cpu_to_be32(val); \
  grub_fdt_set_prop ((fdt), (nodeoffset), (name), &_val, 4);	\
})

#endif	/* ! GRUB_FDT_HEADER */

[-- Attachment #4: linux.c --]
[-- Type: text/x-csrc, Size: 9348 bytes --]

/* linux.c - boot Linux */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2013  Free Software Foundation, Inc.
 *
 *  GRUB 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/dl.h>
#include <grub/fdt.h>
#include <grub/file.h>
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/command.h>
#include <grub/cache.h>
#include <grub/lib/cmdline.h>

GRUB_MOD_LICENSE ("GPLv3+");

static grub_dl_t my_mod;

static grub_addr_t initrd_start, initrd_end;

static grub_addr_t linux_addr;
static grub_size_t linux_size;

static char *linux_args;

static void *fdt_addr;

#define LINUX_ZIMAGE_OFFSET	0x24
#define LINUX_ZIMAGE_MAGIC	0x016f2818

#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF

#define LINUX_PHYS_OFFSET        (0x00008000)
#define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
#define LINUX_FDT_PHYS_OFFSET    (LINUX_INITRD_PHYS_OFFSET - 0x10000)

typedef void (*kernel_entry_t) (int, unsigned long, void *);

/*
 * linux_prepare_fdt():
 *   Prepares a loaded FDT for being passed to Linux.
 *   Merges in command line parameters and sets up initrd addresses.
 */
static grub_err_t
linux_prepare_fdt (void)
{
#define FDT_ADDITIONAL_ENTRIES_SIZE	(0x100 + grub_strlen (linux_args))
  int node;
  int retval;
  int tmp_size;
  void *tmp_fdt;

  tmp_size = grub_fdt_get_totalsize (fdt_addr) + FDT_ADDITIONAL_ENTRIES_SIZE;
  tmp_fdt = grub_malloc (tmp_size);
  if (!tmp_fdt)
    return GRUB_ERR_OUT_OF_MEMORY;

  grub_memcpy (tmp_fdt, fdt_addr, grub_fdt_get_totalsize (fdt_addr));
  grub_fdt_set_totalsize (tmp_fdt, tmp_size);

  /* Find or create '/chosen' node */
  node = grub_fdt_find_subnode (tmp_fdt, 0, "chosen");
  if (node < 0)
    {
      grub_printf ("No 'chosen' node in FDT - creating.\n");
      node = grub_fdt_add_subnode (tmp_fdt, 0, "chosen");
      if (node < 0)
	goto failure;
    }

  grub_printf ("linux_args: '%s'\n", linux_args);

  /* Generate and set command line */
  retval = grub_fdt_set_prop (tmp_fdt, node, "bootargs", linux_args,
			      grub_strlen (linux_args) + 1);
  if (retval)
    goto failure;

  if (initrd_start && initrd_end)
    {
      /*
       * We're using physical addresses, so even if we have LPAE, we're
       * restricted to a 32-bit address space.
       */
      grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n",
		    initrd_start, initrd_end);

      retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-start",
				    initrd_start);
      if (retval)
	goto failure;
      retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-end",
				    initrd_end);
      if (retval)
	goto failure;
    }

  /* Copy updated FDT to its launch location */
  grub_memcpy (fdt_addr, tmp_fdt, tmp_size);
  grub_free (tmp_fdt);

  grub_dprintf ("loader", "FDT updated for Linux boot\n");

  return GRUB_ERR_NONE;

failure:
  grub_free (tmp_fdt);
  return GRUB_ERR_BAD_ARGUMENT;
}

static grub_err_t
linux_boot (void)
{
  kernel_entry_t linuxmain;
  grub_err_t err;

  if (!fdt_addr)
    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
		       N_("device tree must be supplied"));

  grub_arch_sync_caches ((void *) linux_addr, linux_size);

  grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);

  err = linux_prepare_fdt ();
  if (err != GRUB_ERR_NONE)
    {
      return grub_error (err, "unable to prepare FDT");
    }
  grub_dprintf ("loader", "FDT @ 0x%p\n", fdt_addr);

  grub_dprintf ("loader", "Jumping to Linux...\n");

  /* Boot the kernel.
   *   Arguments to kernel:
   *     r0 - 0
   *     r1 - machine type
   *     r2 - address of DTB
   */
  linuxmain = (kernel_entry_t) linux_addr;

  err = grub_efi_prepare_platform();
  if (err != GRUB_ERR_NONE)
    return err;

  linuxmain (0, ARM_FDT_MACHINE_TYPE, fdt_addr);

  return err;
}

/*
 * Only support zImage, so no relocations necessary
 */
static grub_err_t
linux_load (grub_file_t file)
{
  int size;
  grub_err_t err;

  size = grub_file_size (file);
  if (size == 0)
    return GRUB_ERR_FILE_READ_ERROR;

  linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET,
							      size);
  if (!linux_addr)
    return GRUB_ERR_OUT_OF_MEMORY;

  grub_dprintf ("loader", "Loading Linux to 0x%08x\n",
		(grub_addr_t) linux_addr);

  if (grub_file_read (file, (void *) linux_addr, size) != size)
    {
      grub_printf ("Kernel read failed!\n");
      err = GRUB_ERR_FILE_READ_ERROR;
      goto error;
    }

  if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
      != LINUX_ZIMAGE_MAGIC)
    {
      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid zImage"));
      goto error;
    }

  linux_size = size;
  return GRUB_ERR_NONE;
error:
  grub_free ((void *) linux_addr);
  return err;
}

static grub_err_t
linux_unload (void)
{
  grub_dl_unref (my_mod);

  if (linux_args)
    {
      grub_free (linux_args);
      linux_args = NULL;
    }
  grub_free ((void *) linux_addr);

  return GRUB_ERR_NONE;
}

static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
		int argc, char *argv[])
{
  int size;
  grub_err_t retval;
  grub_file_t file;
  grub_dl_ref (my_mod);

  if (argc == 0)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));

  file = grub_file_open (argv[0]);
  if (!file)
    goto fail;

  retval = linux_load (file);
  grub_file_close (file);
  if (retval != GRUB_ERR_NONE)
    {
	  grub_errno = retval;
      goto fail;
    }

  grub_loader_set (linux_boot, linux_unload, 0);

  size = grub_loader_cmdline_size (argc, argv);
  linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
  if (!linux_args)
    {
      grub_loader_unset();
      goto fail;
    }

  /* Create kernel command line.  */
  grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
  grub_create_loader_cmdline (argc, argv,
			      linux_args + sizeof (LINUX_IMAGE) - 1, size);

  return GRUB_ERR_NONE;

fail:
  grub_dl_unref (my_mod);
  return grub_errno;
}

static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
		 int argc, char *argv[])
{
  grub_file_t file;
  int size;

  if (argc == 0)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));

  file = grub_file_open (argv[0]);
  if (!file)
    return grub_errno;

  size = grub_file_size (file);
  if (size == 0)
    goto fail;

  if (initrd_start)
    grub_free ((void *) initrd_start);
  initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (
		 LINUX_INITRD_PHYS_OFFSET, size);
  if (!initrd_start)
    {
      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory allocation failed"));
      goto fail;
    }

  grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
		(grub_addr_t) initrd_start);

  if (grub_file_read (file, (void *) initrd_start, size) != size)
    {
      grub_free ((void *) initrd_start);
      initrd_start = 0;
      goto fail;
    }

  initrd_end = initrd_start + size;

  return GRUB_ERR_NONE;

fail:
  grub_file_close (file);

  return grub_errno;
}

static grub_err_t
load_dtb (grub_file_t dtb, int size)
{
  if ((grub_file_read (dtb, fdt_addr, size) != size)
      || (grub_fdt_check_header (fdt_addr, size) != 0))
    return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid device tree"));

  grub_fdt_set_totalsize (fdt_addr, size);
  return GRUB_ERR_NONE;
}

static grub_err_t
grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
		     int argc, char *argv[])
{
  grub_file_t dtb;
  int size;

  if (argc != 1)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));

  dtb = grub_file_open (argv[0]);
  if (!dtb)
    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file"));

  size = grub_file_size (dtb);
  if (size == 0)
    goto out;

  if (fdt_addr)
    grub_free (fdt_addr);
  fdt_addr = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
  if (!fdt_addr)
    {
      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory allocation failed"));
      goto out;
    }

  grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
		(grub_addr_t) fdt_addr);
  load_dtb (dtb, size);
  if (grub_errno != GRUB_ERR_NONE)
    {
      grub_free (fdt_addr);
      fdt_addr = NULL;
    }

 out:
  grub_file_close (dtb);

  return grub_errno;
}

static grub_command_t cmd_linux, cmd_initrd, cmd_devicetree;

GRUB_MOD_INIT (linux)
{
  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
				     0, N_("Load Linux."));
  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
				      0, N_("Load initrd."));
  cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree,
					  0, N_("Load DTB file."));
  my_mod = mod;
}

GRUB_MOD_FINI (linux)
{
  grub_unregister_command (cmd_linux);
  grub_unregister_command (cmd_initrd);
  grub_unregister_command (cmd_devicetree);
}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-03-24 17:01 [PATCH 5/7] add imported "FDT" module for flattened device tree operations Leif Lindholm
  2013-03-30 16:53 ` Francesco Lavra
  2013-04-01  2:16 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-04-02 20:39 ` Phillip Susi
  2013-04-04 18:22   ` Francesco Lavra
  2 siblings, 1 reply; 14+ messages in thread
From: Phillip Susi @ 2013-04-02 20:39 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Leif Lindholm

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Your patches can not be reviewed inline because your mail client is
incorrectly setting the mime type to application/octet-stream and the
disposition to attachment.  Please fix this.


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJRW0H5AAoJEJrBOlT6nu75eQ8H/jb5IzgyChXT/UMkT7ZtS/SG
oWeN/abnRXp8Zo16Xo2saT+MiddnTfq8jpwSOvGBAAMsbd6Jdj/4aDgkusyhO0fh
7n+VuzBIDSVXnlSbMEr9RhMlHKyucJDAAmKmiMzpqHz/Uqrt4yNXWBVOGZGg6Y8N
l3T0Ne3cxc2DRgXb0TgH8vDiRkTEVDHxAp1U/o98maOtLg7+rbXNsiDkPRUYkXcJ
A3xDnwbzkTKamPuX9ChHwGJkQceeAG6nCFbrof+5ypWaFI7Zx7NjNciEHA5wY/zx
BDGSrhFL77mDtVPsfYXA8GMooL+ia+3wTWYarhPrtFPi7mq/ny266tQJKk47xOU=
=3yGf
-----END PGP SIGNATURE-----


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-02 20:39 ` Phillip Susi
@ 2013-04-04 18:22   ` Francesco Lavra
  2013-04-04 19:02     ` Phillip Susi
  0 siblings, 1 reply; 14+ messages in thread
From: Francesco Lavra @ 2013-04-04 18:22 UTC (permalink / raw)
  To: grub-devel

On 04/02/2013 10:39 PM, Phillip Susi wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Your patches can not be reviewed inline because your mail client is
> incorrectly setting the mime type to application/octet-stream and the
> disposition to attachment.  Please fix this.

Actually the mime types are correct (text/x-csrc and text/x-cdhr). You
are right about the content disposition though, my mail client ignores
this option when displaying e-mails so I can actually view attachments
inline even though the message source says differently.
Will make sure to have this fixed next time.

--
Francesco


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-04 18:22   ` Francesco Lavra
@ 2013-04-04 19:02     ` Phillip Susi
  2013-04-04 19:15       ` Andrey Borzenkov
  2013-04-04 19:46       ` Francesco Lavra
  0 siblings, 2 replies; 14+ messages in thread
From: Phillip Susi @ 2013-04-04 19:02 UTC (permalink / raw)
  To: The development of GNU GRUB

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 4/4/2013 2:22 PM, Francesco Lavra wrote:
> On 04/02/2013 10:39 PM, Phillip Susi wrote:
>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
>> 
>> Your patches can not be reviewed inline because your mail client
>> is incorrectly setting the mime type to application/octet-stream
>> and the disposition to attachment.  Please fix this.
> 
> Actually the mime types are correct (text/x-csrc and text/x-cdhr).
> You are right about the content disposition though, my mail client
> ignores this option when displaying e-mails so I can actually view
> attachments inline even though the message source says
> differently. Will make sure to have this fixed next time.

Quoting the headers from your original message:

Content-Type: application/octet-stream; name="0005-fdt-support.patch"

Additionally it used base64 encoding so it was treating the file as
binary data, and encoding it to use more space that needed.  Also you
appear to be using the now popular and vile reply-to-list function to
send replies only to the mailing list.  This misfeature breaks cross
posting, non subscribed posters, and delays people from seeing your
response when they do not frequently check all of the mailing lists
they are subscribed to, so please use reply-to-all instead.

See http://david.woodhou.se/reply-to-list.html for more information.


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJRXc41AAoJEJrBOlT6nu75qH8H/0DRzBi5mJp5jhCTOSvFVOJl
9GlA20pad+IV9qMAKAV1OKe5zCe8izr24uG0Vc8+cH4p8CkieEMwyT36t/4oQ3hl
kkQhJYnlNK9rodsIEoX8jbYvR/7iBbc6g8Bv8EoomAwgEcTVoERD4hpsYgrzZf73
AeSLf/HQAtnOptSwcf9JEHnhXFEubK30DmU7vqW187Brgx2PONwcvv7lLsw8mBXV
Zmk9HOlSAH8fZ1eZ1yX42eN8vlaCEa6VldMpY1ijx2LNaHVBTjXlKTlJvltHyTxU
VXOpEDNjkcNQRpf5oqt9h86O5vt1q86KJQowLauZubcK+K4XED8m8OYaB7CxAQo=
=AaaX
-----END PGP SIGNATURE-----


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-04 19:02     ` Phillip Susi
@ 2013-04-04 19:15       ` Andrey Borzenkov
  2013-04-04 19:33         ` Phillip Susi
  2013-04-04 19:46       ` Francesco Lavra
  1 sibling, 1 reply; 14+ messages in thread
From: Andrey Borzenkov @ 2013-04-04 19:15 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: psusi

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

В Thu, 04 Apr 2013 15:02:13 -0400
Phillip Susi <psusi@ubuntu.com> пишет:

>                                                            Also you
> appear to be using the now popular and vile reply-to-list function to
> send replies only to the mailing list.

Actually list sets Reply-To, so it is not necessary reply-to-list.

>                         so please use reply-to-all instead.
> 

And I was so often chastised exactly for using reply-to-all.

So what do you suggest when one subscriber requests reply-to-list and
another - reply-to-all?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (GNU/Linux)

iEYEARECAAYFAlFd0U4ACgkQR6LMutpd94zsrACfYN31F0bdWblZ8K9KSjoCEoqz
mogAnjl91W2Z47t7ioh0716uYml4z8uI
=rzWI
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-04 19:15       ` Andrey Borzenkov
@ 2013-04-04 19:33         ` Phillip Susi
  0 siblings, 0 replies; 14+ messages in thread
From: Phillip Susi @ 2013-04-04 19:33 UTC (permalink / raw)
  To: Andrey Borzenkov; +Cc: The development of GNU GRUB

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 4/4/2013 3:15 PM, Andrey Borzenkov wrote:
> Actually list sets Reply-To, so it is not necessary reply-to-list.

Only badly behaved ones do.  This field is for the SENDER to set ( for
instance, if they do not want to get a duplicate reply and have the
reply only to to the mailing list ), not the mailing list.  See
http://www.unicom.com/pw/reply-to-harmful.html.

>> so please use reply-to-all instead.
> And I was so often chastised exactly for using reply-to-all.

Then they were wrong.

> So what do you suggest when one subscriber requests reply-to-list
> and another - reply-to-all?

Always use reply-to-all.  If a subscriber does not want to get a
direct reply, they can simply set the reply-to header to point to the
mailing list and they won't get a duplicate reply, but other people
who want the reply, or messages cross posted to multiple mailing lists
will not be broken.  Alternatively they can set up a filter to notice
when the message has been sent to both them and a mailing list they
subscribe to and delete the duplicate.  Another alternative is offered
by most mailing lists where you can configure it to not send you a
copy of the message if you are already listed in the to or cc.

Any way you do it, the onus is on the person not wanting the duplicate
to avoid it, not on everyone else, especially when doing so causes
some people who should get a copy of the message not to, which is much
more harmful than someone getting a duplicate copy they don't want.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJRXdWIAAoJEJrBOlT6nu7543QIAMs3qO2yqDRVVChrUGtv54wt
M2VZx1+fyq3JJB3lvNQ1AfNAzqMFUZFK+rj3ugEdg1dCF0J+16kyMV4XO68wm4eb
k1vHxfrjFxL+6wzMLun5LYTDU1u2NjlYhnTktKxlsMJd6xslB8vC9MwnXrsCe1Xc
QCId4v5+FlM2Gt1kyf2MZzBEJ6CJfvds8i3DEA4GJJNGcylqd5gYLH5vyH9sveIP
mP+ahqdPT1xnKN4q/+TrZtnKwXIRIg/rSVBBNt9Rru4GFwv5zZ5bZyLNyq8ilc13
wR1l6EDB5SHBZp/7Tgk1/ZHBb8S9Wcwu4kK6BeTs+SwkTcIuMA9mN4l4AGI/klc=
=P+7M
-----END PGP SIGNATURE-----


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-04 19:02     ` Phillip Susi
  2013-04-04 19:15       ` Andrey Borzenkov
@ 2013-04-04 19:46       ` Francesco Lavra
  1 sibling, 0 replies; 14+ messages in thread
From: Francesco Lavra @ 2013-04-04 19:46 UTC (permalink / raw)
  To: Phillip Susi; +Cc: The development of GNU GRUB

[Using reply-to-all now...]

On 04/04/2013 09:02 PM, Phillip Susi wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On 4/4/2013 2:22 PM, Francesco Lavra wrote:
>> On 04/02/2013 10:39 PM, Phillip Susi wrote:
>>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
>>>
>>> Your patches can not be reviewed inline because your mail client
>>> is incorrectly setting the mime type to application/octet-stream
>>> and the disposition to attachment.  Please fix this.
>>
>> Actually the mime types are correct (text/x-csrc and text/x-cdhr).
>> You are right about the content disposition though, my mail client
>> ignores this option when displaying e-mails so I can actually view
>> attachments inline even though the message source says
>> differently. Will make sure to have this fixed next time.
> 
> Quoting the headers from your original message:
> 
> Content-Type: application/octet-stream; name="0005-fdt-support.patch"

I realize now that your comments were addressed to Leif and not me.
Sorry for the noise.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-01 16:42   ` Francesco Lavra
@ 2013-04-07 21:28     ` Francesco Lavra
  2013-04-08 18:14     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-05-17 11:49     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2 siblings, 0 replies; 14+ messages in thread
From: Francesco Lavra @ 2013-04-07 21:28 UTC (permalink / raw)
  To: grub-devel; +Cc: leif.lindholm

[-- Attachment #1: Type: text/plain, Size: 1551 bytes --]

On 04/01/2013 06:42 PM, Francesco Lavra wrote:
> On 04/01/2013 04:16 AM, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> Could you put the library itself into a separate tar rather than patch?
> 
> I recall you saying a few months ago that you'd prefer rather without
> libfdt. In fact, libfdt contains much more than what is needed by GRUB.
> I rewrote the FDT-related functions needed by GRUB (using GRUB's naming
> convention) and put them in the standalone files grub-core/lib/fdt.c and
> include/grub/fdt.h. The .c file would need to be included in the linux
> loader module. I also changed loader/arm/linux.c to use the new functions.
> Attached are the needed files; the loader code already contains the
> changes which I proposed in my review of Leif's patch, but supports EFI
> only, not U-Boot. Also, my code is not completely tested yet, I just
> wanted to send it out to get your feedback.

Now I tested my code more thoroughly and fixed quite a few issues. In
attachment you can find the updated version of the fdt.c file.
As far as the linux loader is concerned, I had naively assumed that the
memory allocated with grub_efi_allocate_loader_memory() could be freed
with the usual grub_free(). But then I soon realized this was not the
case, and I wrote a small helper function to properly free the memory:

void
grub_efi_free_memory (void *start, grub_uint32_t size)
{
  grub_efi_free_pages ((grub_addr_t) start, (size >> PAGE_SHIFT) + 1);
}

This function should go in the same file as
grub_efi_allocate_loader_memory().

--
Francesco

[-- Attachment #2: fdt.c --]
[-- Type: text/x-csrc, Size: 14638 bytes --]

/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2013  Free Software Foundation, Inc.
 *
 *  GRUB 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/fdt.h>
#include <grub/misc.h>
#include <grub/mm.h>

#define FDT_SUPPORTED_VERSION	17

#define FDT_BEGIN_NODE	0x00000001
#define FDT_END_NODE	0x00000002
#define FDT_PROP	0x00000003
#define FDT_NOP		0x00000004
#define FDT_END		0x00000009

#define struct_end(fdt)	\
	((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)	\
	 + grub_fdt_get_size_dt_struct(fdt))

/* Size needed by a node entry: 2 tokens (FDT_BEGIN_NODE and FDT_END_NODE), plus
   the NULL-terminated string containing the name, plus padding if needed. */
#define node_entry_size(node_name)	\
	(2 * sizeof(grub_uint32_t)	\
	+ ALIGN_UP (grub_strlen (name) + 1, sizeof(grub_uint32_t)))

/* Size needed by a property entry: 1 token (FDT_PROPERTY), plus len and nameoff
   fields, plus the property value, plus padding if needed. */
#define prop_entry_size(prop_len)	\
	(3 * sizeof(grub_uint32_t) + ALIGN_UP(prop_len, sizeof(grub_uint32_t)))

#define SKIP_NODE_NAME(name, token, end)	\
  name = (char *) ((token) + 1);	\
  while (name < (char *) end)	\
  {	\
    if (!*name++)	\
      break;	\
  }	\
  token = (grub_uint32_t *) ALIGN_UP((grub_addr_t) (name), sizeof(*token))


static grub_uint32_t *get_next_node (const void *fdt, char *node_name)
{
  grub_uint32_t *end = (void *) struct_end (fdt);
  grub_uint32_t *token;

  if (node_name >= (char *) end)
    return NULL;
  while (*node_name++)
  {
    if (node_name >= (char *) end)
  	  return NULL;
  }
  token = (grub_uint32_t *) ALIGN_UP ((grub_addr_t) node_name, 4);
  while (token < end)
  {
    switch (grub_be_to_cpu32(*token))
    {
      case FDT_BEGIN_NODE:
        token = get_next_node (fdt, (char *) (token + 1));
        if (!token)
          return NULL;
        break;
      case FDT_END_NODE:
        token++;
        if (token >= end)
          return NULL;
        return token;
      case FDT_PROP:
        /* Skip property token and following data (len, nameoff and property
           value). */
        token += prop_entry_size(grub_be_to_cpu32(*(token + 1)))
                 / sizeof(*token);
        break;
      case FDT_NOP:
        token++;
        break;
      default:
        return NULL;
    }
  }
  return NULL;
}

static int get_mem_rsvmap_size (const void *fdt)
{
  int size = 0;
  grub_uint64_t *ptr = (void *) ((grub_addr_t) fdt
                                 + grub_fdt_get_off_mem_rsvmap (fdt));

  do
  {
    size += 2 * sizeof(*ptr);
    if (!*ptr && !*(ptr + 1))
      return size;
    ptr += 2;
  } while ((grub_addr_t) ptr <= (grub_addr_t) fdt + grub_fdt_get_totalsize (fdt)
                                  - 2 * sizeof(grub_uint64_t));
  return -1;
}

static grub_uint32_t get_free_space (void *fdt)
{
  int mem_rsvmap_size = get_mem_rsvmap_size (fdt);

  if (mem_rsvmap_size < 0)
    /* invalid memory reservation block */
    return 0;
  return (grub_fdt_get_totalsize (fdt) - sizeof(grub_fdt_header_t)
          - mem_rsvmap_size - grub_fdt_get_size_dt_strings (fdt)
          - grub_fdt_get_size_dt_struct (fdt));
}

static int add_subnode (void *fdt, int parentoffset, const char *name)
{
  grub_uint32_t *token = (void *) ((grub_addr_t) fdt
                                   + grub_fdt_get_off_dt_struct(fdt)
                                   + parentoffset);
  grub_uint32_t *end = (void *) struct_end (fdt);
  unsigned int entry_size = node_entry_size (name);
  char *node_name;

  SKIP_NODE_NAME(node_name, token, end);

  /* Insert the new subnode just after the properties of the parent node (if
     any).*/
  while (1)
  {
    if (token >= end)
      return -1;
    switch (grub_be_to_cpu32(*token))
    {
      case FDT_PROP:
        /* Skip len, nameoff and property value. */
        token += prop_entry_size(grub_be_to_cpu32(*(token + 1)))
                 / sizeof(*token);
        break;
      case FDT_BEGIN_NODE:
      case FDT_END_NODE:
        goto insert;
      case FDT_NOP:
        token++;
      default:
        /* invalid token */
        return -1;
    }
  }
insert:
  grub_memmove (token + entry_size / sizeof(*token), token,
                (grub_addr_t) end - (grub_addr_t) token);
  *token = grub_cpu_to_be32(FDT_BEGIN_NODE);
  token[entry_size / sizeof(*token) - 2] = 0;	/* padding bytes */
  grub_strcpy((char *) (token + 1), name);
  token[entry_size / sizeof(*token) - 1] = grub_cpu_to_be32(FDT_END_NODE);
  return ((grub_addr_t) token - (grub_addr_t) fdt
          - grub_fdt_get_off_dt_struct(fdt));
}

/* Rearrange FDT blocks in the canonical order: first the memory reservation
   block (just after the FDT header), then the structure block and finally the
   strings block. No free space is left between the first and the second block,
   while the space between the second and the third block is given by the
   clearance argument. */
static int rearrange_blocks (void *fdt, unsigned int clearance)
{
  grub_uint32_t off_mem_rsvmap = ALIGN_UP(sizeof(grub_fdt_header_t), 8);
  grub_uint32_t off_dt_struct = off_mem_rsvmap + get_mem_rsvmap_size (fdt);
  grub_uint32_t off_dt_strings = off_dt_struct
                                 + grub_fdt_get_size_dt_struct (fdt)
                                 + clearance;
  grub_uint8_t *fdt_ptr = fdt;
  grub_uint8_t *tmp_fdt;

  if ((grub_fdt_get_off_mem_rsvmap (fdt) == off_mem_rsvmap)
      && (grub_fdt_get_off_dt_struct (fdt) == off_dt_struct))
    {
      /* No need to allocate memory for a temporary FDT, just move the strings
         block if needed. */
      if (grub_fdt_get_off_dt_strings (fdt) != off_dt_strings)
        {
          grub_memmove(fdt_ptr + off_dt_strings,
                       fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
                       grub_fdt_get_size_dt_strings (fdt));
          grub_fdt_set_off_dt_strings (fdt, off_dt_strings);
        }
      return 0;
    }
  tmp_fdt = grub_malloc (grub_fdt_get_totalsize (fdt));
  if (!tmp_fdt)
    return -1;
  grub_memcpy (tmp_fdt + off_mem_rsvmap,
               fdt_ptr + grub_fdt_get_off_mem_rsvmap (fdt),
               get_mem_rsvmap_size (fdt));
  grub_fdt_set_off_mem_rsvmap (fdt, off_mem_rsvmap);
  grub_memcpy (tmp_fdt + off_dt_struct,
               fdt_ptr + grub_fdt_get_off_dt_struct (fdt),
               grub_fdt_get_size_dt_struct (fdt));
  grub_fdt_set_off_dt_struct (fdt, off_dt_struct);
  grub_memcpy (tmp_fdt + off_dt_strings,
               fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
               grub_fdt_get_size_dt_strings (fdt));
  grub_fdt_set_off_dt_strings (fdt, off_dt_strings);

  /* Copy reordered blocks back to fdt. */
  memcpy (fdt_ptr + off_mem_rsvmap, tmp_fdt + off_mem_rsvmap,
         grub_fdt_get_totalsize (fdt) - off_mem_rsvmap);

  grub_free(tmp_fdt);
  return 0;
}

static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
				 const char *name)
{
  grub_uint32_t *prop = (void *) ((grub_addr_t) fdt
                                 + grub_fdt_get_off_dt_struct (fdt)
                                 + nodeoffset);
  grub_uint32_t *end = (void *) struct_end(fdt);
  grub_uint32_t nameoff;
  char *node_name;

  SKIP_NODE_NAME(node_name, prop, end);
  while (prop < end - 2)
  {
    if (grub_be_to_cpu32(*prop) == FDT_PROP)
      {
        nameoff = grub_be_to_cpu32(*(prop + 2));
        if ((nameoff + grub_strlen (name) < grub_fdt_get_size_dt_strings (fdt))
            && !grub_strcmp (name, (char *) fdt +
                             grub_fdt_get_off_dt_strings (fdt) + nameoff))
        {
          if (prop + prop_entry_size(grub_be_to_cpu32(*(prop + 1)))
              / sizeof (*prop) >= end)
            return NULL;
          return prop;
        }
        prop += prop_entry_size(grub_be_to_cpu32(*(prop + 1))) / sizeof (*prop);
      }
    else if (grub_be_to_cpu32(*prop) == FDT_NOP)
      prop++;
    else
      return NULL;
  }
  return NULL;
}

/* Check the FDT header for consistency and adjust the totalsize field to match
   the size allocated for the FDT; if this function is called before the other
   functions in this file and returns success, the other functions are
   guaranteed not to access memory locations outside the allocated memory. */
int grub_fdt_check_header (void *fdt, unsigned int size)
{
  if (((grub_addr_t) fdt & 0x7) || (grub_fdt_get_magic (fdt) != FDT_MAGIC)
      || (grub_fdt_get_totalsize (fdt) > size)
      || (grub_fdt_get_version (fdt) < FDT_SUPPORTED_VERSION)
      || (grub_fdt_get_last_comp_version (fdt) > FDT_SUPPORTED_VERSION)
      || (grub_fdt_get_off_dt_struct (fdt) & 0x00000003)
      || (grub_fdt_get_size_dt_struct (fdt) & 0x00000003)
      || (grub_fdt_get_off_dt_struct (fdt) + grub_fdt_get_size_dt_struct (fdt)
          > grub_fdt_get_totalsize (fdt))
      || (grub_fdt_get_off_dt_strings (fdt) + grub_fdt_get_size_dt_strings (fdt)
          > grub_fdt_get_totalsize (fdt))
      || (grub_fdt_get_off_mem_rsvmap (fdt) & 0x00000007)
      || (grub_fdt_get_off_mem_rsvmap (fdt)
          > grub_fdt_get_totalsize (fdt) - 2 * sizeof(grub_uint64_t)))
    return -1;
  return 0;
}

/* Find a direct sub-node of a given parent node. */
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
			   const char *name)
{
  grub_uint32_t *token, *end;
  char *node_name;

  if (parentoffset & 0x3)
    return -1;
  token = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
                    + parentoffset);
  end = (void *) struct_end (fdt);
  if ((token >= end) || (grub_be_to_cpu32(*token) != FDT_BEGIN_NODE))
    return -1;
  SKIP_NODE_NAME(node_name, token, end);
  while (token < end)
  {
    switch (grub_be_to_cpu32(*token))
    {
      case FDT_BEGIN_NODE:
        node_name = (char *) (token + 1);
        if (node_name + grub_strlen (name) >= (char *) end)
          return -1;
        if (!grub_strcmp (node_name, name))
          return (int) ((grub_addr_t) token - (grub_addr_t) fdt
                        - grub_fdt_get_off_dt_struct (fdt));
        token = get_next_node (fdt, node_name);
        if (!token)
          return -1;
        break;
      case FDT_PROP:
        /* Skip property token and following data (len, nameoff and property
           value). */
        if (token >= end - 1)
          return -1;
        token += prop_entry_size(grub_be_to_cpu32(*(token + 1)))
                 / sizeof(*token);
        break;
      case FDT_NOP:
        token++;
        break;
      default:
        return -1;
    }
  }
  return -1;
}

int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
			  const char *name)
{
  unsigned int entry_size = node_entry_size(name);

  if ((parentoffset & 0x3) || (get_free_space (fdt) < entry_size))
    return -1;

  /* The new node entry will increase the size of the structure block: rearrange
     blocks such that there is sufficient free space between the structure and
     the strings block, then add the new node entry. */
  if (rearrange_blocks (fdt, entry_size) < 0)
    return -1;
  return add_subnode (fdt, parentoffset, name);
}

int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
		       const void *val, grub_uint32_t len)
{
  grub_uint32_t *prop;
  int prop_name_present = 0;
  grub_uint32_t nameoff = 0;

  if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3)
      || (grub_be_to_cpu32(*(grub_uint32_t *) ((grub_addr_t) fdt
                           + grub_fdt_get_off_dt_struct (fdt) + nodeoffset))
          != FDT_BEGIN_NODE))
    return -1;
  prop = find_prop (fdt, nodeoffset, name);
  if (prop)
    {
	  grub_uint32_t prop_len = ALIGN_UP(grub_be_to_cpu32 (*(prop + 1)),
                                        sizeof(grub_uint32_t));
	  grub_uint32_t i;

      prop_name_present = 1;
	  for (i = 0; i < prop_len / sizeof(grub_uint32_t); i++)
        *(prop + 3 + i) = grub_cpu_to_be32 (FDT_NOP);
      if (len > ALIGN_UP(prop_len, sizeof(grub_uint32_t)))
        {
          /* Length of new property value is greater than the space allocated
             for the current value: a new entry needs to be created, so save the
             nameoff field of the current entry and replace the current entry
             with NOP tokens. */
          nameoff = grub_be_to_cpu32 (*(prop + 2));
    	  *prop = *(prop + 1) = *(prop + 2) = grub_cpu_to_be32 (FDT_NOP);
          prop = NULL;
        }
    }
  if (!prop || !prop_name_present) {
    unsigned int needed_space = 0;

    if (!prop)
      needed_space = prop_entry_size(len);
    if (!prop_name_present)
      needed_space += grub_strlen (name) + 1;
    if (needed_space > get_free_space (fdt))
      return -1;
    if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0)
      return -1;
  }
  if (!prop_name_present) {
    /* Append the property name at the end of the strings block. */
    nameoff = grub_fdt_get_size_dt_strings (fdt);
    grub_strcpy ((char *) fdt + grub_fdt_get_off_dt_strings (fdt) + nameoff,
                 name);
    grub_fdt_set_size_dt_strings (fdt, grub_fdt_get_size_dt_strings (fdt)
                                  + grub_strlen (name) + 1);
  }
  if (!prop) {
    char *node_name = (char *) ((grub_addr_t) fdt
                                + grub_fdt_get_off_dt_struct (fdt) + nodeoffset
                                + sizeof(grub_uint32_t));

    prop = (void *) (node_name + ALIGN_UP(grub_strlen(node_name) + 1, 4));
    grub_memmove (prop + prop_entry_size(len) / sizeof(*prop), prop,
                  struct_end(fdt) - (grub_addr_t) prop);
    grub_fdt_set_size_dt_struct (fdt, grub_fdt_get_size_dt_struct (fdt)
                                 + prop_entry_size(len));
    *prop = grub_cpu_to_be32 (FDT_PROP);
    *(prop + 2) = grub_cpu_to_be32 (nameoff);
  }
  *(prop + 1) = grub_cpu_to_be32 (len);

  /* Insert padding bytes at the end of the value; if they are not needed, they
     will be overwritten by the following memcpy. */
  *(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0;

  grub_memcpy (prop + 3, val, len);
  return 0;
}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-01 16:42   ` Francesco Lavra
  2013-04-07 21:28     ` Francesco Lavra
@ 2013-04-08 18:14     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-05-17 11:49     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2 siblings, 0 replies; 14+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-04-08 18:14 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 1165 bytes --]

On 01.04.2013 18:42, Francesco Lavra wrote:

> On 04/01/2013 04:16 AM, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> Could you put the library itself into a separate tar rather than patch?
> 
> I recall you saying a few months ago that you'd prefer rather without
> libfdt. In fact, libfdt contains much more than what is needed by GRUB.
> I rewrote the FDT-related functions needed by GRUB (using GRUB's naming
> convention) and put them in the standalone files grub-core/lib/fdt.c and
> include/grub/fdt.h. The .c file would need to be included in the linux
> loader module. I also changed loader/arm/linux.c to use the new functions.
> Attached are the needed files; the loader code already contains the
> changes which I proposed in my review of Leif's patch, but supports EFI
> only, not U-Boot. Also, my code is not completely tested yet, I just
> wanted to send it out to get your feedback.
> 

Very good. This solves a bunch of problems.

> Regards,
> Francesco
> 
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel




[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 294 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-04-01 16:42   ` Francesco Lavra
  2013-04-07 21:28     ` Francesco Lavra
  2013-04-08 18:14     ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-05-17 11:49     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-05-19 17:36       ` Francesco Lavra
  2 siblings, 1 reply; 14+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-05-17 11:49 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 1282 bytes --]

I applied this to ARM branch after fixing several grave problems
including attempts to free statically allocated memory. The files
originally didn't even compile.
On 01.04.2013 18:42, Francesco Lavra wrote:

> On 04/01/2013 04:16 AM, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> Could you put the library itself into a separate tar rather than patch?
> 
> I recall you saying a few months ago that you'd prefer rather without
> libfdt. In fact, libfdt contains much more than what is needed by GRUB.
> I rewrote the FDT-related functions needed by GRUB (using GRUB's naming
> convention) and put them in the standalone files grub-core/lib/fdt.c and
> include/grub/fdt.h. The .c file would need to be included in the linux
> loader module. I also changed loader/arm/linux.c to use the new functions.
> Attached are the needed files; the loader code already contains the
> changes which I proposed in my review of Leif's patch, but supports EFI
> only, not U-Boot. Also, my code is not completely tested yet, I just
> wanted to send it out to get your feedback.
> 
> Regards,
> Francesco
> 
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel




[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 294 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/7] add imported "FDT" module for flattened device tree operations
  2013-05-17 11:49     ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-05-19 17:36       ` Francesco Lavra
  0 siblings, 0 replies; 14+ messages in thread
From: Francesco Lavra @ 2013-05-19 17:36 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Vladimir 'φ-coder/phcoder' Serbinenko

On 05/17/2013 01:49 PM, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> I applied this to ARM branch after fixing several grave problems
> including attempts to free statically allocated memory. The files
> originally didn't even compile.

You seem to have missed the follow-up e-mail I sent on April 7th (see 
http://lists.gnu.org/archive/html/grub-devel/2013-04/msg00086.html), 
where I sent an updated version of the fdt driver; in fact, my first 
version of fdt.c had several issues which have been addressed in the 
second version. So please replace the current fdt.c file in the arm 
branch with the updated file.

In the mail I mentioned above, I also acknowledged my mistake in using 
grub_free() to free memory allocated by 
grub_efi_allocate_loader_memory(). But the memory used for the Linux 
kernel, the initrd and the fdt is statically allocated only in the 
u-boot case, which as I explained when I first posted my code wasn't 
supported by my code. In the EFI case the memory is not statically 
allocated and IMHO should be freed when not needed anymore. I also 
proposed to add a function grub_efi_free_memory() to 
kern/arm/efi/misc.c and to use that function to free the memory. If you 
want to add this stuff, just say so and I will happily send a patch.

Regarding the current Linux loader file, I noticed a few issues:
- The defines added at the beginning of the file are not necessary in 
the current code, because they are already in include/grub/arm/linux.h. 
When I sent my loader code, I added those defines to the .c file 
because with support for EFI only it seemed overkill to have a new 
header file.
- In linux_unload(), the initrd data is discarded: why? This doesn't 
seem right, and looking for example at the i386 linux loader, I see 
no such thing there either.
- In grub_cmd_initrd() there is a leftover call to grub_free() on 
initrd_start, which should be removed (and IMHO replaced in the EFI 
case by the right function call to free the memory).
- In grub_cmd_devicetree(), if the supplied file name doesn't 
correspond to an existing file, grub_file_close() is called with a NULL 
argument, which results in a fatal crash.

The patch below addresses these issues.
Thanks,
Francesco

=== modified file 'grub-core/loader/arm/linux.c'
--- grub-core/loader/arm/linux.c	2013-05-17 11:45:22 +0000
+++ grub-core/loader/arm/linux.c	2013-05-19 17:00:13 +0000
@@ -43,15 +43,6 @@
 static grub_uint32_t machine_type;
 static void *fdt_addr;
 
-#define LINUX_ZIMAGE_OFFSET	0x24
-#define LINUX_ZIMAGE_MAGIC	0x016f2818
-
-#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
-
-#define LINUX_PHYS_OFFSET        (0x00008000)
-#define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
-#define LINUX_FDT_PHYS_OFFSET    (LINUX_INITRD_PHYS_OFFSET - 0x10000)
-
 /*
  * linux_prepare_fdt():
  *   Prepares a loaded FDT for being passed to Linux.
@@ -212,8 +203,6 @@
   grub_free (linux_args);
   linux_args = NULL;
 
-  initrd_start = initrd_end = 0;
-
   return GRUB_ERR_NONE;
 }
 
@@ -278,8 +267,6 @@
   if (size == 0)
     goto fail;
 
-  if (initrd_start)
-    grub_free ((void *) initrd_start);
 #ifdef GRUB_MACHINE_EFI
   initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
 
@@ -337,7 +324,7 @@
 
   dtb = grub_file_open (argv[0]);
   if (!dtb)
-    goto out;
+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file"));
 
   size = grub_file_size (dtb);
   if (size == 0)


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2013-05-19 17:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-24 17:01 [PATCH 5/7] add imported "FDT" module for flattened device tree operations Leif Lindholm
2013-03-30 16:53 ` Francesco Lavra
2013-04-01  2:16 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-04-01 16:42   ` Francesco Lavra
2013-04-07 21:28     ` Francesco Lavra
2013-04-08 18:14     ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-05-17 11:49     ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-05-19 17:36       ` Francesco Lavra
2013-04-02 20:39 ` Phillip Susi
2013-04-04 18:22   ` Francesco Lavra
2013-04-04 19:02     ` Phillip Susi
2013-04-04 19:15       ` Andrey Borzenkov
2013-04-04 19:33         ` Phillip Susi
2013-04-04 19:46       ` Francesco Lavra

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.