All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
@ 2012-09-05 11:43 Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 1/4] Fix an overflow bug with address comparison Matthew Leach
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Matthew Leach @ 2012-09-05 11:43 UTC (permalink / raw)
  To: kexec; +Cc: Matthew Leach, will.deacon

Hi all,

Running a kexec() on newer ARM platforms has become an issue as
information about the platform that is presented via device-tree is
required to boot a new kernel.

The ATAGs kernel code is re-used, replacing the ATAGs with a
device-tree blob so that only kexec-tools needs to be changed. There
are two options for generating a dtb to be passed to the kernel from
kexec-tools: 1) Read in the device-tree that is exposed in
/proc/device-tree and flatten this out into a dtb.  2) Allow the user
to specify a dtb file on the command line.  These blobs are then
loaded into memory before the kernel image and the address passed
through to r2, as stated in the ARM booting documentation.

All comments welcome,
Matt

Matthew Leach (4):
  Fix an overflow bug with address comparison
  Move libfdt to a generic location
  Add the dtc for device-tree manipulation
  Add device tree support to the ARM platform

 kexec/arch/arm/Makefile                            |  10 +
 kexec/arch/arm/include/arch/options.h              |   6 +-
 kexec/arch/arm/kexec-zImage-arm.c                  | 140 ++++-
 kexec/arch/ppc/Makefile                            |   8 +-
 kexec/kexec.c                                      |   2 +-
 util_lib/Makefile                                  |   2 +
 util_lib/dtc/Makefile.dtc                          |   9 +
 util_lib/dtc/data.c                                | 321 ++++++++++
 util_lib/dtc/dtc.c                                 |  44 ++
 util_lib/dtc/dtc.h                                 | 244 ++++++++
 util_lib/dtc/flattree.c                            | 649 +++++++++++++++++++++
 util_lib/dtc/fstree.c                              |  91 +++
 util_lib/dtc/livetree.c                            | 579 ++++++++++++++++++
 util_lib/dtc/srcpos.c                              | 252 ++++++++
 util_lib/dtc/srcpos.h                              |  87 +++
 util_lib/dtc/util.c                                |  59 ++
 util_lib/dtc/util.h                                |  56 ++
 util_lib/dtc/version_gen.h                         |   1 +
 .../arch/ppc => util_lib}/libfdt/Makefile.libfdt   |   8 +-
 {kexec/arch/ppc => util_lib}/libfdt/TODO           |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt.c          |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt.h          |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_ro.c       |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_rw.c       |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_strerror.c |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_sw.c       |   0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_wip.c      |   0
 {kexec/arch/ppc => util_lib}/libfdt/libfdt.h       |   0
 {kexec/arch/ppc => util_lib}/libfdt/libfdt_env.h   |   0
 .../arch/ppc => util_lib}/libfdt/libfdt_internal.h |   0
 30 files changed, 2553 insertions(+), 15 deletions(-)
 create mode 100644 util_lib/dtc/Makefile.dtc
 create mode 100644 util_lib/dtc/data.c
 create mode 100644 util_lib/dtc/dtc.c
 create mode 100644 util_lib/dtc/dtc.h
 create mode 100644 util_lib/dtc/flattree.c
 create mode 100644 util_lib/dtc/fstree.c
 create mode 100644 util_lib/dtc/livetree.c
 create mode 100644 util_lib/dtc/srcpos.c
 create mode 100644 util_lib/dtc/srcpos.h
 create mode 100644 util_lib/dtc/util.c
 create mode 100644 util_lib/dtc/util.h
 create mode 100644 util_lib/dtc/version_gen.h
 rename {kexec/arch/ppc => util_lib}/libfdt/Makefile.libfdt (60%)
 rename {kexec/arch/ppc => util_lib}/libfdt/TODO (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt.h (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_ro.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_rw.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_strerror.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_sw.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_wip.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/libfdt.h (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/libfdt_env.h (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/libfdt_internal.h (100%)

-- 
1.7.12


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* [RFC PATCH 1/4] Fix an overflow bug with address comparison
  2012-09-05 11:43 [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Matthew Leach
@ 2012-09-05 11:44 ` Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 2/4] Move libfdt to a generic location Matthew Leach
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Matthew Leach @ 2012-09-05 11:44 UTC (permalink / raw)
  To: kexec; +Cc: Matthew Leach, will.deacon

The variables mstart and mend are assigned the values of
mem_region[i].start and mem_region[i].end which are of the type
unsigned long long. Ensure that mstart and mend are of the same data
type to prevent address overflow.

Signed-off-by: Matthew Leach <matthew.leach@arm.com>
---
 kexec/kexec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kexec/kexec.c b/kexec/kexec.c
index 8928be0..c7b38e3 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -108,7 +108,7 @@ int valid_memory_range(struct kexec_info *info,
 		return 0;
 	}
 	for (i = 0; i < info->memory_ranges; i++) {
-		unsigned long mstart, mend;
+		unsigned long long mstart, mend;
 		/* Only consider memory ranges */
 		if (info->memory_range[i].type != RANGE_RAM)
 			continue;
-- 
1.7.12


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* [RFC PATCH 2/4] Move libfdt to a generic location
  2012-09-05 11:43 [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 1/4] Fix an overflow bug with address comparison Matthew Leach
@ 2012-09-05 11:44 ` Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 3/4] Add the dtc for device-tree manipulation Matthew Leach
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Matthew Leach @ 2012-09-05 11:44 UTC (permalink / raw)
  To: kexec; +Cc: Matthew Leach, will.deacon

Move the libfdt library to a more accessible location for other
architectures and update the ppc makefile to reflect these changes.

Signed-off-by: Matthew Leach <matthew.leach@arm.com>
---
 kexec/arch/ppc/Makefile                               | 8 ++++----
 {kexec/arch/ppc => util_lib}/libfdt/Makefile.libfdt   | 8 ++++----
 {kexec/arch/ppc => util_lib}/libfdt/TODO              | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt.c             | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt.h             | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_ro.c          | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_rw.c          | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_strerror.c    | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_sw.c          | 0
 {kexec/arch/ppc => util_lib}/libfdt/fdt_wip.c         | 0
 {kexec/arch/ppc => util_lib}/libfdt/libfdt.h          | 0
 {kexec/arch/ppc => util_lib}/libfdt/libfdt_env.h      | 0
 {kexec/arch/ppc => util_lib}/libfdt/libfdt_internal.h | 0
 13 files changed, 8 insertions(+), 8 deletions(-)
 rename {kexec/arch/ppc => util_lib}/libfdt/Makefile.libfdt (60%)
 rename {kexec/arch/ppc => util_lib}/libfdt/TODO (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt.h (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_ro.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_rw.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_strerror.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_sw.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/fdt_wip.c (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/libfdt.h (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/libfdt_env.h (100%)
 rename {kexec/arch/ppc => util_lib}/libfdt/libfdt_internal.h (100%)

diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index e868917..38f4257 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -1,7 +1,7 @@
 #
 # kexec ppc (linux booting linux)
 #
-include $(srcdir)/kexec/arch/ppc/libfdt/Makefile.libfdt
+include $(srcdir)/util_lib/libfdt/Makefile.libfdt
 
 ppc_KEXEC_SRCS =  kexec/arch/ppc/kexec-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-ppc.c
@@ -13,14 +13,14 @@ ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/fs2dt.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/crashdump-powerpc.c
+ppc_KEXEC_SRCS += kexec/arch/ppc/libfdt-wrapper.c
 
 ppc_UIMAGE = kexec/kexec-uImage.c
 
-libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c
-libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/arch/ppc/libfdt/%)
+libfdt_SRCS += $(LIBFDT_SRCS:%=util_lib/libfdt/%)
 ppc_ARCH_REUSE_INITRD =
 
-CPPFLAGS+=-I$(srcdir)/kexec/arch/$(ARCH)/libfdt
+CPPFLAGS+=-I$(srcdir)/util_lib/libfdt
 
 ppc_KEXEC_SRCS += $(libfdt_SRCS)
 
diff --git a/kexec/arch/ppc/libfdt/Makefile.libfdt b/util_lib/libfdt/Makefile.libfdt
similarity index 60%
rename from kexec/arch/ppc/libfdt/Makefile.libfdt
rename to util_lib/libfdt/Makefile.libfdt
index 1d1b295..f34595e 100644
--- a/kexec/arch/ppc/libfdt/Makefile.libfdt
+++ b/util_lib/libfdt/Makefile.libfdt
@@ -7,7 +7,7 @@ LIBFDT_INCLUDES = fdt.h libfdt.h
 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)
 
-dist += kexec/arch/ppc/libfdt/Makefile.libfdt				\
-	kexec/arch/ppc/libfdt/fdt.h kexec/arch/ppc/libfdt/libfdt.h	\
-	kexec/arch/ppc/libfdt/libfdt_env.h				\
-	kexec/arch/ppc/libfdt/libfdt_internal.h
+dist += util_lib/libfdt/Makefile.libfdt				\
+	util_lib/libfdt/fdt.h util_lib/libfdt/libfdt.h	\
+	util_lib/libfdt/libfdt_env.h				\
+	util_lib/libfdt/libfdt_internal.h
diff --git a/kexec/arch/ppc/libfdt/TODO b/util_lib/libfdt/TODO
similarity index 100%
rename from kexec/arch/ppc/libfdt/TODO
rename to util_lib/libfdt/TODO
diff --git a/kexec/arch/ppc/libfdt/fdt.c b/util_lib/libfdt/fdt.c
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt.c
rename to util_lib/libfdt/fdt.c
diff --git a/kexec/arch/ppc/libfdt/fdt.h b/util_lib/libfdt/fdt.h
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt.h
rename to util_lib/libfdt/fdt.h
diff --git a/kexec/arch/ppc/libfdt/fdt_ro.c b/util_lib/libfdt/fdt_ro.c
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt_ro.c
rename to util_lib/libfdt/fdt_ro.c
diff --git a/kexec/arch/ppc/libfdt/fdt_rw.c b/util_lib/libfdt/fdt_rw.c
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt_rw.c
rename to util_lib/libfdt/fdt_rw.c
diff --git a/kexec/arch/ppc/libfdt/fdt_strerror.c b/util_lib/libfdt/fdt_strerror.c
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt_strerror.c
rename to util_lib/libfdt/fdt_strerror.c
diff --git a/kexec/arch/ppc/libfdt/fdt_sw.c b/util_lib/libfdt/fdt_sw.c
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt_sw.c
rename to util_lib/libfdt/fdt_sw.c
diff --git a/kexec/arch/ppc/libfdt/fdt_wip.c b/util_lib/libfdt/fdt_wip.c
similarity index 100%
rename from kexec/arch/ppc/libfdt/fdt_wip.c
rename to util_lib/libfdt/fdt_wip.c
diff --git a/kexec/arch/ppc/libfdt/libfdt.h b/util_lib/libfdt/libfdt.h
similarity index 100%
rename from kexec/arch/ppc/libfdt/libfdt.h
rename to util_lib/libfdt/libfdt.h
diff --git a/kexec/arch/ppc/libfdt/libfdt_env.h b/util_lib/libfdt/libfdt_env.h
similarity index 100%
rename from kexec/arch/ppc/libfdt/libfdt_env.h
rename to util_lib/libfdt/libfdt_env.h
diff --git a/kexec/arch/ppc/libfdt/libfdt_internal.h b/util_lib/libfdt/libfdt_internal.h
similarity index 100%
rename from kexec/arch/ppc/libfdt/libfdt_internal.h
rename to util_lib/libfdt/libfdt_internal.h
-- 
1.7.12


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* [RFC PATCH 3/4] Add the dtc for device-tree manipulation
  2012-09-05 11:43 [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 1/4] Fix an overflow bug with address comparison Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 2/4] Move libfdt to a generic location Matthew Leach
@ 2012-09-05 11:44 ` Matthew Leach
  2012-09-05 11:44 ` [RFC PATCH 4/4] Add device tree support to the ARM platform Matthew Leach
  2012-09-05 12:38 ` [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Simon Horman
  4 siblings, 0 replies; 15+ messages in thread
From: Matthew Leach @ 2012-09-05 11:44 UTC (permalink / raw)
  To: kexec; +Cc: Matthew Leach, will.deacon

The dtc includes functions for generating a dtb for the currently
running kernel that is exposed in /proc/device-tree. Include the dtc
so a dtb can be generated for a new kernel without the user having to
obtain a dtb file.

Signed-off-by: Matthew Leach <matthew.leach@arm.com>
---
 util_lib/Makefile          |   2 +
 util_lib/dtc/Makefile.dtc  |   9 +
 util_lib/dtc/data.c        | 321 ++++++++++++++++++++++
 util_lib/dtc/dtc.c         |  44 +++
 util_lib/dtc/dtc.h         | 244 +++++++++++++++++
 util_lib/dtc/flattree.c    | 649 +++++++++++++++++++++++++++++++++++++++++++++
 util_lib/dtc/fstree.c      |  91 +++++++
 util_lib/dtc/livetree.c    | 579 ++++++++++++++++++++++++++++++++++++++++
 util_lib/dtc/srcpos.c      | 252 ++++++++++++++++++
 util_lib/dtc/srcpos.h      |  87 ++++++
 util_lib/dtc/util.c        |  59 +++++
 util_lib/dtc/util.h        |  56 ++++
 util_lib/dtc/version_gen.h |   1 +
 13 files changed, 2394 insertions(+)
 create mode 100644 util_lib/dtc/Makefile.dtc
 create mode 100644 util_lib/dtc/data.c
 create mode 100644 util_lib/dtc/dtc.c
 create mode 100644 util_lib/dtc/dtc.h
 create mode 100644 util_lib/dtc/flattree.c
 create mode 100644 util_lib/dtc/fstree.c
 create mode 100644 util_lib/dtc/livetree.c
 create mode 100644 util_lib/dtc/srcpos.c
 create mode 100644 util_lib/dtc/srcpos.h
 create mode 100644 util_lib/dtc/util.c
 create mode 100644 util_lib/dtc/util.h
 create mode 100644 util_lib/dtc/version_gen.h

diff --git a/util_lib/Makefile b/util_lib/Makefile
index 54ccdc5..8b00944 100644
--- a/util_lib/Makefile
+++ b/util_lib/Makefile
@@ -1,6 +1,8 @@
 #
 # Utility function library
 #
+include $(srcdir)/util_lib/dtc/Makefile.dtc
+
 UTIL_LIB_SRCS +=
 UTIL_LIB_SRCS += util_lib/compute_ip_checksum.c
 UTIL_LIB_SRCS += util_lib/sha256.c
diff --git a/util_lib/dtc/Makefile.dtc b/util_lib/dtc/Makefile.dtc
new file mode 100644
index 0000000..3433d76
--- /dev/null
+++ b/util_lib/dtc/Makefile.dtc
@@ -0,0 +1,9 @@
+DTC_INCLUDES = dtc.h srcpos.h util.h version_gen.h
+DTC_SRCS = fstree.c flattree.c srcpos.c util.c livetree.c data.c dtc.c
+DTC_OBJS = $(DTC_SRCS:%.c=%.o)
+
+CPPFLAGS += -I$(srcdir)/util_lib/dtc/
+
+dist += util_lib/dtc/Makefile.dtc \
+        $(DTC_SRCS:%=util_lib/dtc/%) \
+        $(DTC_INCLUDES:%=util_lib/dtc/%)
\ No newline at end of file
diff --git a/util_lib/dtc/data.c b/util_lib/dtc/data.c
new file mode 100644
index 0000000..fe555e8
--- /dev/null
+++ b/util_lib/dtc/data.c
@@ -0,0 +1,321 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ *
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include "dtc.h"
+
+void data_free(struct data d)
+{
+	struct marker *m, *nm;
+
+	m = d.markers;
+	while (m) {
+		nm = m->next;
+		free(m->ref);
+		free(m);
+		m = nm;
+	}
+
+	if (d.val)
+		free(d.val);
+}
+
+struct data data_grow_for(struct data d, int xlen)
+{
+	struct data nd;
+	int newsize;
+
+	if (xlen == 0)
+		return d;
+
+	nd = d;
+
+	newsize = xlen;
+
+	while ((d.len + xlen) > newsize)
+		newsize *= 2;
+
+	nd.val = xrealloc(d.val, newsize);
+
+	return nd;
+}
+
+struct data data_copy_mem(const char *mem, int len)
+{
+	struct data d;
+
+	d = data_grow_for(empty_data, len);
+
+	d.len = len;
+	memcpy(d.val, mem, len);
+
+	return d;
+}
+
+static char get_oct_char(const char *s, int *i)
+{
+	char x[4];
+	char *endx;
+	long val;
+
+	x[3] = '\0';
+	strncpy(x, s + *i, 3);
+
+	val = strtol(x, &endx, 8);
+
+	assert(endx > x);
+
+	(*i) += endx - x;
+	return val;
+}
+
+static char get_hex_char(const char *s, int *i)
+{
+	char x[3];
+	char *endx;
+	long val;
+
+	x[2] = '\0';
+	strncpy(x, s + *i, 2);
+
+	val = strtol(x, &endx, 16);
+	if (!(endx  > x))
+		die("\\x used with no following hex digits\n");
+
+	(*i) += endx - x;
+	return val;
+}
+
+struct data data_copy_escape_string(const char *s, int len)
+{
+	int i = 0;
+	struct data d;
+	char *q;
+
+	d = data_grow_for(empty_data, strlen(s)+1);
+
+	q = d.val;
+	while (i < len) {
+		char c = s[i++];
+
+		if (c != '\\') {
+			q[d.len++] = c;
+			continue;
+		}
+
+		c = s[i++];
+		assert(c);
+		switch (c) {
+		case 'a':
+			q[d.len++] = '\a';
+			break;
+		case 'b':
+			q[d.len++] = '\b';
+			break;
+		case 't':
+			q[d.len++] = '\t';
+			break;
+		case 'n':
+			q[d.len++] = '\n';
+			break;
+		case 'v':
+			q[d.len++] = '\v';
+			break;
+		case 'f':
+			q[d.len++] = '\f';
+			break;
+		case 'r':
+			q[d.len++] = '\r';
+			break;
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+			i--; /* need to re-read the first digit as
+			      * part of the octal value */
+			q[d.len++] = get_oct_char(s, &i);
+			break;
+		case 'x':
+			q[d.len++] = get_hex_char(s, &i);
+			break;
+		default:
+			q[d.len++] = c;
+		}
+	}
+
+	q[d.len++] = '\0';
+	return d;
+}
+
+struct data data_copy_file(FILE *f, size_t maxlen)
+{
+	struct data d = empty_data;
+
+	while (!feof(f) && (d.len < maxlen)) {
+		size_t chunksize, ret;
+
+		if (maxlen == -1)
+			chunksize = 4096;
+		else
+			chunksize = maxlen - d.len;
+
+		d = data_grow_for(d, chunksize);
+		ret = fread(d.val + d.len, 1, chunksize, f);
+
+		if (ferror(f))
+			die("Error reading file into data: %s", strerror(errno));
+
+		if (d.len + ret < d.len)
+			die("Overflow reading file into data\n");
+
+		d.len += ret;
+	}
+
+	return d;
+}
+
+struct data data_append_data(struct data d, const void *p, int len)
+{
+	d = data_grow_for(d, len);
+	memcpy(d.val + d.len, p, len);
+	d.len += len;
+	return d;
+}
+
+struct data data_insert_at_marker(struct data d, struct marker *m,
+				  const void *p, int len)
+{
+	d = data_grow_for(d, len);
+	memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
+	memcpy(d.val + m->offset, p, len);
+	d.len += len;
+
+	/* Adjust all markers after the one we're inserting at */
+	m = m->next;
+	for_each_marker(m)
+		m->offset += len;
+	return d;
+}
+
+static struct data data_append_markers(struct data d, struct marker *m)
+{
+	struct marker **mp = &d.markers;
+
+	/* Find the end of the markerlist */
+	while (*mp)
+		mp = &((*mp)->next);
+	*mp = m;
+	return d;
+}
+
+struct data data_merge(struct data d1, struct data d2)
+{
+	struct data d;
+	struct marker *m2 = d2.markers;
+
+	d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
+
+	/* Adjust for the length of d1 */
+	for_each_marker(m2)
+		m2->offset += d1.len;
+
+	d2.markers = NULL; /* So data_free() doesn't clobber them */
+	data_free(d2);
+
+	return d;
+}
+
+struct data data_append_cell(struct data d, cell_t word)
+{
+	cell_t beword = cpu_to_fdt32(word);
+
+	return data_append_data(d, &beword, sizeof(beword));
+}
+
+struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
+{
+	struct fdt_reserve_entry bere;
+
+	bere.address = cpu_to_fdt64(re->address);
+	bere.size = cpu_to_fdt64(re->size);
+
+	return data_append_data(d, &bere, sizeof(bere));
+}
+
+struct data data_append_addr(struct data d, uint64_t addr)
+{
+	uint64_t beaddr = cpu_to_fdt64(addr);
+
+	return data_append_data(d, &beaddr, sizeof(beaddr));
+}
+
+struct data data_append_byte(struct data d, uint8_t byte)
+{
+	return data_append_data(d, &byte, 1);
+}
+
+struct data data_append_zeroes(struct data d, int len)
+{
+	d = data_grow_for(d, len);
+
+	memset(d.val + d.len, 0, len);
+	d.len += len;
+	return d;
+}
+
+struct data data_append_align(struct data d, int align)
+{
+	int newlen = ALIGN(d.len, align);
+	return data_append_zeroes(d, newlen - d.len);
+}
+
+struct data data_add_marker(struct data d, enum markertype type, char *ref)
+{
+	struct marker *m;
+
+	m = xmalloc(sizeof(*m));
+	m->offset = d.len;
+	m->type = type;
+	m->ref = ref;
+	m->next = NULL;
+
+	return data_append_markers(d, m);
+}
+
+int data_is_one_string(struct data d)
+{
+	int i;
+	int len = d.len;
+
+	if (len == 0)
+		return 0;
+
+	for (i = 0; i < len-1; i++)
+		if (d.val[i] == '\0')
+			return 0;
+
+	if (d.val[len-1] != '\0')
+		return 0;
+
+	return 1;
+}
diff --git a/util_lib/dtc/dtc.c b/util_lib/dtc/dtc.c
new file mode 100644
index 0000000..b812dfc
--- /dev/null
+++ b/util_lib/dtc/dtc.c
@@ -0,0 +1,44 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ *
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include "dtc.h"
+#include "srcpos.h"
+
+#include "version_gen.h"
+
+static void fill_fullpaths(struct node *tree, const char *prefix)
+{
+	struct node *child;
+	const char *unit;
+
+	tree->fullpath = join_path(prefix, tree->name);
+
+	unit = strchr(tree->name, '@');
+	if (unit)
+		tree->basenamelen = unit - tree->name;
+	else
+		tree->basenamelen = strlen(tree->name);
+
+	for_each_child(tree, child)
+		fill_fullpaths(child, tree->fullpath);
+}
+
+
+
diff --git a/util_lib/dtc/dtc.h b/util_lib/dtc/dtc.h
new file mode 100644
index 0000000..afb26f6
--- /dev/null
+++ b/util_lib/dtc/dtc.h
@@ -0,0 +1,244 @@
+#ifndef _DTC_H
+#define _DTC_H
+
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ *
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#include "util.h"
+
+#ifdef DEBUG
+#define debug(fmt,args...)	printf(fmt, ##args)
+#else
+#define debug(fmt,args...)
+#endif
+
+
+#define DEFAULT_FDT_VERSION	17
+
+/*
+ * Command line options
+ */
+extern int quiet;		/* Level of quietness */
+extern int reservenum;		/* Number of memory reservation slots */
+extern int minsize;		/* Minimum blob size */
+extern int padsize;		/* Additional padding to blob */
+extern int phandle_format;	/* Use linux,phandle or phandle properties */
+
+#define PHANDLE_LEGACY	0x1
+#define PHANDLE_EPAPR	0x2
+#define PHANDLE_BOTH	0x3
+
+typedef uint32_t cell_t;
+
+
+#define streq(a, b)	(strcmp((a), (b)) == 0)
+#define strneq(a, b, n)	(strncmp((a), (b), (n)) == 0)
+
+#define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/* Data blobs */
+enum markertype {
+	REF_PHANDLE,
+	REF_PATH,
+	LABEL,
+};
+
+struct  marker {
+	enum markertype type;
+	int offset;
+	char *ref;
+	struct marker *next;
+};
+
+struct data {
+	int len;
+	char *val;
+	struct marker *markers;
+};
+
+
+#define empty_data ((struct data){ /* all .members = 0 or NULL */ })
+
+#define for_each_marker(m) \
+	for (; (m); (m) = (m)->next)
+#define for_each_marker_of_type(m, t) \
+	for_each_marker(m) \
+		if ((m)->type == (t))
+
+void data_free(struct data d);
+
+struct data data_grow_for(struct data d, int xlen);
+
+struct data data_copy_mem(const char *mem, int len);
+struct data data_copy_escape_string(const char *s, int len);
+struct data data_copy_file(FILE *f, size_t len);
+
+struct data data_append_data(struct data d, const void *p, int len);
+struct data data_insert_at_marker(struct data d, struct marker *m,
+				  const void *p, int len);
+struct data data_merge(struct data d1, struct data d2);
+struct data data_append_cell(struct data d, cell_t word);
+struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
+struct data data_append_addr(struct data d, uint64_t addr);
+struct data data_append_byte(struct data d, uint8_t byte);
+struct data data_append_zeroes(struct data d, int len);
+struct data data_append_align(struct data d, int align);
+
+struct data data_add_marker(struct data d, enum markertype type, char *ref);
+
+int data_is_one_string(struct data d);
+
+/* DT constraints */
+
+#define MAX_PROPNAME_LEN	31
+#define MAX_NODENAME_LEN	31
+
+/* Live trees */
+struct label {
+	char *label;
+	struct label *next;
+};
+
+struct property {
+	char *name;
+	struct data val;
+
+	struct property *next;
+
+	struct label *labels;
+};
+
+struct node {
+	char *name;
+	struct property *proplist;
+	struct node *children;
+
+	struct node *parent;
+	struct node *next_sibling;
+
+	char *fullpath;
+	int basenamelen;
+
+	cell_t phandle;
+	int addr_cells, size_cells;
+
+	struct label *labels;
+};
+
+#define for_each_label(l0, l) \
+	for ((l) = (l0); (l); (l) = (l)->next)
+
+#define for_each_property(n, p) \
+	for ((p) = (n)->proplist; (p); (p) = (p)->next)
+
+#define for_each_child(n, c)	\
+	for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
+
+void add_label(struct label **labels, char *label);
+
+struct property *build_property(char *name, struct data val);
+struct property *chain_property(struct property *first, struct property *list);
+struct property *reverse_properties(struct property *first);
+
+struct node *build_node(struct property *proplist, struct node *children);
+struct node *name_node(struct node *node, char *name);
+struct node *chain_node(struct node *first, struct node *list);
+struct node *merge_nodes(struct node *old_node, struct node *new_node);
+
+void add_property(struct node *node, struct property *prop);
+void add_child(struct node *parent, struct node *child);
+
+const char *get_unitname(struct node *node);
+struct property *get_property(struct node *node, const char *propname);
+cell_t propval_cell(struct property *prop);
+struct property *get_property_by_label(struct node *tree, const char *label,
+				       struct node **node);
+struct marker *get_marker_label(struct node *tree, const char *label,
+				struct node **node, struct property **prop);
+struct node *get_subnode(struct node *node, const char *nodename);
+struct node *get_node_by_path(struct node *tree, const char *path);
+struct node *get_node_by_label(struct node *tree, const char *label);
+struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
+struct node *get_node_by_ref(struct node *tree, const char *ref);
+cell_t get_node_phandle(struct node *root, struct node *node);
+
+uint32_t guess_boot_cpuid(struct node *tree);
+
+/* Boot info (tree plus memreserve information */
+
+struct reserve_info {
+	struct fdt_reserve_entry re;
+
+	struct reserve_info *next;
+
+	struct label *labels;
+};
+
+struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
+struct reserve_info *chain_reserve_entry(struct reserve_info *first,
+					 struct reserve_info *list);
+struct reserve_info *add_reserve_entry(struct reserve_info *list,
+				       struct reserve_info *new);
+
+
+struct boot_info {
+	struct reserve_info *reservelist;
+	struct node *dt;		/* the device tree */
+	uint32_t boot_cpuid_phys;
+};
+
+struct boot_info *build_boot_info(struct reserve_info *reservelist,
+				  struct node *tree, uint32_t boot_cpuid_phys);
+void sort_tree(struct boot_info *bi);
+
+/* Checks */
+
+void process_checks(int force, struct boot_info *bi);
+
+/* Flattened trees */
+
+void* dt_to_blob_buf(off_t* size, struct boot_info *bi, int version);
+
+struct boot_info *dt_from_blob(const char *fname);
+
+/* Tree source */
+
+void dt_to_source(FILE *f, struct boot_info *bi);
+struct boot_info *dt_from_source(const char *f);
+
+/* FS trees */
+
+struct boot_info *dt_from_fs(const char *dirname);
+
+#endif /* _DTC_H */
diff --git a/util_lib/dtc/flattree.c b/util_lib/dtc/flattree.c
new file mode 100644
index 0000000..d110001
--- /dev/null
+++ b/util_lib/dtc/flattree.c
@@ -0,0 +1,649 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ *
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include "dtc.h"
+#include "srcpos.h"
+
+#define FTF_FULLPATH	0x1
+#define FTF_VARALIGN	0x2
+#define FTF_NAMEPROPS	0x4
+#define FTF_BOOTCPUID	0x8
+#define FTF_STRTABSIZE	0x10
+#define FTF_STRUCTSIZE	0x20
+#define FTF_NOPS	0x40
+
+static struct version_info {
+	int version;
+	int last_comp_version;
+	int hdr_size;
+	int flags;
+} version_table[] = {
+	{1, 1, FDT_V1_SIZE,
+	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
+	{2, 1, FDT_V2_SIZE,
+	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
+	{3, 1, FDT_V3_SIZE,
+	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
+	{16, 16, FDT_V3_SIZE,
+	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
+	{17, 16, FDT_V17_SIZE,
+	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
+};
+
+struct emitter {
+	void (*cell)(void *, cell_t);
+	void (*string)(void *, char *, int);
+	void (*align)(void *, int);
+	void (*data)(void *, struct data);
+	void (*beginnode)(void *, struct label *labels);
+	void (*endnode)(void *, struct label *labels);
+	void (*property)(void *, struct label *labels);
+};
+
+static void bin_emit_cell(void *e, cell_t val)
+{
+	struct data *dtbuf = e;
+
+	*dtbuf = data_append_cell(*dtbuf, val);
+}
+
+static void bin_emit_string(void *e, char *str, int len)
+{
+	struct data *dtbuf = e;
+
+	if (len == 0)
+		len = strlen(str);
+
+	*dtbuf = data_append_data(*dtbuf, str, len);
+	*dtbuf = data_append_byte(*dtbuf, '\0');
+}
+
+static void bin_emit_align(void *e, int a)
+{
+	struct data *dtbuf = e;
+
+	*dtbuf = data_append_align(*dtbuf, a);
+}
+
+static void bin_emit_data(void *e, struct data d)
+{
+	struct data *dtbuf = e;
+
+	*dtbuf = data_append_data(*dtbuf, d.val, d.len);
+}
+
+static void bin_emit_beginnode(void *e, struct label *labels)
+{
+	bin_emit_cell(e, FDT_BEGIN_NODE);
+}
+
+static void bin_emit_endnode(void *e, struct label *labels)
+{
+	bin_emit_cell(e, FDT_END_NODE);
+}
+
+static void bin_emit_property(void *e, struct label *labels)
+{
+	bin_emit_cell(e, FDT_PROP);
+}
+
+static struct emitter bin_emitter = {
+	.cell = bin_emit_cell,
+	.string = bin_emit_string,
+	.align = bin_emit_align,
+	.data = bin_emit_data,
+	.beginnode = bin_emit_beginnode,
+	.endnode = bin_emit_endnode,
+	.property = bin_emit_property,
+};
+
+
+#define ASM_EMIT_BELONG(f, fmt, ...) \
+	{ \
+		fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
+		fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
+		fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
+		fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
+	}
+
+
+
+
+static int stringtable_insert(struct data *d, const char *str)
+{
+	int i;
+
+	/* FIXME: do this more efficiently? */
+
+	for (i = 0; i < d->len; i++) {
+		if (streq(str, d->val + i))
+			return i;
+	}
+
+	*d = data_append_data(*d, str, strlen(str)+1);
+	return i;
+}
+
+static void flatten_tree(struct node *tree, struct emitter *emit,
+			 void *etarget, struct data *strbuf,
+			 struct version_info *vi)
+{
+	struct property *prop;
+	struct node *child;
+	int seen_name_prop = 0;
+
+	emit->beginnode(etarget, tree->labels);
+
+	if (vi->flags & FTF_FULLPATH)
+		emit->string(etarget, tree->fullpath, 0);
+	else
+		emit->string(etarget, tree->name, 0);
+
+	emit->align(etarget, sizeof(cell_t));
+
+	for_each_property(tree, prop) {
+		int nameoff;
+
+		if (streq(prop->name, "name"))
+			seen_name_prop = 1;
+
+		nameoff = stringtable_insert(strbuf, prop->name);
+
+		emit->property(etarget, prop->labels);
+		emit->cell(etarget, prop->val.len);
+		emit->cell(etarget, nameoff);
+
+		if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
+			emit->align(etarget, 8);
+
+		emit->data(etarget, prop->val);
+		emit->align(etarget, sizeof(cell_t));
+	}
+
+	if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
+		emit->property(etarget, NULL);
+		emit->cell(etarget, tree->basenamelen+1);
+		emit->cell(etarget, stringtable_insert(strbuf, "name"));
+
+		if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
+			emit->align(etarget, 8);
+
+		emit->string(etarget, tree->name, tree->basenamelen);
+		emit->align(etarget, sizeof(cell_t));
+	}
+
+	for_each_child(tree, child) {
+		flatten_tree(child, emit, etarget, strbuf, vi);
+	}
+
+	emit->endnode(etarget, tree->labels);
+}
+
+static struct data flatten_reserve_list(struct reserve_info *reservelist,
+				 struct version_info *vi)
+{
+	struct reserve_info *re;
+	struct data d = empty_data;
+
+	for (re = reservelist; re; re = re->next) {
+		d = data_append_re(d, &re->re);
+	}
+
+	return d;
+}
+
+static void make_fdt_header(struct fdt_header *fdt,
+			    struct version_info *vi,
+			    int reservesize, int dtsize, int strsize,
+			    int boot_cpuid_phys)
+{
+	int reserve_off;
+
+	reservesize += sizeof(struct fdt_reserve_entry);
+
+	memset(fdt, 0xff, sizeof(*fdt));
+
+	fdt->magic = cpu_to_fdt32(FDT_MAGIC);
+	fdt->version = cpu_to_fdt32(vi->version);
+	fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
+
+	/* Reserve map should be doubleword aligned */
+	reserve_off = ALIGN(vi->hdr_size, 8);
+
+	fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
+	fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
+	fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
+					  + dtsize);
+	fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
+
+	if (vi->flags & FTF_BOOTCPUID)
+		fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
+	if (vi->flags & FTF_STRTABSIZE)
+		fdt->size_dt_strings = cpu_to_fdt32(strsize);
+	if (vi->flags & FTF_STRUCTSIZE)
+		fdt->size_dt_struct = cpu_to_fdt32(dtsize);
+}
+
+void* dt_to_blob_buf(off_t* size, struct boot_info *bi, int version)
+{
+	struct version_info *vi = NULL;
+	int i;
+	struct data blob       = empty_data;
+	struct data reservebuf = empty_data;
+	struct data dtbuf      = empty_data;
+	struct data strbuf     = empty_data;
+	struct fdt_header fdt;
+	int padlen = 0;
+
+	for (i = 0; i < ARRAY_SIZE(version_table); i++) {
+		if (version_table[i].version == version)
+			vi = &version_table[i];
+	}
+
+	if (!vi)
+		die("Unknown device tree blob version %d\n", version);
+
+	flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+	bin_emit_cell(&dtbuf, FDT_END);
+
+	reservebuf = flatten_reserve_list(bi->reservelist, vi);
+
+	/* Make header */
+	make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
+			bi->boot_cpuid_phys);
+
+	if (padlen > 0) {
+		int tsize = fdt32_to_cpu(fdt.totalsize);
+		tsize += padlen;
+		fdt.totalsize = cpu_to_fdt32(tsize);
+	}
+
+	/*
+	 * Assemble the blob: start with the header, add with alignment
+	 * the reserve buffer, add the reserve map terminating zeroes,
+	 * the device tree itself, and finally the strings.
+	 */
+	blob = data_append_data(blob, &fdt, vi->hdr_size);
+	blob = data_append_align(blob, 8);
+	blob = data_merge(blob, reservebuf);
+	blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
+	blob = data_merge(blob, dtbuf);
+	blob = data_merge(blob, strbuf);
+
+	*size = blob.len;
+
+	return blob.val;
+}
+
+
+struct inbuf {
+	char *base, *limit, *ptr;
+};
+
+static void inbuf_init(struct inbuf *inb, void *base, void *limit)
+{
+	inb->base = base;
+	inb->limit = limit;
+	inb->ptr = inb->base;
+}
+
+static void flat_read_chunk(struct inbuf *inb, void *p, int len)
+{
+	if ((inb->ptr + len) > inb->limit)
+		die("Premature end of data parsing flat device tree\n");
+
+	memcpy(p, inb->ptr, len);
+
+	inb->ptr += len;
+}
+
+static uint32_t flat_read_word(struct inbuf *inb)
+{
+	uint32_t val;
+
+	assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
+
+	flat_read_chunk(inb, &val, sizeof(val));
+
+	return fdt32_to_cpu(val);
+}
+
+static void flat_realign(struct inbuf *inb, int align)
+{
+	int off = inb->ptr - inb->base;
+
+	inb->ptr = inb->base + ALIGN(off, align);
+	if (inb->ptr > inb->limit)
+		die("Premature end of data parsing flat device tree\n");
+}
+
+static char *flat_read_string(struct inbuf *inb)
+{
+	int len = 0;
+	const char *p = inb->ptr;
+	char *str;
+
+	do {
+		if (p >= inb->limit)
+			die("Premature end of data parsing flat device tree\n");
+		len++;
+	} while ((*p++) != '\0');
+
+	str = xstrdup(inb->ptr);
+
+	inb->ptr += len;
+
+	flat_realign(inb, sizeof(uint32_t));
+
+	return str;
+}
+
+static struct data flat_read_data(struct inbuf *inb, int len)
+{
+	struct data d = empty_data;
+
+	if (len == 0)
+		return empty_data;
+
+	d = data_grow_for(d, len);
+	d.len = len;
+
+	flat_read_chunk(inb, d.val, len);
+
+	flat_realign(inb, sizeof(uint32_t));
+
+	return d;
+}
+
+static char *flat_read_stringtable(struct inbuf *inb, int offset)
+{
+	const char *p;
+
+	p = inb->base + offset;
+	while (1) {
+		if (p >= inb->limit || p < inb->base)
+			die("String offset %d overruns string table\n",
+			    offset);
+
+		if (*p == '\0')
+			break;
+
+		p++;
+	}
+
+	return xstrdup(inb->base + offset);
+}
+
+static struct property *flat_read_property(struct inbuf *dtbuf,
+					   struct inbuf *strbuf, int flags)
+{
+	uint32_t proplen, stroff;
+	char *name;
+	struct data val;
+
+	proplen = flat_read_word(dtbuf);
+	stroff = flat_read_word(dtbuf);
+
+	name = flat_read_stringtable(strbuf, stroff);
+
+	if ((flags & FTF_VARALIGN) && (proplen >= 8))
+		flat_realign(dtbuf, 8);
+
+	val = flat_read_data(dtbuf, proplen);
+
+	return build_property(name, val);
+}
+
+
+static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
+{
+	struct reserve_info *reservelist = NULL;
+	struct reserve_info *new;
+	struct fdt_reserve_entry re;
+
+	/*
+	 * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
+	 * List terminates at an entry with size equal to zero.
+	 *
+	 * First pass, count entries.
+	 */
+	while (1) {
+		flat_read_chunk(inb, &re, sizeof(re));
+		re.address  = fdt64_to_cpu(re.address);
+		re.size = fdt64_to_cpu(re.size);
+		if (re.size == 0)
+			break;
+
+		new = build_reserve_entry(re.address, re.size);
+		reservelist = add_reserve_entry(reservelist, new);
+	}
+
+	return reservelist;
+}
+
+
+static char *nodename_from_path(const char *ppath, const char *cpath)
+{
+	int plen;
+
+	plen = strlen(ppath);
+
+	if (!strneq(ppath, cpath, plen))
+		die("Path \"%s\" is not valid as a child of \"%s\"\n",
+		    cpath, ppath);
+
+	/* root node is a special case */
+	if (!streq(ppath, "/"))
+		plen++;
+
+	return xstrdup(cpath + plen);
+}
+
+static struct node *unflatten_tree(struct inbuf *dtbuf,
+				   struct inbuf *strbuf,
+				   const char *parent_flatname, int flags)
+{
+	struct node *node;
+	char *flatname;
+	uint32_t val;
+
+	node = build_node(NULL, NULL);
+
+	flatname = flat_read_string(dtbuf);
+
+	if (flags & FTF_FULLPATH)
+		node->name = nodename_from_path(parent_flatname, flatname);
+	else
+		node->name = flatname;
+
+	do {
+		struct property *prop;
+		struct node *child;
+
+		val = flat_read_word(dtbuf);
+		switch (val) {
+		case FDT_PROP:
+			if (node->children)
+				fprintf(stderr, "Warning: Flat tree input has "
+					"subnodes preceding a property.\n");
+			prop = flat_read_property(dtbuf, strbuf, flags);
+			add_property(node, prop);
+			break;
+
+		case FDT_BEGIN_NODE:
+			child = unflatten_tree(dtbuf,strbuf, flatname, flags);
+			add_child(node, child);
+			break;
+
+		case FDT_END_NODE:
+			break;
+
+		case FDT_END:
+			die("Premature FDT_END in device tree blob\n");
+			break;
+
+		case FDT_NOP:
+			if (!(flags & FTF_NOPS))
+				fprintf(stderr, "Warning: NOP tag found in flat tree"
+					" version <16\n");
+
+			/* Ignore */
+			break;
+
+		default:
+			die("Invalid opcode word %08x in device tree blob\n",
+			    val);
+		}
+	} while (val != FDT_END_NODE);
+
+	return node;
+}
+
+
+struct boot_info *dt_from_blob(const char *fname)
+{
+	FILE *f;
+	uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
+	uint32_t off_dt, off_str, off_mem_rsvmap;
+	int rc;
+	char *blob;
+	struct fdt_header *fdt;
+	char *p;
+	struct inbuf dtbuf, strbuf;
+	struct inbuf memresvbuf;
+	int sizeleft;
+	struct reserve_info *reservelist;
+	struct node *tree;
+	uint32_t val;
+	int flags = 0;
+
+	f = srcfile_relative_open(fname, NULL);
+
+	rc = fread(&magic, sizeof(magic), 1, f);
+	if (ferror(f))
+		die("Error reading DT blob magic number: %s\n",
+		    strerror(errno));
+	if (rc < 1) {
+		if (feof(f))
+			die("EOF reading DT blob magic number\n");
+		else
+			die("Mysterious short read reading magic number\n");
+	}
+
+	magic = fdt32_to_cpu(magic);
+	if (magic != FDT_MAGIC)
+		die("Blob has incorrect magic number\n");
+
+	rc = fread(&totalsize, sizeof(totalsize), 1, f);
+	if (ferror(f))
+		die("Error reading DT blob size: %s\n", strerror(errno));
+	if (rc < 1) {
+		if (feof(f))
+			die("EOF reading DT blob size\n");
+		else
+			die("Mysterious short read reading blob size\n");
+	}
+
+	totalsize = fdt32_to_cpu(totalsize);
+	if (totalsize < FDT_V1_SIZE)
+		die("DT blob size (%d) is too small\n", totalsize);
+
+	blob = xmalloc(totalsize);
+
+	fdt = (struct fdt_header *)blob;
+	fdt->magic = cpu_to_fdt32(magic);
+	fdt->totalsize = cpu_to_fdt32(totalsize);
+
+	sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
+	p = blob + sizeof(magic)  + sizeof(totalsize);
+
+	while (sizeleft) {
+		if (feof(f))
+			die("EOF before reading %d bytes of DT blob\n",
+			    totalsize);
+
+		rc = fread(p, 1, sizeleft, f);
+		if (ferror(f))
+			die("Error reading DT blob: %s\n",
+			    strerror(errno));
+
+		sizeleft -= rc;
+		p += rc;
+	}
+
+	off_dt = fdt32_to_cpu(fdt->off_dt_struct);
+	off_str = fdt32_to_cpu(fdt->off_dt_strings);
+	off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
+	version = fdt32_to_cpu(fdt->version);
+	boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
+
+	if (off_mem_rsvmap >= totalsize)
+		die("Mem Reserve structure offset exceeds total size\n");
+
+	if (off_dt >= totalsize)
+		die("DT structure offset exceeds total size\n");
+
+	if (off_str > totalsize)
+		die("String table offset exceeds total size\n");
+
+	if (version >= 3) {
+		uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
+		if (off_str+size_str > totalsize)
+			die("String table extends past total size\n");
+		inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
+	} else {
+		inbuf_init(&strbuf, blob + off_str, blob + totalsize);
+	}
+
+	if (version >= 17) {
+		size_dt = fdt32_to_cpu(fdt->size_dt_struct);
+		if (off_dt+size_dt > totalsize)
+			die("Structure block extends past total size\n");
+	}
+
+	if (version < 16) {
+		flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
+	} else {
+		flags |= FTF_NOPS;
+	}
+
+	inbuf_init(&memresvbuf,
+		   blob + off_mem_rsvmap, blob + totalsize);
+	inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
+
+	reservelist = flat_read_mem_reserve(&memresvbuf);
+
+	val = flat_read_word(&dtbuf);
+
+	if (val != FDT_BEGIN_NODE)
+		die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
+
+	tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
+
+	val = flat_read_word(&dtbuf);
+	if (val != FDT_END)
+		die("Device tree blob doesn't end with FDT_END\n");
+
+	free(blob);
+
+	fclose(f);
+
+	return build_boot_info(reservelist, tree, boot_cpuid_phys);
+}
diff --git a/util_lib/dtc/fstree.c b/util_lib/dtc/fstree.c
new file mode 100644
index 0000000..f377453
--- /dev/null
+++ b/util_lib/dtc/fstree.c
@@ -0,0 +1,91 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ *
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include "dtc.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+static struct node *read_fstree(const char *dirname)
+{
+	DIR *d;
+	struct dirent *de;
+	struct stat st;
+	struct node *tree;
+
+	d = opendir(dirname);
+	if (!d)
+		die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
+
+	tree = build_node(NULL, NULL);
+
+	while ((de = readdir(d)) != NULL) {
+		char *tmpnam;
+
+		if (streq(de->d_name, ".")
+		    || streq(de->d_name, ".."))
+			continue;
+
+		tmpnam = join_path(dirname, de->d_name);
+
+		if (lstat(tmpnam, &st) < 0)
+			die("stat(%s): %s\n", tmpnam, strerror(errno));
+
+		if (S_ISREG(st.st_mode)) {
+			struct property *prop;
+			FILE *pfile;
+
+			pfile = fopen(tmpnam, "r");
+			if (! pfile) {
+				fprintf(stderr,
+					"WARNING: Cannot open %s: %s\n",
+					tmpnam, strerror(errno));
+			} else {
+				prop = build_property(xstrdup(de->d_name),
+						      data_copy_file(pfile,
+								     st.st_size));
+				add_property(tree, prop);
+				fclose(pfile);
+			}
+		} else if (S_ISDIR(st.st_mode)) {
+			struct node *newchild;
+
+			newchild = read_fstree(tmpnam);
+			newchild = name_node(newchild, xstrdup(de->d_name));
+			add_child(tree, newchild);
+		}
+
+		free(tmpnam);
+	}
+
+	closedir(d);
+	return tree;
+}
+
+struct boot_info *dt_from_fs(const char *dirname)
+{
+	struct node *tree;
+
+	tree = read_fstree(dirname);
+	tree = name_node(tree, "");
+
+	return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
+}
+
diff --git a/util_lib/dtc/livetree.c b/util_lib/dtc/livetree.c
new file mode 100644
index 0000000..1420804
--- /dev/null
+++ b/util_lib/dtc/livetree.c
@@ -0,0 +1,579 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
+ *
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include "dtc.h"
+
+/*
+ * Tree building functions
+ */
+
+void add_label(struct label **labels, char *label)
+{
+	struct label *new;
+
+	/* Make sure the label isn't already there */
+	for_each_label(*labels, new)
+		if (streq(new->label, label))
+			return;
+
+	new = xmalloc(sizeof(*new));
+	new->label = label;
+	new->next = *labels;
+	*labels = new;
+}
+
+struct property *build_property(char *name, struct data val)
+{
+	struct property *new = xmalloc(sizeof(*new));
+
+	memset(new, 0, sizeof(*new));
+
+	new->name = name;
+	new->val = val;
+
+	return new;
+}
+
+struct property *chain_property(struct property *first, struct property *list)
+{
+	assert(first->next == NULL);
+
+	first->next = list;
+	return first;
+}
+
+struct property *reverse_properties(struct property *first)
+{
+	struct property *p = first;
+	struct property *head = NULL;
+	struct property *next;
+
+	while (p) {
+		next = p->next;
+		p->next = head;
+		head = p;
+		p = next;
+	}
+	return head;
+}
+
+struct node *build_node(struct property *proplist, struct node *children)
+{
+	struct node *new = xmalloc(sizeof(*new));
+	struct node *child;
+
+	memset(new, 0, sizeof(*new));
+
+	new->proplist = reverse_properties(proplist);
+	new->children = children;
+
+	for_each_child(new, child) {
+		child->parent = new;
+	}
+
+	return new;
+}
+
+struct node *name_node(struct node *node, char *name)
+{
+	assert(node->name == NULL);
+
+	node->name = name;
+
+	return node;
+}
+
+struct node *merge_nodes(struct node *old_node, struct node *new_node)
+{
+	struct property *new_prop, *old_prop;
+	struct node *new_child, *old_child;
+	struct label *l;
+
+	/* Add new node labels to old node */
+	for_each_label(new_node->labels, l)
+		add_label(&old_node->labels, l->label);
+
+	/* Move properties from the new node to the old node.  If there
+	 * is a collision, replace the old value with the new */
+	while (new_node->proplist) {
+		/* Pop the property off the list */
+		new_prop = new_node->proplist;
+		new_node->proplist = new_prop->next;
+		new_prop->next = NULL;
+
+		/* Look for a collision, set new value if there is */
+		for_each_property(old_node, old_prop) {
+			if (streq(old_prop->name, new_prop->name)) {
+				/* Add new labels to old property */
+				for_each_label(new_prop->labels, l)
+					add_label(&old_prop->labels, l->label);
+
+				old_prop->val = new_prop->val;
+				free(new_prop);
+				new_prop = NULL;
+				break;
+			}
+		}
+
+		/* if no collision occurred, add property to the old node. */
+		if (new_prop)
+			add_property(old_node, new_prop);
+	}
+
+	/* Move the override child nodes into the primary node.  If
+	 * there is a collision, then merge the nodes. */
+	while (new_node->children) {
+		/* Pop the child node off the list */
+		new_child = new_node->children;
+		new_node->children = new_child->next_sibling;
+		new_child->parent = NULL;
+		new_child->next_sibling = NULL;
+
+		/* Search for a collision.  Merge if there is */
+		for_each_child(old_node, old_child) {
+			if (streq(old_child->name, new_child->name)) {
+				merge_nodes(old_child, new_child);
+				new_child = NULL;
+				break;
+			}
+		}
+
+		/* if no collision occurred, add child to the old node. */
+		if (new_child)
+			add_child(old_node, new_child);
+	}
+
+	/* The new node contents are now merged into the old node.  Free
+	 * the new node. */
+	free(new_node);
+
+	return old_node;
+}
+
+struct node *chain_node(struct node *first, struct node *list)
+{
+	assert(first->next_sibling == NULL);
+
+	first->next_sibling = list;
+	return first;
+}
+
+void add_property(struct node *node, struct property *prop)
+{
+	struct property **p;
+
+	prop->next = NULL;
+
+	p = &node->proplist;
+	while (*p)
+		p = &((*p)->next);
+
+	*p = prop;
+}
+
+void add_child(struct node *parent, struct node *child)
+{
+	struct node **p;
+
+	child->next_sibling = NULL;
+	child->parent = parent;
+
+	p = &parent->children;
+	while (*p)
+		p = &((*p)->next_sibling);
+
+	*p = child;
+}
+
+struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
+{
+	struct reserve_info *new = xmalloc(sizeof(*new));
+
+	memset(new, 0, sizeof(*new));
+
+	new->re.address = address;
+	new->re.size = size;
+
+	return new;
+}
+
+struct reserve_info *chain_reserve_entry(struct reserve_info *first,
+					struct reserve_info *list)
+{
+	assert(first->next == NULL);
+
+	first->next = list;
+	return first;
+}
+
+struct reserve_info *add_reserve_entry(struct reserve_info *list,
+				      struct reserve_info *new)
+{
+	struct reserve_info *last;
+
+	new->next = NULL;
+
+	if (! list)
+		return new;
+
+	for (last = list; last->next; last = last->next)
+		;
+
+	last->next = new;
+
+	return list;
+}
+
+struct boot_info *build_boot_info(struct reserve_info *reservelist,
+				  struct node *tree, uint32_t boot_cpuid_phys)
+{
+	struct boot_info *bi;
+
+	bi = xmalloc(sizeof(*bi));
+	bi->reservelist = reservelist;
+	bi->dt = tree;
+	bi->boot_cpuid_phys = boot_cpuid_phys;
+
+	return bi;
+}
+
+/*
+ * Tree accessor functions
+ */
+
+const char *get_unitname(struct node *node)
+{
+	if (node->name[node->basenamelen] == '\0')
+		return "";
+	else
+		return node->name + node->basenamelen + 1;
+}
+
+struct property *get_property(struct node *node, const char *propname)
+{
+	struct property *prop;
+
+	for_each_property(node, prop)
+		if (streq(prop->name, propname))
+			return prop;
+
+	return NULL;
+}
+
+cell_t propval_cell(struct property *prop)
+{
+	assert(prop->val.len == sizeof(cell_t));
+	return fdt32_to_cpu(*((cell_t *)prop->val.val));
+}
+
+struct property *get_property_by_label(struct node *tree, const char *label,
+				       struct node **node)
+{
+	struct property *prop;
+	struct node *c;
+
+	*node = tree;
+
+	for_each_property(tree, prop) {
+		struct label *l;
+
+		for_each_label(prop->labels, l)
+			if (streq(l->label, label))
+				return prop;
+	}
+
+	for_each_child(tree, c) {
+		prop = get_property_by_label(c, label, node);
+		if (prop)
+			return prop;
+	}
+
+	*node = NULL;
+	return NULL;
+}
+
+struct marker *get_marker_label(struct node *tree, const char *label,
+				struct node **node, struct property **prop)
+{
+	struct marker *m;
+	struct property *p;
+	struct node *c;
+
+	*node = tree;
+
+	for_each_property(tree, p) {
+		*prop = p;
+		m = p->val.markers;
+		for_each_marker_of_type(m, LABEL)
+			if (streq(m->ref, label))
+				return m;
+	}
+
+	for_each_child(tree, c) {
+		m = get_marker_label(c, label, node, prop);
+		if (m)
+			return m;
+	}
+
+	*prop = NULL;
+	*node = NULL;
+	return NULL;
+}
+
+struct node *get_subnode(struct node *node, const char *nodename)
+{
+	struct node *child;
+
+	for_each_child(node, child)
+		if (streq(child->name, nodename))
+			return child;
+
+	return NULL;
+}
+
+struct node *get_node_by_path(struct node *tree, const char *path)
+{
+	const char *p;
+	struct node *child;
+
+	if (!path || ! (*path))
+		return tree;
+
+	while (path[0] == '/')
+		path++;
+
+	p = strchr(path, '/');
+
+	for_each_child(tree, child) {
+		if (p && strneq(path, child->name, p-path))
+			return get_node_by_path(child, p+1);
+		else if (!p && streq(path, child->name))
+			return child;
+	}
+
+	return NULL;
+}
+
+struct node *get_node_by_label(struct node *tree, const char *label)
+{
+	struct node *child, *node;
+	struct label *l;
+
+	assert(label && (strlen(label) > 0));
+
+	for_each_label(tree->labels, l)
+		if (streq(l->label, label))
+			return tree;
+
+	for_each_child(tree, child) {
+		node = get_node_by_label(child, label);
+		if (node)
+			return node;
+	}
+
+	return NULL;
+}
+
+struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
+{
+	struct node *child, *node;
+
+	assert((phandle != 0) && (phandle != -1));
+
+	if (tree->phandle == phandle)
+		return tree;
+
+	for_each_child(tree, child) {
+		node = get_node_by_phandle(child, phandle);
+		if (node)
+			return node;
+	}
+
+	return NULL;
+}
+
+struct node *get_node_by_ref(struct node *tree, const char *ref)
+{
+	if (ref[0] == '/')
+		return get_node_by_path(tree, ref);
+	else
+		return get_node_by_label(tree, ref);
+}
+
+
+uint32_t guess_boot_cpuid(struct node *tree)
+{
+	struct node *cpus, *bootcpu;
+	struct property *reg;
+
+	cpus = get_node_by_path(tree, "/cpus");
+	if (!cpus)
+		return 0;
+
+
+	bootcpu = cpus->children;
+	if (!bootcpu)
+		return 0;
+
+	reg = get_property(bootcpu, "reg");
+	if (!reg || (reg->val.len != sizeof(uint32_t)))
+		return 0;
+
+	/* FIXME: Sanity check node? */
+
+	return propval_cell(reg);
+}
+
+static int cmp_reserve_info(const void *ax, const void *bx)
+{
+	const struct reserve_info *a, *b;
+
+	a = *((const struct reserve_info * const *)ax);
+	b = *((const struct reserve_info * const *)bx);
+
+	if (a->re.address < b->re.address)
+		return -1;
+	else if (a->re.address > b->re.address)
+		return 1;
+	else if (a->re.size < b->re.size)
+		return -1;
+	else if (a->re.size > b->re.size)
+		return 1;
+	else
+		return 0;
+}
+
+static void sort_reserve_entries(struct boot_info *bi)
+{
+	struct reserve_info *ri, **tbl;
+	int n = 0, i = 0;
+
+	for (ri = bi->reservelist;
+	     ri;
+	     ri = ri->next)
+		n++;
+
+	if (n == 0)
+		return;
+
+	tbl = xmalloc(n * sizeof(*tbl));
+
+	for (ri = bi->reservelist;
+	     ri;
+	     ri = ri->next)
+		tbl[i++] = ri;
+
+	qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
+
+	bi->reservelist = tbl[0];
+	for (i = 0; i < (n-1); i++)
+		tbl[i]->next = tbl[i+1];
+	tbl[n-1]->next = NULL;
+
+	free(tbl);
+}
+
+static int cmp_prop(const void *ax, const void *bx)
+{
+	const struct property *a, *b;
+
+	a = *((const struct property * const *)ax);
+	b = *((const struct property * const *)bx);
+
+	return strcmp(a->name, b->name);
+}
+
+static void sort_properties(struct node *node)
+{
+	int n = 0, i = 0;
+	struct property *prop, **tbl;
+
+	for_each_property(node, prop)
+		n++;
+
+	if (n == 0)
+		return;
+
+	tbl = xmalloc(n * sizeof(*tbl));
+
+	for_each_property(node, prop)
+		tbl[i++] = prop;
+
+	qsort(tbl, n, sizeof(*tbl), cmp_prop);
+
+	node->proplist = tbl[0];
+	for (i = 0; i < (n-1); i++)
+		tbl[i]->next = tbl[i+1];
+	tbl[n-1]->next = NULL;
+
+	free(tbl);
+}
+
+static int cmp_subnode(const void *ax, const void *bx)
+{
+	const struct node *a, *b;
+
+	a = *((const struct node * const *)ax);
+	b = *((const struct node * const *)bx);
+
+	return strcmp(a->name, b->name);
+}
+
+static void sort_subnodes(struct node *node)
+{
+	int n = 0, i = 0;
+	struct node *subnode, **tbl;
+
+	for_each_child(node, subnode)
+		n++;
+
+	if (n == 0)
+		return;
+
+	tbl = xmalloc(n * sizeof(*tbl));
+
+	for_each_child(node, subnode)
+		tbl[i++] = subnode;
+
+	qsort(tbl, n, sizeof(*tbl), cmp_subnode);
+
+	node->children = tbl[0];
+	for (i = 0; i < (n-1); i++)
+		tbl[i]->next_sibling = tbl[i+1];
+	tbl[n-1]->next_sibling = NULL;
+
+	free(tbl);
+}
+
+static void sort_node(struct node *node)
+{
+	struct node *c;
+
+	sort_properties(node);
+	sort_subnodes(node);
+	for_each_child(node, c)
+		sort_node(c);
+}
+
+void sort_tree(struct boot_info *bi)
+{
+	sort_reserve_entries(bi);
+	sort_node(bi->dt);
+}
diff --git a/util_lib/dtc/srcpos.c b/util_lib/dtc/srcpos.c
new file mode 100644
index 0000000..36a38e9
--- /dev/null
+++ b/util_lib/dtc/srcpos.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+
+#include "dtc.h"
+#include "srcpos.h"
+
+
+static char *dirname(const char *path)
+{
+	const char *slash = strrchr(path, '/');
+
+	if (slash) {
+		int len = slash - path;
+		char *dir = xmalloc(len + 1);
+
+		memcpy(dir, path, len);
+		dir[len] = '\0';
+		return dir;
+	}
+	return NULL;
+}
+
+FILE *depfile; /* = NULL */
+struct srcfile_state *current_srcfile; /* = NULL */
+
+/* Detect infinite include recursion. */
+#define MAX_SRCFILE_DEPTH     (100)
+static int srcfile_depth; /* = 0 */
+
+FILE *srcfile_relative_open(const char *fname, char **fullnamep)
+{
+	FILE *f;
+	char *fullname;
+
+	if (streq(fname, "-")) {
+		f = stdin;
+		fullname = xstrdup("<stdin>");
+	} else {
+		if (!current_srcfile || !current_srcfile->dir
+		    || (fname[0] == '/'))
+			fullname = xstrdup(fname);
+		else
+			fullname = join_path(current_srcfile->dir, fname);
+
+		f = fopen(fullname, "r");
+		if (!f)
+			die("Couldn't open \"%s\": %s\n", fname,
+			    strerror(errno));
+	}
+
+	if (depfile)
+		fprintf(depfile, " %s", fullname);
+
+	if (fullnamep)
+		*fullnamep = fullname;
+	else
+		free(fullname);
+
+	return f;
+}
+
+void srcfile_push(const char *fname)
+{
+	struct srcfile_state *srcfile;
+
+	if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
+		die("Includes nested too deeply");
+
+	srcfile = xmalloc(sizeof(*srcfile));
+
+	srcfile->f = srcfile_relative_open(fname, &srcfile->name);
+	srcfile->dir = dirname(srcfile->name);
+	srcfile->prev = current_srcfile;
+
+	srcfile->lineno = 1;
+	srcfile->colno = 1;
+
+	current_srcfile = srcfile;
+}
+
+int srcfile_pop(void)
+{
+	struct srcfile_state *srcfile = current_srcfile;
+
+	assert(srcfile);
+
+	current_srcfile = srcfile->prev;
+
+	if (fclose(srcfile->f))
+		die("Error closing \"%s\": %s\n", srcfile->name,
+		    strerror(errno));
+
+	/* FIXME: We allow the srcfile_state structure to leak,
+	 * because it could still be referenced from a location
+	 * variable being carried through the parser somewhere.  To
+	 * fix this we could either allocate all the files from a
+	 * table, or use a pool allocator. */
+
+	return current_srcfile ? 1 : 0;
+}
+
+/*
+ * The empty source position.
+ */
+
+struct srcpos srcpos_empty = {
+	.first_line = 0,
+	.first_column = 0,
+	.last_line = 0,
+	.last_column = 0,
+	.file = NULL,
+};
+
+#define TAB_SIZE      8
+
+void srcpos_update(struct srcpos *pos, const char *text, int len)
+{
+	int i;
+
+	pos->file = current_srcfile;
+
+	pos->first_line = current_srcfile->lineno;
+	pos->first_column = current_srcfile->colno;
+
+	for (i = 0; i < len; i++)
+		if (text[i] == '\n') {
+			current_srcfile->lineno++;
+			current_srcfile->colno = 1;
+		} else if (text[i] == '\t') {
+			current_srcfile->colno =
+				ALIGN(current_srcfile->colno, TAB_SIZE);
+		} else {
+			current_srcfile->colno++;
+		}
+
+	pos->last_line = current_srcfile->lineno;
+	pos->last_column = current_srcfile->colno;
+}
+
+struct srcpos *
+srcpos_copy(struct srcpos *pos)
+{
+	struct srcpos *pos_new;
+
+	pos_new = xmalloc(sizeof(struct srcpos));
+	memcpy(pos_new, pos, sizeof(struct srcpos));
+
+	return pos_new;
+}
+
+
+
+void
+srcpos_dump(struct srcpos *pos)
+{
+	printf("file        : \"%s\"\n",
+	       pos->file ? (char *) pos->file : "<no file>");
+	printf("first_line  : %d\n", pos->first_line);
+	printf("first_column: %d\n", pos->first_column);
+	printf("last_line   : %d\n", pos->last_line);
+	printf("last_column : %d\n", pos->last_column);
+	printf("file        : %s\n", pos->file->name);
+}
+
+
+char *
+srcpos_string(struct srcpos *pos)
+{
+	const char *fname = "<no-file>";
+	char *pos_str;
+	int rc;
+
+	if (pos)
+		fname = pos->file->name;
+
+
+	if (pos->first_line != pos->last_line)
+		rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
+			      pos->first_line, pos->first_column,
+			      pos->last_line, pos->last_column);
+	else if (pos->first_column != pos->last_column)
+		rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
+			      pos->first_line, pos->first_column,
+			      pos->last_column);
+	else
+		rc = asprintf(&pos_str, "%s:%d.%d", fname,
+			      pos->first_line, pos->first_column);
+
+	if (rc == -1)
+		die("Couldn't allocate in srcpos string");
+
+	return pos_str;
+}
+
+void
+srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
+{
+       const char *srcstr;
+
+       srcstr = srcpos_string(pos);
+
+       fprintf(stdout, "Error: %s ", srcstr);
+       vfprintf(stdout, fmt, va);
+       fprintf(stdout, "\n");
+}
+
+void
+srcpos_error(struct srcpos *pos, char const *fmt, ...)
+{
+	va_list va;
+
+	va_start(va, fmt);
+	srcpos_verror(pos, fmt, va);
+	va_end(va);
+}
+
+
+void
+srcpos_warn(struct srcpos *pos, char const *fmt, ...)
+{
+	const char *srcstr;
+	va_list va;
+	va_start(va, fmt);
+
+	srcstr = srcpos_string(pos);
+
+	fprintf(stderr, "Warning: %s ", srcstr);
+	vfprintf(stderr, fmt, va);
+	fprintf(stderr, "\n");
+
+	va_end(va);
+}
diff --git a/util_lib/dtc/srcpos.h b/util_lib/dtc/srcpos.h
new file mode 100644
index 0000000..ce980ca
--- /dev/null
+++ b/util_lib/dtc/srcpos.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#ifndef _SRCPOS_H_
+#define _SRCPOS_H_
+
+#include <stdio.h>
+
+struct srcfile_state {
+	FILE *f;
+	char *name;
+	char *dir;
+	int lineno, colno;
+	struct srcfile_state *prev;
+};
+
+extern FILE *depfile; /* = NULL */
+extern struct srcfile_state *current_srcfile; /* = NULL */
+
+FILE *srcfile_relative_open(const char *fname, char **fullnamep);
+void srcfile_push(const char *fname);
+int srcfile_pop(void);
+
+struct srcpos {
+    int first_line;
+    int first_column;
+    int last_line;
+    int last_column;
+    struct srcfile_state *file;
+};
+
+#define YYLTYPE struct srcpos
+
+#define YYLLOC_DEFAULT(Current, Rhs, N)						\
+	do {									\
+		if (N) {							\
+			(Current).first_line = YYRHSLOC(Rhs, 1).first_line;	\
+			(Current).first_column = YYRHSLOC(Rhs, 1).first_column;	\
+			(Current).last_line = YYRHSLOC(Rhs, N).last_line;	\
+			(Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+			(Current).file = YYRHSLOC(Rhs, N).file;			\
+		} else {							\
+			(Current).first_line = (Current).last_line =		\
+				YYRHSLOC(Rhs, 0).last_line;			\
+			(Current).first_column = (Current).last_column =	\
+				YYRHSLOC(Rhs, 0).last_column;			\
+			(Current).file = YYRHSLOC (Rhs, 0).file;		\
+		}								\
+	} while (0)
+
+
+/*
+ * Fictional source position used for IR nodes that are
+ * created without otherwise knowing a true source position.
+ * For example,constant definitions from the command line.
+ */
+extern struct srcpos srcpos_empty;
+
+extern void srcpos_update(struct srcpos *pos, const char *text, int len);
+extern struct srcpos *srcpos_copy(struct srcpos *pos);
+extern char *srcpos_string(struct srcpos *pos);
+extern void srcpos_dump(struct srcpos *pos);
+
+extern void srcpos_verror(struct srcpos *pos, char const *, va_list va)
+     __attribute__((format(printf, 2, 0)));
+extern void srcpos_error(struct srcpos *pos, char const *, ...)
+     __attribute__((format(printf, 2, 3)));
+extern void srcpos_warn(struct srcpos *pos, char const *, ...)
+     __attribute__((format(printf, 2, 3)));
+
+#endif /* _SRCPOS_H_ */
diff --git a/util_lib/dtc/util.c b/util_lib/dtc/util.c
new file mode 100644
index 0000000..d7ac27d
--- /dev/null
+++ b/util_lib/dtc/util.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "util.h"
+
+char *xstrdup(const char *s)
+{
+	int len = strlen(s) + 1;
+	char *dup = xmalloc(len);
+
+	memcpy(dup, s, len);
+
+	return dup;
+}
+
+char *join_path(const char *path, const char *name)
+{
+	int lenp = strlen(path);
+	int lenn = strlen(name);
+	int len;
+	int needslash = 1;
+	char *str;
+
+	len = lenp + lenn + 2;
+	if ((lenp > 0) && (path[lenp-1] == '/')) {
+		needslash = 0;
+		len--;
+	}
+
+	str = xmalloc(len);
+	memcpy(str, path, lenp);
+	if (needslash) {
+		str[lenp] = '/';
+		lenp++;
+	}
+	memcpy(str+lenp, name, lenn+1);
+	return str;
+}
diff --git a/util_lib/dtc/util.h b/util_lib/dtc/util.h
new file mode 100644
index 0000000..9cead84
--- /dev/null
+++ b/util_lib/dtc/util.h
@@ -0,0 +1,56 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+static inline void __attribute__((noreturn)) die(char * str, ...)
+{
+	va_list ap;
+
+	va_start(ap, str);
+	fprintf(stderr, "FATAL ERROR: ");
+	vfprintf(stderr, str, ap);
+	exit(1);
+}
+
+static inline void *xmalloc(size_t len)
+{
+	void *new = malloc(len);
+
+	if (!new)
+		die("malloc() failed\n");
+
+	return new;
+}
+
+static inline void *xrealloc(void *p, size_t len)
+{
+	void *new = realloc(p, len);
+
+	if (!new)
+		die("realloc() failed (len=%d)\n", len);
+
+	return new;
+}
+
+extern char *xstrdup(const char *s);
+extern char *join_path(const char *path, const char *name);
+
+#endif /* _UTIL_H */
diff --git a/util_lib/dtc/version_gen.h b/util_lib/dtc/version_gen.h
new file mode 100644
index 0000000..6158b86
--- /dev/null
+++ b/util_lib/dtc/version_gen.h
@@ -0,0 +1 @@
+#define DTC_VERSION "DTC 1.2.0-g37c0b6a0"
-- 
1.7.12


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* [RFC PATCH 4/4] Add device tree support to the ARM platform
  2012-09-05 11:43 [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Matthew Leach
                   ` (2 preceding siblings ...)
  2012-09-05 11:44 ` [RFC PATCH 3/4] Add the dtc for device-tree manipulation Matthew Leach
@ 2012-09-05 11:44 ` Matthew Leach
  2012-09-05 12:38 ` [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Simon Horman
  4 siblings, 0 replies; 15+ messages in thread
From: Matthew Leach @ 2012-09-05 11:44 UTC (permalink / raw)
  To: kexec; +Cc: Matthew Leach, will.deacon

To allow newer ARM platforms to use kexec, pass device tree
information to the kernel during boot.

By default the dtb is found from /proc/device-tree. A user can specify
a dtb file or use legacy ATAGs

Signed-off-by: Matthew Leach <matthew.leach@arm.com>
---
 kexec/arch/arm/Makefile               |  10 +++
 kexec/arch/arm/include/arch/options.h |   6 +-
 kexec/arch/arm/kexec-zImage-arm.c     | 140 ++++++++++++++++++++++++++++++++--
 3 files changed, 150 insertions(+), 6 deletions(-)

diff --git a/kexec/arch/arm/Makefile b/kexec/arch/arm/Makefile
index 288ec33..f25ce15 100644
--- a/kexec/arch/arm/Makefile
+++ b/kexec/arch/arm/Makefile
@@ -1,12 +1,22 @@
 #
 # kexec arm (linux booting linux)
 #
+include $(srcdir)/util_lib/dtc/Makefile.dtc
+
 arm_KEXEC_SRCS=  kexec/arch/arm/kexec-elf-rel-arm.c
 arm_KEXEC_SRCS+= kexec/arch/arm/kexec-zImage-arm.c
 arm_KEXEC_SRCS+= kexec/arch/arm/kexec-uImage-arm.c
 arm_KEXEC_SRCS+= kexec/arch/arm/kexec-arm.c
 arm_KEXEC_SRCS+= kexec/arch/arm/crashdump-arm.c
 
+libfdt_SRCS += $(LIBFDT_SRCS:%=util_lib/libfdt/%)
+dtc_SRCS += $(DTC_SRCS:%=util_lib/dtc/%)
+
+arm_KEXEC_SRCS+= $(libfdt_SRCS)
+arm_KEXEC_SRCS+= $(dtc_SRCS)
+
+CPPFLAGS+=-I$(srcdir)/util_lib/libfdt
+
 arm_UIMAGE = kexec/kexec-uImage.c
 arm_PHYS_TO_VIRT = kexec/arch/arm/phys_to_virt.c
 
diff --git a/kexec/arch/arm/include/arch/options.h b/kexec/arch/arm/include/arch/options.h
index d89c91f..b355c26 100644
--- a/kexec/arch/arm/include/arch/options.h
+++ b/kexec/arch/arm/include/arch/options.h
@@ -5,6 +5,8 @@
 
 #define OPT_APPEND	'a'
 #define OPT_RAMDISK	'r'
+#define OPT_DTB     (OPT_ARCH_MAX+0)
+#define OPT_ATAGS   (OPT_ARCH_MAX+1)
 
 /* Options relevant to the architecture (excluding loader-specific ones),
  * in this case none:
@@ -33,7 +35,9 @@
 	{ "command-line",	1, 0, OPT_APPEND },	\
 	{ "append",		1, 0, OPT_APPEND },	\
 	{ "initrd",		1, 0, OPT_RAMDISK },	\
-	{ "ramdisk",		1, 0, OPT_RAMDISK },
+	{ "ramdisk",		1, 0, OPT_RAMDISK },	\
+	{ "dtb",		1, 0, OPT_DTB }, 	\
+	{ "atags",		0, 0, OPT_ATAGS },
 
 #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR "a:r:"
 
diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
index 88a6c29..74028b8 100644
--- a/kexec/arch/arm/kexec-zImage-arm.c
+++ b/kexec/arch/arm/kexec-zImage-arm.c
@@ -13,6 +13,8 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <unistd.h>
+#include <dtc.h>
+#include <libfdt.h>
 #include <arch/options.h>
 #include "../../kexec.h"
 #include "../../kexec-syscall.h"
@@ -96,6 +98,8 @@ void zImage_arm_usage(void)
 		"     --append=STRING       Set the kernel command line to STRING.\n"
 		"     --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
 		"     --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
+		"     --dtb=FILE            Use FILE as the fdt blob.\n"
+		"     --atags               Use ATAGs instead of device-tree.\n"
 		);
 }
 
@@ -208,6 +212,63 @@ int atag_arm_load(struct kexec_info *info, unsigned long base,
 	return 0;
 }
 
+void dtb_fixup_chosen_node(char **dtb_buf, off_t *buf_sz, const char *command_line,
+                           unsigned long initrd_start, unsigned long initrd_end)
+{
+	if (command_line || initrd_start != initrd_end) {
+		int chosen_offset;
+		int root_offset;
+		int command_line_len = strlen(command_line);
+		off_t new_buf_sz = *buf_sz + command_line_len + 0x50; /* extra space for new node */
+		void *new_buf = malloc(new_buf_sz);
+
+		fdt_open_into(*dtb_buf, new_buf, new_buf_sz);
+
+		root_offset = fdt_path_offset(new_buf, "/");
+		chosen_offset = fdt_path_offset(new_buf, "/chosen");
+		if (chosen_offset == -FDT_ERR_NOTFOUND) {
+			chosen_offset = fdt_add_subnode(new_buf, root_offset, "chosen");
+		}
+		if (chosen_offset < 0) {
+			fprintf(stderr, "Warning: failed to find the chosen node, a specified command line and"
+			        " initrd will not be set.\n");
+			free(new_buf);
+			return;
+		}
+
+		/*
+		 * Add the 'bootargs' proerpty to the chosen node if the command
+		 * line is specified.
+		 */
+		if (command_line) {
+			if (fdt_setprop_string(new_buf, chosen_offset,
+			                       "bootargs", command_line) < 0) {
+				fprintf(stderr, "Warning: failed to set the command line.\n");
+				free(new_buf);
+				return;
+			}
+		}
+
+		/*
+		 * Add the 'initrd-start' and 'initrd-end' properties to the
+		 * chosen node if an initrd is specified.
+		 */
+		if (initrd_start != initrd_end) {
+			if ((fdt_setprop_cell(new_buf, chosen_offset,
+			                      "initrd-start", initrd_start) < 0) ||
+			    (fdt_setprop_cell(new_buf, chosen_offset,
+			                      "initrd-end", initrd_end) < 0)) {
+				fprintf(stderr, "Warning: failed to set the initrd addresses.\n");
+				return;
+			}	
+		}
+
+		free(*dtb_buf);
+		*dtb_buf = new_buf;
+		*buf_sz = new_buf_sz;
+	}
+}
+
 int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info)
 {
@@ -222,6 +283,12 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	off_t ramdisk_length;
 	off_t ramdisk_offset;
 	int opt;
+	int use_atags;
+	char *dtb_buf;
+	off_t dtb_length;
+	char *dtb_file;
+	off_t dtb_offset;
+
 	/* See options.h -- add any more there, too. */
 	static const struct option options[] = {
 		KEXEC_ARCH_OPTIONS
@@ -229,6 +296,8 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 		{ "append",		1, 0, OPT_APPEND },
 		{ "initrd",		1, 0, OPT_RAMDISK },
 		{ "ramdisk",		1, 0, OPT_RAMDISK },
+		{ "dtb",		1, 0, OPT_DTB },
+		{ "atags",		0, 0, OPT_ATAGS },
 		{ 0, 			0, 0, 0 },
 	};
 	static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:";
@@ -241,6 +310,8 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	ramdisk = 0;
 	ramdisk_buf = 0;
 	ramdisk_length = 0;
+	use_atags = 0;
+	dtb_file = NULL;
 	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch(opt) {
 		default:
@@ -257,8 +328,21 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 		case OPT_RAMDISK:
 			ramdisk = optarg;
 			break;
+		case OPT_DTB:
+			dtb_file = optarg;
+			break;
+		case OPT_ATAGS:
+			use_atags = 1;
+			break;
 		}
 	}
+
+	if (use_atags && dtb_file) {
+		fprintf(stderr, "You can only use ATAGs if you don't specify a "
+		        "dtb file.\n");
+		return -1;
+	}
+
 	if (command_line) {
 		command_line_len = strlen(command_line) + 1;
 		if (command_line_len > COMMAND_LINE_SIZE)
@@ -315,12 +399,58 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	/* assume the maximum kernel compression ratio is 4,
 	 * and just to be safe, place ramdisk after that
 	 */
-	ramdisk_offset = base + len * 4;
+		ramdisk_offset = base + len * 4;
 
-	if (atag_arm_load(info, base + atag_offset,
-			 command_line, command_line_len,
-			 ramdisk_buf, ramdisk_length, ramdisk_offset) == -1)
-		return -1;
+	if (use_atags) {
+		/*
+		 * use ATAGs from /proc/atags
+		 */
+		if (atag_arm_load(info, base + atag_offset,
+		                  command_line, command_line_len,
+		                  ramdisk_buf, ramdisk_length, ramdisk_offset) == -1)
+			return -1;
+	} else {
+		/*
+		 * Read a user-specified DTB file.
+		 */
+		if (dtb_file) {
+			dtb_buf = slurp_file(dtb_file, &dtb_length);
+		} else {
+			/*
+			 * Extract the DTB from /proc/device-tree.
+			 */
+			struct boot_info *bi;
+			bi = dt_from_fs("/proc/device-tree");
+			dtb_buf = dt_to_blob_buf(&dtb_length, bi, DEFAULT_FDT_VERSION);
+		}
+
+		dtb_fixup_chosen_node(&dtb_buf, &dtb_length, command_line,
+		                      ramdisk_offset, ramdisk_offset + ramdisk_length);
+
+		if (fdt_check_header(dtb_buf) != 0) {
+			fprintf(stderr, "Invalid FDT buffer.\n");
+			return -1;
+		}
+
+		if (base + atag_offset + dtb_length > base + offset) {
+			fprintf(stderr, "DTB too large!\n");
+			return -1;
+		}
+
+		if (ramdisk) {
+			add_segment(info, ramdisk_buf, ramdisk_length,
+			            ramdisk_offset, ramdisk_length);
+		}
+
+		/* Stick the dtb at the end of the initrd and page
+		 * align it.
+		 */
+		dtb_offset = ramdisk_offset + ramdisk_length + getpagesize();
+		dtb_offset &= ~(getpagesize() - 1);
+
+		add_segment(info, dtb_buf, dtb_length,
+		            dtb_offset, dtb_length);
+	}
 
 	add_segment(info, buf, len, base + offset, len);
 
-- 
1.7.12


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-05 11:43 [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Matthew Leach
                   ` (3 preceding siblings ...)
  2012-09-05 11:44 ` [RFC PATCH 4/4] Add device tree support to the ARM platform Matthew Leach
@ 2012-09-05 12:38 ` Simon Horman
  2012-09-05 14:34   ` Matthew Leach
  4 siblings, 1 reply; 15+ messages in thread
From: Simon Horman @ 2012-09-05 12:38 UTC (permalink / raw)
  To: Matthew Leach; +Cc: will.deacon, kexec

On Wed, Sep 05, 2012 at 12:43:59PM +0100, Matthew Leach wrote:
> Hi all,
> 
> Running a kexec() on newer ARM platforms has become an issue as
> information about the platform that is presented via device-tree is
> required to boot a new kernel.
> 
> The ATAGs kernel code is re-used, replacing the ATAGs with a
> device-tree blob so that only kexec-tools needs to be changed. There
> are two options for generating a dtb to be passed to the kernel from
> kexec-tools: 1) Read in the device-tree that is exposed in
> /proc/device-tree and flatten this out into a dtb.  2) Allow the user
> to specify a dtb file on the command line.  These blobs are then
> loaded into memory before the kernel image and the address passed
> through to r2, as stated in the ARM booting documentation.

Hi Matt,

are you aware that I posted patches to add ARM DT support
to kexec-tools a few weeks ago?

I'm not particularly concerned which version goes in,
but perhaps we can learn from each others efforts.

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* RE: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-05 12:38 ` [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Simon Horman
@ 2012-09-05 14:34   ` Matthew Leach
  2012-09-06  3:29     ` Simon Horman
  0 siblings, 1 reply; 15+ messages in thread
From: Matthew Leach @ 2012-09-05 14:34 UTC (permalink / raw)
  To: 'Simon Horman'; +Cc: Will Deacon, kexec

Hi Simon,

> Hi Matt,
> 
> are you aware that I posted patches to add ARM DT support
> to kexec-tools a few weeks ago?

Ah, I missed that...
 
> I'm not particularly concerned which version goes in,
> but perhaps we can learn from each others efforts.

After looking over your patches I propose that I incorporate your
generic fs2dt code instead of pulling in the dtc. Also, I use a
different segment for the dtb rather than appending it to the
zImage; I think this approach would be better as it is less
restrictive, however a kernel patch is required to set r2 to the
appropriate address on entry to the new kernel. What are your
thoughts?

If you are happy with this I will submit a v2 set of patches.

Matt



_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-05 14:34   ` Matthew Leach
@ 2012-09-06  3:29     ` Simon Horman
  2012-09-06  9:01       ` Will Deacon
  2012-09-06 11:04       ` Matthew Leach
  0 siblings, 2 replies; 15+ messages in thread
From: Simon Horman @ 2012-09-06  3:29 UTC (permalink / raw)
  To: Matthew Leach; +Cc: kexec, Will Deacon

Hi Matt,

On Wed, Sep 05, 2012 at 03:34:09PM +0100, Matthew Leach wrote:
> Hi Simon,
> 
> > Hi Matt,
> > 
> > are you aware that I posted patches to add ARM DT support
> > to kexec-tools a few weeks ago?
> 
> Ah, I missed that...
>  
> > I'm not particularly concerned which version goes in,
> > but perhaps we can learn from each others efforts.
> 
> After looking over your patches I propose that I incorporate your
> generic fs2dt code instead of pulling in the dtc.

Thanks. It was that part of the code that I spent the bulk of my time on.
And although it is still has a few rough edges I would be happy for it
to be used.

> Also, I use a
> different segment for the dtb rather than appending it to the
> zImage; I think this approach would be better as it is less
> restrictive, however a kernel patch is required to set r2 to the
> appropriate address on entry to the new kernel. What are your
> thoughts?

I would prefer to avoid requiring kernel changes unless necessary -
the kernels some of the boards I work with require DT since 3.5.
However, I am happy to discuss this further, there certainly is
merit to a clean implementation.

> If you are happy with this I will submit a v2 set of patches.

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06  3:29     ` Simon Horman
@ 2012-09-06  9:01       ` Will Deacon
  2012-09-06  9:09         ` Simon Horman
  2012-09-06 11:04       ` Matthew Leach
  1 sibling, 1 reply; 15+ messages in thread
From: Will Deacon @ 2012-09-06  9:01 UTC (permalink / raw)
  To: Simon Horman; +Cc: Matthew Leach, kexec@lists.infradead.org

Hi guys,

On Thu, Sep 06, 2012 at 04:29:02AM +0100, Simon Horman wrote:
> On Wed, Sep 05, 2012 at 03:34:09PM +0100, Matthew Leach wrote:
> > Also, I use a
> > different segment for the dtb rather than appending it to the
> > zImage; I think this approach would be better as it is less
> > restrictive, however a kernel patch is required to set r2 to the
> > appropriate address on entry to the new kernel. What are your
> > thoughts?
> 
> I would prefer to avoid requiring kernel changes unless necessary -
> the kernels some of the boards I work with require DT since 3.5.
> However, I am happy to discuss this further, there certainly is
> merit to a clean implementation.

I had a quick look at both the approaches and it looks like Matthew requires
changes to the host kernel (to load the dtb correctly) and Simon requires
changes to the target kernel (to pick up the dtb correctly).

I would personally prefer changing the host, as the target should ideally
have no knowledge about the kexec. Given that kexec has not supported DT on
ARM so far and these patches have no affect on the existing ATAG mechanism,
I don't think there is a problem with making changes to the kernel.

I also wouldn't like to hedge my bets on CONFIG_ARM_APPENDED_DTB staying
around forever -- it's intended as convenience for legacy bootloaders rather
than something that should be used in preference to passing the dtb via r2.

Will

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06  9:01       ` Will Deacon
@ 2012-09-06  9:09         ` Simon Horman
  2012-09-06  9:14           ` Will Deacon
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Horman @ 2012-09-06  9:09 UTC (permalink / raw)
  To: Will Deacon; +Cc: Matthew Leach, kexec@lists.infradead.org

Hi Will,

On Thu, Sep 06, 2012 at 10:01:28AM +0100, Will Deacon wrote:
> Hi guys,
> 
> On Thu, Sep 06, 2012 at 04:29:02AM +0100, Simon Horman wrote:
> > On Wed, Sep 05, 2012 at 03:34:09PM +0100, Matthew Leach wrote:
> > > Also, I use a
> > > different segment for the dtb rather than appending it to the
> > > zImage; I think this approach would be better as it is less
> > > restrictive, however a kernel patch is required to set r2 to the
> > > appropriate address on entry to the new kernel. What are your
> > > thoughts?
> > 
> > I would prefer to avoid requiring kernel changes unless necessary -
> > the kernels some of the boards I work with require DT since 3.5.
> > However, I am happy to discuss this further, there certainly is
> > merit to a clean implementation.
> 
> I had a quick look at both the approaches and it looks like Matthew requires
> changes to the host kernel (to load the dtb correctly) and Simon requires
> changes to the target kernel (to pick up the dtb correctly).

Could you explain a little why you feel my patch requires a change to
the target kernel?

> I would personally prefer changing the host, as the target should ideally
> have no knowledge about the kexec. Given that kexec has not supported DT on
> ARM so far and these patches have no affect on the existing ATAG mechanism,
> I don't think there is a problem with making changes to the kernel.

Agreed.

> I also wouldn't like to hedge my bets on CONFIG_ARM_APPENDED_DTB staying
> around forever -- it's intended as convenience for legacy bootloaders rather
> than something that should be used in preference to passing the dtb via r2.

Also agreed.

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06  9:09         ` Simon Horman
@ 2012-09-06  9:14           ` Will Deacon
  2012-09-06 22:03             ` Simon Horman
  0 siblings, 1 reply; 15+ messages in thread
From: Will Deacon @ 2012-09-06  9:14 UTC (permalink / raw)
  To: Simon Horman; +Cc: Matthew Leach, kexec@lists.infradead.org

On Thu, Sep 06, 2012 at 10:09:14AM +0100, Simon Horman wrote:
> Hi Will,
> 
> On Thu, Sep 06, 2012 at 10:01:28AM +0100, Will Deacon wrote:
> > Hi guys,
> > 
> > On Thu, Sep 06, 2012 at 04:29:02AM +0100, Simon Horman wrote:
> > > On Wed, Sep 05, 2012 at 03:34:09PM +0100, Matthew Leach wrote:
> > > > Also, I use a
> > > > different segment for the dtb rather than appending it to the
> > > > zImage; I think this approach would be better as it is less
> > > > restrictive, however a kernel patch is required to set r2 to the
> > > > appropriate address on entry to the new kernel. What are your
> > > > thoughts?
> > > 
> > > I would prefer to avoid requiring kernel changes unless necessary -
> > > the kernels some of the boards I work with require DT since 3.5.
> > > However, I am happy to discuss this further, there certainly is
> > > merit to a clean implementation.
> > 
> > I had a quick look at both the approaches and it looks like Matthew requires
> > changes to the host kernel (to load the dtb correctly) and Simon requires
> > changes to the target kernel (to pick up the dtb correctly).
> 
> Could you explain a little why you feel my patch requires a change to
> the target kernel?

Sure, I may be misunderstanding something, so please shout if that's the
case! Anyway, I was under the impression that you required
CONFIG_ARM_APPENDED_DTB to be enabled in the target so that it can pick up
the new DT. If that's not the case, then you'll need to change the host
kernel to fix up r2 (rather than point it at the KEXEC_ARM_ATAGS_OFFSET,
which is too small for a dtb).

What am I missing?

Will

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* RE: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06  3:29     ` Simon Horman
  2012-09-06  9:01       ` Will Deacon
@ 2012-09-06 11:04       ` Matthew Leach
  2012-09-06 11:19         ` Will Deacon
  2012-09-06 22:00         ` Simon Horman
  1 sibling, 2 replies; 15+ messages in thread
From: Matthew Leach @ 2012-09-06 11:04 UTC (permalink / raw)
  To: 'Simon Horman'; +Cc: kexec, Will Deacon

Hi Simon,

I have been having some issues using kexec with your dtb patches...

> Thanks. It was that part of the code that I spent the bulk of my time
> on.
> And although it is still has a few rough edges I would be happy for it
> to be used.

I have looked at the output from your generic fs2dt and compared
it to the original dts and all looks okay so I'm happy that this
part of your code works fine.

> I would prefer to avoid requiring kernel changes unless necessary -
> the kernels some of the boards I work with require DT since 3.5.
> However, I am happy to discuss this further, there certainly is
> merit to a clean implementation.

I believe that you are loading the dtb at an offset from the base
of 0x1000, this is where the problem lies in that the dtb can be
corrupted by the page tables of the decompressor.

Also, device trees can contain firmware and as such be on the
order of megabytes in size. This could potentially corrupt the
decompressor image depending upon the order that these two blobs
are written to memory.


I suggest that we put the DTB out of the way, perhaps just after
the initrd segment, or at the initrd_offset in the case that
there is no initrd. This would require a kernel change to set the
correct parameter to the relocate_new_kerenel function, but the
change is minimal.

If you are happy with this, I have a set of patches that does the
job.

Matt



_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06 11:04       ` Matthew Leach
@ 2012-09-06 11:19         ` Will Deacon
  2012-09-06 22:00         ` Simon Horman
  1 sibling, 0 replies; 15+ messages in thread
From: Will Deacon @ 2012-09-06 11:19 UTC (permalink / raw)
  To: Matthew Leach; +Cc: 'Simon Horman', kexec@lists.infradead.org

On Thu, Sep 06, 2012 at 12:04:50PM +0100, Matthew Leach wrote:
> I believe that you are loading the dtb at an offset from the base
> of 0x1000, this is where the problem lies in that the dtb can be
> corrupted by the page tables of the decompressor.

Aha, so it is still using the KEXEC_ARM_ATAGS_OFFSET stuff. Sorry if I
confused anybody about the DTB-append comments, I guess I was confusing the
segment layout with the final loaded layout.

It's worth pointing out that, with LPAE kernels, the page tables are larger
and sit at offset 0x3000, so this leaves only 8k for the .dtb which is
definitely not enough.

> I suggest that we put the DTB out of the way, perhaps just after
> the initrd segment, or at the initrd_offset in the case that
> there is no initrd. This would require a kernel change to set the
> correct parameter to the relocate_new_kerenel function, but the
> change is minimal.

I'm fine with changing the kernel, as long as it doesn't break existing
users (it doesn't).

Will

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06 11:04       ` Matthew Leach
  2012-09-06 11:19         ` Will Deacon
@ 2012-09-06 22:00         ` Simon Horman
  1 sibling, 0 replies; 15+ messages in thread
From: Simon Horman @ 2012-09-06 22:00 UTC (permalink / raw)
  To: Matthew Leach; +Cc: kexec, Will Deacon

On Thu, Sep 06, 2012 at 12:04:50PM +0100, Matthew Leach wrote:
> Hi Simon,
> 
> I have been having some issues using kexec with your dtb patches...
> 
> > Thanks. It was that part of the code that I spent the bulk of my time
> > on.
> > And although it is still has a few rough edges I would be happy for it
> > to be used.
> 
> I have looked at the output from your generic fs2dt and compared
> it to the original dts and all looks okay so I'm happy that this
> part of your code works fine.

:)

> > I would prefer to avoid requiring kernel changes unless necessary -
> > the kernels some of the boards I work with require DT since 3.5.
> > However, I am happy to discuss this further, there certainly is
> > merit to a clean implementation.
> 
> I believe that you are loading the dtb at an offset from the base
> of 0x1000, this is where the problem lies in that the dtb can be
> corrupted by the page tables of the decompressor.

Of course, sorry for missing that.

> Also, device trees can contain firmware and as such be on the
> order of megabytes in size. This could potentially corrupt the
> decompressor image depending upon the order that these two blobs
> are written to memory.

Yes, I see that now. The dtb I was using for testing was rather small,
less than 200b IIRC.

Actually, I accidently left debug code in the patchset that prints a hex
dump of the dtb to stdtout. That ought to be removed but that the dump
fited comfortably in few dozen lines illustrates how small a blob I had.

> I suggest that we put the DTB out of the way, perhaps just after
> the initrd segment, or at the initrd_offset in the case that
> there is no initrd. This would require a kernel change to set the
> correct parameter to the relocate_new_kerenel function, but the
> change is minimal.
> 
> If you are happy with this, I have a set of patches that does the
> job.

Thanks, for the explanation, and thanks to Will for his.
I'm happy with the approach that you propose.


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

* Re: [RFC PATCH 0/4]  Add device-tree support to kexec-tools for ARM
  2012-09-06  9:14           ` Will Deacon
@ 2012-09-06 22:03             ` Simon Horman
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Horman @ 2012-09-06 22:03 UTC (permalink / raw)
  To: Will Deacon; +Cc: Matthew Leach, kexec@lists.infradead.org

On Thu, Sep 06, 2012 at 10:14:06AM +0100, Will Deacon wrote:
> On Thu, Sep 06, 2012 at 10:09:14AM +0100, Simon Horman wrote:
> > Hi Will,
> > 
> > On Thu, Sep 06, 2012 at 10:01:28AM +0100, Will Deacon wrote:
> > > Hi guys,
> > > 
> > > On Thu, Sep 06, 2012 at 04:29:02AM +0100, Simon Horman wrote:
> > > > On Wed, Sep 05, 2012 at 03:34:09PM +0100, Matthew Leach wrote:
> > > > > Also, I use a
> > > > > different segment for the dtb rather than appending it to the
> > > > > zImage; I think this approach would be better as it is less
> > > > > restrictive, however a kernel patch is required to set r2 to the
> > > > > appropriate address on entry to the new kernel. What are your
> > > > > thoughts?
> > > > 
> > > > I would prefer to avoid requiring kernel changes unless necessary -
> > > > the kernels some of the boards I work with require DT since 3.5.
> > > > However, I am happy to discuss this further, there certainly is
> > > > merit to a clean implementation.
> > > 
> > > I had a quick look at both the approaches and it looks like Matthew requires
> > > changes to the host kernel (to load the dtb correctly) and Simon requires
> > > changes to the target kernel (to pick up the dtb correctly).
> > 
> > Could you explain a little why you feel my patch requires a change to
> > the target kernel?
> 
> Sure, I may be misunderstanding something, so please shout if that's the
> case! Anyway, I was under the impression that you required
> CONFIG_ARM_APPENDED_DTB to be enabled in the target so that it can pick up
> the new DT. If that's not the case, then you'll need to change the host
> kernel to fix up r2 (rather than point it at the KEXEC_ARM_ATAGS_OFFSET,
> which is too small for a dtb).

Thanks. It was not my intention that  CONFIG_ARM_APPENDED_DTB is required,
though due to limitations of the bootloader on the board I was using I did
have that option enabled for the host kernel.

Thanks for pointing out the size issue with using KEXEC_ARM_ATAGS_OFFSET,
I had overlooked that.

I think the best way forward, as both you and Matt suggested earlier,
is to modify the host kernel.


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

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

end of thread, other threads:[~2012-09-06 22:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-05 11:43 [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Matthew Leach
2012-09-05 11:44 ` [RFC PATCH 1/4] Fix an overflow bug with address comparison Matthew Leach
2012-09-05 11:44 ` [RFC PATCH 2/4] Move libfdt to a generic location Matthew Leach
2012-09-05 11:44 ` [RFC PATCH 3/4] Add the dtc for device-tree manipulation Matthew Leach
2012-09-05 11:44 ` [RFC PATCH 4/4] Add device tree support to the ARM platform Matthew Leach
2012-09-05 12:38 ` [RFC PATCH 0/4] Add device-tree support to kexec-tools for ARM Simon Horman
2012-09-05 14:34   ` Matthew Leach
2012-09-06  3:29     ` Simon Horman
2012-09-06  9:01       ` Will Deacon
2012-09-06  9:09         ` Simon Horman
2012-09-06  9:14           ` Will Deacon
2012-09-06 22:03             ` Simon Horman
2012-09-06 11:04       ` Matthew Leach
2012-09-06 11:19         ` Will Deacon
2012-09-06 22:00         ` Simon Horman

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.