public inbox for kexec@lists.infradead.org
 help / color / mirror / Atom feed
* PPC32 kexec v3
@ 2010-03-31  8:24 Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 1/7] slurpfile: use lseek() on character nodes instead of fstat() for file size Sebastian Andrzej Siewior
                   ` (6 more replies)
  0 siblings, 7 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: kexec

Hi Simon,

sorry for the delay. I broke something and wanted to make sure that
whatever I sent is working.
I'm sending the whole series which should be bisectable and care about
HAVE_LIBZ.
Patch 6 splits my uImage handling and 7 reuses it for SH and ARM. This is
only compile tested for ARM. The only benefit is that with libz it will
be crc32 tested.

The whole series is also at
  git://git.breakpoint.cc/bigeasy/kexec-tools.git ppc32

Sebastian


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

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

* [PATCH 1/7] slurpfile: use lseek() on character nodes instead of fstat() for file size
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 2/7] powerpc: dtb and purgatory support for ppc32 Sebastian Andrzej Siewior
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: Sebastian Andrzej Siewior, kexec

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

fstat() is used to determine the filesize before read() and
it requires a filesystem. That means that it can not be used
on character nodes. This makes it impossible to obtains the
kernel from a char node like mtd or more likely ubi.
We can't use this in every case because files in /proc don't
support lseek(). This is required by the powerpc part to read
some device-tree entries.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kexec/kexec.c |   23 +++++++++++++++++++++--
 1 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/kexec/kexec.c b/kexec/kexec.c
index d282ade..fe29fb5 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -475,7 +475,7 @@ char *slurp_file(const char *filename, off_t *r_size)
 {
 	int fd;
 	char *buf;
-	off_t size, progress;
+	off_t size, progress, err;
 	ssize_t result;
 	struct stat stats;
 	
@@ -494,7 +494,26 @@ char *slurp_file(const char *filename, off_t *r_size)
 		die("Cannot stat: %s: %s\n",
 			filename, strerror(errno));
 	}
-	size = stats.st_size;
+	/*
+	 * Seek in case the kernel is a character node like /dev/ubi0_0.
+	 * This does not work on regular files which live in /proc and
+	 * we need this for some /proc/device-tree entries
+	 */
+	if (S_ISCHR(stats.st_mode)) {
+
+		size = lseek(fd, 0, SEEK_END);
+		if (size < 0)
+			die("Can not seek file %s: %s\n", filename,
+					strerror(errno));
+
+		err = lseek(fd, 0, SEEK_SET);
+		if (err < 0)
+			die("Can not seek to the begin of file %s: %s\n",
+					filename, strerror(errno));
+	} else {
+		size = stats.st_size;
+	}
+
 	*r_size = size;
 	buf = xmalloc(size);
 	progress = 0;
-- 
1.6.5.2


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

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

* [PATCH 2/7] powerpc: dtb and purgatory support for ppc32
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 1/7] slurpfile: use lseek() on character nodes instead of fstat() for file size Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 3/7] powerpc32: pull in libfdt Sebastian Andrzej Siewior
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: Sebastian Andrzej Siewior, kexec

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Some code dtb scanning & filling has been borrowed from ppc64.
The old behavior is still available if compiled with GameCube,
other PowerPC platform use the can purgatory and specify a new
dtb.
Booting a self contained elf image (incl. dtb / without the need
for a bd sturct or the like) can be booted. The dtb support is currently
optional. That means if the elf image does not contain a dtb file then
the user has to supply a complete dtb (including mem size, command line,
bus freq., mac addr, ...)

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kexec/arch/ppc/kexec-elf-ppc.c     |  108 +++++++---
 kexec/arch/ppc/kexec-elf-rel-ppc.c |    4 +
 kexec/arch/ppc/kexec-ppc.c         |  449 +++++++++++++++++++++++++++++++++++-
 kexec/arch/ppc/kexec-ppc.h         |    7 +
 purgatory/arch/ppc/Makefile        |    1 +
 purgatory/arch/ppc/purgatory-ppc.c |    6 +
 purgatory/arch/ppc/v2wrap.S        |   66 ++++++
 7 files changed, 608 insertions(+), 33 deletions(-)
 create mode 100644 purgatory/arch/ppc/v2wrap.S

diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c
index 530e501..03b8a94 100644
--- a/kexec/arch/ppc/kexec-elf-ppc.c
+++ b/kexec/arch/ppc/kexec-elf-ppc.c
@@ -91,16 +91,6 @@ int elf_ppc_probe(const char *buf, off_t len)
 	return result;
 }
 
-void elf_ppc_usage(void)
-{
-	printf
-	    (
-	     "    --command-line=STRING Set the kernel command line to STRING.\n"
-	     "    --append=STRING       Set the kernel command line to STRING.\n"
-	     "    --gamecube=1|0        Enable/disable support for ELFs with changed\n"
-	     "                          addresses suitable for the GameCube.\n");
-}
-
 static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 {
 	struct mem_phdr *phdr, *phdr_end;
@@ -122,39 +112,56 @@ static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 	}
 }
 
+#define OPT_APPEND	(OPT_ARCH_MAX+0)
+#define OPT_GAMECUBE	(OPT_ARCH_MAX+1)
+#define OPT_DTB		(OPT_ARCH_MAX+2)
+static const struct option options[] = {
+	KEXEC_ARCH_OPTIONS
+	{"command-line", 1, 0, OPT_APPEND},
+	{"append",       1, 0, OPT_APPEND},
+	{"gamecube",     1, 0, OPT_GAMECUBE},
+	{"dtb",     1, 0, OPT_DTB},
+	{0, 0, 0, 0},
+};
+static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
+
+void elf_ppc_usage(void)
+{
+	printf(
+	     "    --command-line=STRING Set the kernel command line to STRING.\n"
+	     "    --append=STRING       Set the kernel command line to STRING.\n"
+	     "    --gamecube=1|0        Enable/disable support for ELFs with changed\n"
+	     "                          addresses suitable for the GameCube.\n"
+	     "     --dtb=<filename> Specify device tree blob file.\n"
+	     );
+}
+
 int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len, 
 	struct kexec_info *info)
 {
 	struct mem_ehdr ehdr;
+	char *command_line;
+	int command_line_len;
+	char *dtb;
+	int result;
+#ifdef WITH_GAMECUBE
+	int target_is_gamecube = 1;
 	char *arg_buf;
 	size_t arg_bytes;
 	unsigned long arg_base;
 	struct boot_notes *notes;
 	size_t note_bytes;
-	const char *command_line;
-	int command_line_len;
 	unsigned char *setup_start;
 	uint32_t setup_size;
-	int result;
-#ifdef WITH_GAMECUBE
-	int target_is_gamecube = 1;
 #else
 	int target_is_gamecube = 0;
+	unsigned int addr;
+	unsigned long dtb_addr;
 #endif
 	int opt;
-#define OPT_APPEND	(OPT_ARCH_MAX+0)
-#define OPT_GAMECUBE	(OPT_ARCH_MAX+1)
-	static const struct option options[] = {
-		KEXEC_ARCH_OPTIONS
-		{"command-line", 1, 0, OPT_APPEND},
-		{"append",       1, 0, OPT_APPEND},
-		{"gamecube",     1, 0, OPT_GAMECUBE},
-		{0, 0, 0, 0},
-	};
 
-	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
-
-	command_line = 0;
+	command_line = NULL;
+	dtb = NULL;
 	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch (opt) {
 		default:
@@ -171,6 +178,10 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		case OPT_GAMECUBE:
 			target_is_gamecube = atoi(optarg);
 			break;
+
+		case OPT_DTB:
+			dtb = optarg;
+			break;
 		}
 	}
 	command_line_len = 0;
@@ -194,6 +205,12 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		return result;
 	}
 
+	/*
+	 * In case of a toy we take the hardcoded things and an easy setup via
+	 * one of the assembly startups. Every thing else should be grown up
+	 * and go through the purgatory.
+	 */
+#ifdef WITH_GAMECUBE
 	if (target_is_gamecube) {
 		setup_start = setup_dol_start;
 		setup_size = setup_dol_size;
@@ -220,5 +237,42 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 	notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
 
 	info->entry = (void *)arg_base;
+#else
+	elf_rel_build_load(info, &info->rhdr, (const char *)purgatory,
+			purgatory_size, 0, elf_max_addr(&ehdr), 1, 0);
+
+	if (dtb) {
+		char *blob_buf;
+		off_t blob_size = 0;
+
+		/* Grab device tree from buffer */
+		blob_buf = slurp_file(dtb, &blob_size);
+		dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
+				KERNEL_ACCESS_TOP, -1);
+		if (command_line)
+			die("Don't consider command line because dtb is supplied\n");
+	} else {
+		die("Missing dtb.\n");
+	}
+
+	/* set various variables for the purgatory */
+	addr = ehdr.e_entry;
+	elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
+
+	addr = dtb_addr;
+	elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr));
+
+	addr = rmo_top;
+	elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr));
+
+#define PUL_STACK_SIZE	(16 * 1024)
+	addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, elf_max_addr(&ehdr), 1);
+	addr += PUL_STACK_SIZE;
+	elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr));
+#undef PUL_STACK_SIZE
+
+	addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
+	info->entry = (void *)addr;
+#endif
 	return 0;
 }
diff --git a/kexec/arch/ppc/kexec-elf-rel-ppc.c b/kexec/arch/ppc/kexec-elf-rel-ppc.c
index 7aa92db..90a66f4 100644
--- a/kexec/arch/ppc/kexec-elf-rel-ppc.c
+++ b/kexec/arch/ppc/kexec-elf-rel-ppc.c
@@ -31,6 +31,10 @@ void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), unsigned long r_type,
 		*(uint16_t *)location = value;
 		break;
 		
+	case R_PPC_ADDR16_HI:
+		*(uint16_t *)location = (value>>16) & 0xffff;
+		break;
+
 	case R_PPC_ADDR16_HA:
 		/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
 		   (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
index a77804f..ac0daad 100644
--- a/kexec/arch/ppc/kexec-ppc.c
+++ b/kexec/arch/ppc/kexec-ppc.c
@@ -12,6 +12,12 @@
 #include <stdint.h>
 #include <string.h>
 #include <getopt.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include "../../kexec.h"
 #include "../../kexec-syscall.h"
 #include "kexec-ppc.h"
@@ -22,13 +28,10 @@
 #ifdef WITH_GAMECUBE
 #define MAX_MEMORY_RANGES  64
 static struct memory_range memory_range[MAX_MEMORY_RANGES];
-#endif
 
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **UNUSED(range), int *UNUSED(ranges),
-		      unsigned long UNUSED(kexec_flags))
+static int get_memory_ranges_gc(struct memory_range **range, int *ranges,
+					unsigned long UNUSED(kexec_flags))
 {
-#ifdef WITH_GAMECUBE
 	int memory_ranges = 0;
 
 	/* RAM - lowmem used by DOLs - framebuffer */
@@ -39,9 +42,443 @@ int get_memory_ranges(struct memory_range **UNUSED(range), int *UNUSED(ranges),
 	*range = memory_range;
 	*ranges = memory_ranges;
 	return 0;
+}
 #else
-	fprintf(stderr, "%s(): Unsupported platform\n", __func__);
+static int use_new_dtb;
+static int max_memory_ranges;
+static int nr_memory_ranges, nr_exclude_ranges;
+static struct memory_range *exclude_range;
+static struct memory_range *memory_range;
+static struct memory_range *base_memory_range;
+static uint64_t memory_max;
+uint64_t rmo_top;
+unsigned int rtas_base, rtas_size;
+
+/*
+ * Count the memory nodes under /proc/device-tree and populate the
+ * max_memory_ranges variable. This variable replaces MAX_MEMORY_RANGES
+ * macro used earlier.
+ */
+static int count_memory_ranges(void)
+{
+	char device_tree[256] = "/proc/device-tree/";
+	struct dirent *dentry;
+	DIR *dir;
+
+	if ((dir = opendir(device_tree)) == NULL) {
+		perror(device_tree);
+		return -1;
+	}
+
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "memory@", 7) &&
+				strcmp(dentry->d_name, "memory"))
+			continue;
+		max_memory_ranges++;
+	}
+
+	/* need to add extra region for retained initrd */
+	if (use_new_dtb) {
+		max_memory_ranges++;
+	}
+
+	closedir(dir);
+	return 0;
+
+}
+
+ static void cleanup_memory_ranges(void)
+ {
+	 free(memory_range);
+	 free(base_memory_range);
+	 free(exclude_range);
+ }
+
+/*
+ * Allocate memory for various data structures used to hold
+ * values of different memory ranges
+ */
+static int alloc_memory_ranges(void)
+{
+	int memory_range_len;
+
+	memory_range_len = sizeof(struct memory_range) * max_memory_ranges;
+
+	memory_range = malloc(memory_range_len);
+	if (!memory_range)
+		return -1;
+
+	base_memory_range = malloc(memory_range_len);
+	if (!base_memory_range)
+		goto err1;
+
+	exclude_range = malloc(memory_range_len);
+	if (!exclude_range)
+		goto err1;
+
+	memset(memory_range, 0, memory_range_len);
+	memset(base_memory_range, 0, memory_range_len);
+	memset(exclude_range, 0, memory_range_len);
+	return 0;
+
+err1:
+	fprintf(stderr, "memory range structure allocation failure\n");
+	cleanup_memory_ranges();
+	return -1;
+}
+
+/* Sort the exclude ranges in memory */
+static int sort_ranges(void)
+{
+	int i, j;
+	uint64_t tstart, tend;
+	for (i = 0; i < nr_exclude_ranges - 1; i++) {
+		for (j = 0; j < nr_exclude_ranges - i - 1; j++) {
+			if (exclude_range[j].start > exclude_range[j+1].start) {
+				tstart = exclude_range[j].start;
+				tend = exclude_range[j].end;
+				exclude_range[j].start = exclude_range[j+1].start;
+				exclude_range[j].end = exclude_range[j+1].end;
+				exclude_range[j+1].start = tstart;
+				exclude_range[j+1].end = tend;
+			}
+		}
+	}
+	return 0;
+}
+
+/* Sort the base ranges in memory - this is useful for ensuring that our
+ * ranges are in ascending order, even if device-tree read of memory nodes
+ * is done differently. Also, could be used for other range coalescing later
+ */
+static int sort_base_ranges(void)
+{
+	int i, j;
+	unsigned long long tstart, tend;
+
+	for (i = 0; i < nr_memory_ranges - 1; i++) {
+		for (j = 0; j < nr_memory_ranges - i - 1; j++) {
+			if (base_memory_range[j].start > base_memory_range[j+1].start) {
+				tstart = base_memory_range[j].start;
+				tend = base_memory_range[j].end;
+				base_memory_range[j].start = base_memory_range[j+1].start;
+				base_memory_range[j].end = base_memory_range[j+1].end;
+				base_memory_range[j+1].start = tstart;
+				base_memory_range[j+1].end = tend;
+			}
+		}
+	}
+	return 0;
+}
+
+
+#define MAXBYTES 128
+
+/* Get base memory ranges */
+static int get_base_ranges(void)
+{
+	int local_memory_ranges = 0;
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	char buf[MAXBYTES];
+	DIR *dir, *dmem;
+	FILE *file;
+	struct dirent *dentry, *mentry;
+	int n;
+
+	if ((dir = opendir(device_tree)) == NULL) {
+		perror(device_tree);
+		return -1;
+	}
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "memory@", 7) &&
+				strcmp(dentry->d_name, "memory"))
+			continue;
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		if ((dmem = opendir(fname)) == NULL) {
+			perror(fname);
+			closedir(dir);
+			return -1;
+		}
+		while ((mentry = readdir(dmem)) != NULL) {
+			if (strcmp(mentry->d_name, "reg"))
+				continue;
+			strcat(fname, "/reg");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(dmem);
+				closedir(dir);
+				return -1;
+			}
+			if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+				perror(fname);
+				fclose(file);
+				closedir(dmem);
+				closedir(dir);
+				return -1;
+			}
+			if (local_memory_ranges >= max_memory_ranges) {
+				fclose(file);
+				break;
+			}
+			base_memory_range[local_memory_ranges].start =
+				((uint32_t *)buf)[0];
+			base_memory_range[local_memory_ranges].end  =
+				base_memory_range[local_memory_ranges].start +
+				((uint32_t *)buf)[1];
+			base_memory_range[local_memory_ranges].type = RANGE_RAM;
+			local_memory_ranges++;
+			dbgprintf("%016llx-%016llx : %x\n",
+					base_memory_range[local_memory_ranges-1].start,
+					base_memory_range[local_memory_ranges-1].end,
+					base_memory_range[local_memory_ranges-1].type);
+			fclose(file);
+		}
+		closedir(dmem);
+	}
+	closedir(dir);
+	nr_memory_ranges = local_memory_ranges;
+	sort_base_ranges();
+	memory_max = base_memory_range[nr_memory_ranges - 1].end;
+#ifdef DEBUG
+	fprintf(stderr, "get base memory ranges:%d\n", nr_memory_ranges);
+#endif
+	return 0;
+}
+
+/* Get devtree details and create exclude_range array
+ * Also create usablemem_ranges for KEXEC_ON_CRASH
+ */
+static int get_devtree_details(unsigned long kexec_flags)
+{
+	uint64_t rmo_base;
+	char buf[MAXBYTES];
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	DIR *dir, *cdir;
+	FILE *file;
+	struct dirent *dentry;
+	int n, i = 0;
+
+	if ((dir = opendir(device_tree)) == NULL) {
+		perror(device_tree);
+		return -1;
+	}
+
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "chosen", 6) &&
+				strncmp(dentry->d_name, "memory@", 7) &&
+				strcmp(dentry->d_name, "memory") &&
+				strncmp(dentry->d_name, "rtas", 4))
+			continue;
+
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		if ((cdir = opendir(fname)) == NULL) {
+			perror(fname);
+			goto error_opendir;
+		}
+
+		if (strncmp(dentry->d_name, "rtas", 4) == 0) {
+			strcat(fname, "/linux,rtas-base");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&rtas_base, sizeof(unsigned int), 1, file) != 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/rtas-size");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&rtas_size, sizeof(unsigned int), 1, file) != 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			closedir(cdir);
+			/* Add rtas to exclude_range */
+			exclude_range[i].start = rtas_base;
+			exclude_range[i].end = rtas_base + rtas_size;
+			i++;
+		} /* rtas */
+
+		if (!strncmp(dentry->d_name, "memory@", 7) ||
+				!strcmp(dentry->d_name, "memory")) {
+			strcat(fname, "/reg");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+				perror(fname);
+				goto error_openfile;
+			}
+			if (n == 8) {
+				rmo_base = ((uint32_t *)buf)[0];
+				rmo_top = rmo_base + ((uint32_t *)buf)[1];
+			} else if (n == 16) {
+				rmo_base = ((uint64_t *)buf)[0];
+				rmo_top = rmo_base + ((uint64_t *)buf)[1];
+			} else {
+				fprintf(stderr, "Mem node has invalid size: %d\n", n);
+				goto error_openfile;
+			}
+			if (rmo_top > 0x30000000UL)
+				rmo_top = 0x30000000UL;
+
+			fclose(file);
+			closedir(cdir);
+		} /* memory */
+	}
+	closedir(dir);
+
+	nr_exclude_ranges = i;
+
+	sort_ranges();
+
+#ifdef DEBUG
+	int k;
+	for (k = 0; k < i; k++)
+		fprintf(stderr, "exclude_range sorted exclude_range[%d] "
+				"start:%llx, end:%llx\n", k, exclude_range[k].start,
+				exclude_range[k].end);
+#endif
+	return 0;
+
+error_openfile:
+	fclose(file);
+error_opencdir:
+	closedir(cdir);
+error_opendir:
+	closedir(dir);
 	return -1;
+}
+
+
+/* Setup a sorted list of memory ranges. */
+static int setup_memory_ranges(unsigned long kexec_flags)
+{
+	int i, j = 0;
+
+	/* Get the base list of memory ranges from /proc/device-tree/memory
+	 * nodes. Build list of ranges to be excluded from valid memory
+	 */
+
+	if (get_base_ranges())
+		goto out;
+	if (get_devtree_details(kexec_flags))
+		goto out;
+
+	for (i = 0; i < nr_exclude_ranges; i++) {
+		/* If first exclude range does not start with 0, include the
+		 * first hole of valid memory from 0 - exclude_range[0].start
+		 */
+		if (i == 0) {
+			if (exclude_range[i].start != 0) {
+				memory_range[j].start = 0;
+				memory_range[j].end = exclude_range[i].start - 1;
+				memory_range[j].type = RANGE_RAM;
+				j++;
+			}
+		} /* i == 0 */
+		/* If the last exclude range does not end at memory_max, include
+		 * the last hole of valid memory from exclude_range[last].end -
+		 * memory_max
+		 */
+		if (i == nr_exclude_ranges - 1) {
+			if (exclude_range[i].end < memory_max) {
+				memory_range[j].start = exclude_range[i].end + 1;
+				memory_range[j].end = memory_max;
+				memory_range[j].type = RANGE_RAM;
+				j++;
+				/* Limit the end to rmo_top */
+				if (memory_range[j-1].start >= rmo_top) {
+					j--;
+					break;
+				}
+				if ((memory_range[j-1].start < rmo_top) &&
+						(memory_range[j-1].end >= rmo_top)) {
+					memory_range[j-1].end = rmo_top;
+					break;
+				}
+				continue;
+			}
+		} /* i == nr_exclude_ranges - 1 */
+		/* contiguous exclude ranges - skip */
+		if (exclude_range[i+1].start == exclude_range[i].end + 1)
+			continue;
+		memory_range[j].start = exclude_range[i].end + 1;
+		memory_range[j].end = exclude_range[i+1].start - 1;
+		memory_range[j].type = RANGE_RAM;
+		j++;
+		/* Limit range to rmo_top */
+		if (memory_range[j-1].start >= rmo_top) {
+			j--;
+			break;
+		}
+		if ((memory_range[j-1].start < rmo_top) &&
+				(memory_range[j-1].end >= rmo_top)) {
+			memory_range[j-1].end = rmo_top;
+			break;
+		}
+	}
+
+	/* fixup in case we have no exclude regions */
+	if (!j) {
+		memory_range[0].start = base_memory_range[0].start;
+		memory_range[0].end = rmo_top;
+		memory_range[0].type = RANGE_RAM;
+		nr_memory_ranges = 1;
+	} else
+		nr_memory_ranges = j;
+
+#ifdef DEBUG
+	int k;
+	for (k = 0; k < j; k++)
+		fprintf(stderr, "setup_memory_ranges memory_range[%d] "
+				"start:%llx, end:%llx\n", k, memory_range[k].start,
+				memory_range[k].end);
+#endif
+	return 0;
+
+out:
+	cleanup_memory_ranges();
+	return -1;
+}
+
+
+/* Return a list of valid memory ranges */
+int get_memory_ranges_dt(struct memory_range **range, int *ranges,
+		unsigned long kexec_flags)
+{
+	if (count_memory_ranges())
+		return -1;
+	if (alloc_memory_ranges())
+		return -1;
+	if (setup_memory_ranges(kexec_flags))
+		return -1;
+
+	*range = memory_range;
+	*ranges = nr_memory_ranges;
+	return 0;
+}
+#endif
+
+/* Return a sorted list of memory ranges. */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+					unsigned long kexec_flags)
+{
+#ifdef WITH_GAMECUBE
+	return get_memory_ranges_gc(range, ranges, kexec_flags);
+#else
+	return get_memory_ranges_dt(range, ranges, kexec_flags);
 #endif
 }
 
diff --git a/kexec/arch/ppc/kexec-ppc.h b/kexec/arch/ppc/kexec-ppc.h
index 6a40cc8..1b2b015 100644
--- a/kexec/arch/ppc/kexec-ppc.h
+++ b/kexec/arch/ppc/kexec-ppc.h
@@ -10,6 +10,7 @@ extern struct {
 
 extern unsigned char setup_dol_start[];
 extern uint32_t setup_dol_size;
+extern uint64_t rmo_top;
 
 extern struct {
 	uint32_t spr8;
@@ -25,4 +26,10 @@ int dol_ppc_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
 void dol_ppc_usage(void);
 
+/*
+ * During inital setup the kernel does not map the whole memory but a part of
+ * it. On Book-E that is 64MiB, 601 24MiB or 256MiB (if possible).
+ */
+#define KERNEL_ACCESS_TOP (24 * 1024 * 1024)
+
 #endif /* KEXEC_PPC_H */
diff --git a/purgatory/arch/ppc/Makefile b/purgatory/arch/ppc/Makefile
index 69fd46c..0dd18b6 100644
--- a/purgatory/arch/ppc/Makefile
+++ b/purgatory/arch/ppc/Makefile
@@ -2,6 +2,7 @@
 # Purgatory ppc
 #
 
+ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/misc.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/purgatory-ppc.c
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/console-ppc.c
diff --git a/purgatory/arch/ppc/purgatory-ppc.c b/purgatory/arch/ppc/purgatory-ppc.c
index 077f495..01d0f38 100644
--- a/purgatory/arch/ppc/purgatory-ppc.c
+++ b/purgatory/arch/ppc/purgatory-ppc.c
@@ -1,6 +1,12 @@
 #include <purgatory.h>
 #include "purgatory-ppc.h"
 
+unsigned int pul_stack = 0;
+unsigned int dt_offset = 0;
+unsigned int kernel = 0;
+unsigned int epapr_magic = 0;
+unsigned int mem_size = 0;
+
 void setup_arch(void)
 {
 	/* Nothing for now */
diff --git a/purgatory/arch/ppc/v2wrap.S b/purgatory/arch/ppc/v2wrap.S
new file mode 100644
index 0000000..79d188f
--- /dev/null
+++ b/purgatory/arch/ppc/v2wrap.S
@@ -0,0 +1,66 @@
+#
+#  kexec: Linux boots Linux
+#
+#  Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
+#  Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
+#  Copyright (C) 2008, Sebastian Andrzej Siewior (bigeasy@linutronix.de), linutronix
+#
+#  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 (version 2 of the License).
+#
+#  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#include "ppc_asm.h"
+
+# v2wrap.S
+# a wrapper to call purgatory code
+# Invokes ppc kernel with the arguments according to ePAPR v1.0
+# It assumes that the MSR is allready correct.
+
+# calling convention:
+#  no register are considred
+#
+
+#define LOADADDR(rn,name)	\
+	lis     rn,name##@h;	\
+	ori     rn,rn,name##@l;	\
+
+	.globl purgatory_start
+purgatory_start:
+
+	LOADADDR(r6,pul_stack)
+	lwz	r1,0(r6)		#setup stack
+
+	subi	r1, r1, 112
+	bl	purgatory
+	nop
+
+	LOADADDR(r6,kernel)
+	lwz	r4,0(r6)		# load the kernel address
+	mtlr	r4			# prepare branch too
+
+	LOADADDR(r6, dt_offset)
+	lwz	r3, 0(r6)		# load device-tree address
+
+	li	r4, 0
+	li	r5, 0
+
+	LOADADDR(r6, epapr_magic)	# ePAPR magic value
+	lwz	r6, 0(r6)
+
+	LOADADDR(r7, mem_size)		# the Initial Mapped Area
+	lwz	r7, 0(r6)
+
+	li	r8, 0
+	li	r9, 0
+
+	blr				# start kernel
-- 
1.6.5.2


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

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

* [PATCH 3/7] powerpc32: pull in libfdt
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 1/7] slurpfile: use lseek() on character nodes instead of fstat() for file size Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 2/7] powerpc: dtb and purgatory support for ppc32 Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  2010-03-31 22:58   ` Simon Horman
  2010-03-31  8:24 ` [PATCH 4/7] powerpc32: add support to fixup the dtb Sebastian Andrzej Siewior
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: Sebastian Andrzej Siewior, kexec

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

This is v1.2.0 of libfdt from the dtc project which is available at
 git://www.jdl.com/software/dtc.git

The other files
- include/page.h
- include/types.h
- libfdt-wrapper.c
- ops.h

are part of the glue code which is used the powerpc boot wrapper code
is comming from the Linux kernel v2.6.27-rc6 and has been modified a
little to fit.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kexec/arch/ppc/Makefile                 |   10 +-
 kexec/arch/ppc/include/page.h           |   34 +
 kexec/arch/ppc/include/types.h          |   27 +
 kexec/arch/ppc/libfdt-wrapper.c         |  189 ++++++
 kexec/arch/ppc/libfdt/Makefile.libfdt   |    8 +
 kexec/arch/ppc/libfdt/TODO              |    3 +
 kexec/arch/ppc/libfdt/fdt.c             |  201 ++++++
 kexec/arch/ppc/libfdt/fdt.h             |   60 ++
 kexec/arch/ppc/libfdt/fdt_ro.c          |  466 +++++++++++++
 kexec/arch/ppc/libfdt/fdt_rw.c          |  463 +++++++++++++
 kexec/arch/ppc/libfdt/fdt_strerror.c    |   96 +++
 kexec/arch/ppc/libfdt/fdt_sw.c          |  257 ++++++++
 kexec/arch/ppc/libfdt/fdt_wip.c         |  145 +++++
 kexec/arch/ppc/libfdt/libfdt.h          | 1076 +++++++++++++++++++++++++++++++
 kexec/arch/ppc/libfdt/libfdt_env.h      |   23 +
 kexec/arch/ppc/libfdt/libfdt_internal.h |   95 +++
 kexec/arch/ppc/ops.h                    |  151 +++++
 17 files changed, 3303 insertions(+), 1 deletions(-)
 create mode 100644 kexec/arch/ppc/include/page.h
 create mode 100644 kexec/arch/ppc/include/types.h
 create mode 100644 kexec/arch/ppc/libfdt-wrapper.c
 create mode 100644 kexec/arch/ppc/libfdt/Makefile.libfdt
 create mode 100644 kexec/arch/ppc/libfdt/TODO
 create mode 100644 kexec/arch/ppc/libfdt/fdt.c
 create mode 100644 kexec/arch/ppc/libfdt/fdt.h
 create mode 100644 kexec/arch/ppc/libfdt/fdt_ro.c
 create mode 100644 kexec/arch/ppc/libfdt/fdt_rw.c
 create mode 100644 kexec/arch/ppc/libfdt/fdt_strerror.c
 create mode 100644 kexec/arch/ppc/libfdt/fdt_sw.c
 create mode 100644 kexec/arch/ppc/libfdt/fdt_wip.c
 create mode 100644 kexec/arch/ppc/libfdt/libfdt.h
 create mode 100644 kexec/arch/ppc/libfdt/libfdt_env.h
 create mode 100644 kexec/arch/ppc/libfdt/libfdt_internal.h
 create mode 100644 kexec/arch/ppc/ops.h

diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index 1550c20..0ef7ca4 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -1,6 +1,8 @@
 #
 # kexec ppc (linux booting linux)
 #
+include kexec/arch/ppc/libfdt/Makefile.libfdt
+
 ppc_KEXEC_SRCS =  kexec/arch/ppc/kexec-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-rel-ppc.c
@@ -8,7 +10,13 @@ ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-dol-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
 
+libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c
+libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/arch/ppc/libfdt/%)
+
+CPPFLAGS+=-I$(srcdir)/kexec/arch/$(ARCH)/libfdt
+
+ppc_KEXEC_SRCS += $(libfdt_SRCS)
+
 dist += kexec/arch/ppc/Makefile $(ppc_KEXEC_SRCS)			\
 	kexec/arch/ppc/kexec-ppc.h kexec/arch/ppc/ppc_asm.h		\
 	kexec/arch/ppc/include/arch/options.h
-
diff --git a/kexec/arch/ppc/include/page.h b/kexec/arch/ppc/include/page.h
new file mode 100644
index 0000000..14eca30
--- /dev/null
+++ b/kexec/arch/ppc/include/page.h
@@ -0,0 +1,34 @@
+#ifndef _PPC_BOOT_PAGE_H
+#define _PPC_BOOT_PAGE_H
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ * 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.
+ */
+
+#ifdef __ASSEMBLY__
+#define ASM_CONST(x) x
+#else
+#define __ASM_CONST(x) x##UL
+#define ASM_CONST(x) __ASM_CONST(x)
+#endif
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(ASM_CONST(1) << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr,size)	(((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size)	((addr)&(~((size)-1)))
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr,size)     _ALIGN_UP(addr,size)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	_ALIGN(addr, PAGE_SIZE)
+
+#endif				/* _PPC_BOOT_PAGE_H */
diff --git a/kexec/arch/ppc/include/types.h b/kexec/arch/ppc/include/types.h
new file mode 100644
index 0000000..31393d1
--- /dev/null
+++ b/kexec/arch/ppc/include/types.h
@@ -0,0 +1,27 @@
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+typedef unsigned char		u8;
+typedef unsigned short		u16;
+typedef unsigned int		u32;
+typedef unsigned long long	u64;
+typedef signed char		s8;
+typedef short			s16;
+typedef int			s32;
+typedef long long		s64;
+
+#define min(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);	\
+	_x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);	\
+	_x > _y ? _x : _y; })
+
+#endif /* _TYPES_H_ */
diff --git a/kexec/arch/ppc/libfdt-wrapper.c b/kexec/arch/ppc/libfdt-wrapper.c
new file mode 100644
index 0000000..f56ccc0
--- /dev/null
+++ b/kexec/arch/ppc/libfdt-wrapper.c
@@ -0,0 +1,189 @@
+/*
+ * This file does the necessary interface mapping between the bootwrapper
+ * device tree operations and the interface provided by shared source
+ * files flatdevicetree.[ch].
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <page.h>
+#include <libfdt.h>
+#include "ops.h"
+
+#define DEBUG	0
+#define BAD_ERROR(err)	(((err) < 0) \
+			 && ((err) != -FDT_ERR_NOTFOUND) \
+			 && ((err) != -FDT_ERR_EXISTS))
+
+#define check_err(err) \
+	({ \
+		if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \
+			printf("%s():%d  %s\n\r", __func__, __LINE__, \
+			       fdt_strerror(err)); \
+		if (BAD_ERROR(err)) \
+			exit(1); \
+		(err < 0) ? -1 : 0; \
+	})
+
+#define offset_devp(off)	\
+	({ \
+		int _offset = (off); \
+		check_err(_offset) ? NULL : (void *)(_offset+1); \
+	})
+
+#define devp_offset_find(devp)	(((int)(devp))-1)
+#define devp_offset(devp)	(devp ? ((int)(devp))-1 : 0)
+
+static void *fdt;
+static void *buf; /* = NULL */
+struct dt_ops dt_ops;
+
+#define EXPAND_GRANULARITY	1024
+
+static void expand_buf(int minexpand)
+{
+	int size = fdt_totalsize(fdt);
+	int rc;
+
+	size = _ALIGN(size + minexpand, EXPAND_GRANULARITY);
+	buf = realloc(buf, size);
+	if (!buf)
+		fatal("Couldn't find %d bytes to expand device tree\n\r", size);
+	rc = fdt_open_into(fdt, buf, size);
+	if (rc != 0)
+		fatal("Couldn't expand fdt into new buffer: %s\n\r",
+		      fdt_strerror(rc));
+
+	fdt = buf;
+}
+
+static void *fdt_wrapper_finddevice(const char *path)
+{
+	return offset_devp(fdt_path_offset(fdt, path));
+}
+
+static int fdt_wrapper_getprop(const void *devp, const char *name,
+			       void *buf, const int buflen)
+{
+	const void *p;
+	int len;
+
+	p = fdt_getprop(fdt, devp_offset(devp), name, &len);
+	if (!p)
+		return check_err(len);
+	memcpy(buf, p, min(len, buflen));
+	return len;
+}
+
+static int fdt_wrapper_setprop(const void *devp, const char *name,
+			       const void *buf, const int len)
+{
+	int rc;
+
+	rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
+	if (rc == -FDT_ERR_NOSPACE) {
+		expand_buf(len + 16);
+		rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
+	}
+
+	return check_err(rc);
+}
+
+static void *fdt_wrapper_get_parent(const void *devp)
+{
+	return offset_devp(fdt_parent_offset(fdt, devp_offset(devp)));
+}
+
+static void *fdt_wrapper_create_node(const void *devp, const char *name)
+{
+	int offset;
+
+	offset = fdt_add_subnode(fdt, devp_offset(devp), name);
+	if (offset == -FDT_ERR_NOSPACE) {
+		expand_buf(strlen(name) + 16);
+		offset = fdt_add_subnode(fdt, devp_offset(devp), name);
+	}
+
+	return offset_devp(offset);
+}
+
+static void *fdt_wrapper_find_node_by_prop_value(const void *prev,
+						 const char *name,
+						 const char *val,
+						 int len)
+{
+	int offset = fdt_node_offset_by_prop_value(fdt, devp_offset_find(prev),
+						   name, val, len);
+	return offset_devp(offset);
+}
+
+static void *fdt_wrapper_find_node_by_compatible(const void *prev,
+						 const char *val)
+{
+	int offset = fdt_node_offset_by_compatible(fdt, devp_offset_find(prev),
+						   val);
+	return offset_devp(offset);
+}
+
+static char *fdt_wrapper_get_path(const void *devp, char *buf, int len)
+{
+	int rc;
+
+	rc = fdt_get_path(fdt, devp_offset(devp), buf, len);
+	if (check_err(rc))
+		return NULL;
+	return buf;
+}
+
+static unsigned long fdt_wrapper_finalize(void)
+{
+	int rc;
+
+	rc = fdt_pack(fdt);
+	if (rc != 0)
+		fatal("Couldn't pack flat tree: %s\n\r",
+		      fdt_strerror(rc));
+	return (unsigned long)fdt;
+}
+
+void fdt_init(void *blob)
+{
+	int err;
+	int bufsize;
+
+	dt_ops.finddevice = fdt_wrapper_finddevice;
+	dt_ops.getprop = fdt_wrapper_getprop;
+	dt_ops.setprop = fdt_wrapper_setprop;
+	dt_ops.get_parent = fdt_wrapper_get_parent;
+	dt_ops.create_node = fdt_wrapper_create_node;
+	dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value;
+	dt_ops.find_node_by_compatible = fdt_wrapper_find_node_by_compatible;
+	dt_ops.get_path = fdt_wrapper_get_path;
+	dt_ops.finalize = fdt_wrapper_finalize;
+
+	/* Make sure the dt blob is the right version and so forth */
+	fdt = blob;
+	bufsize = fdt_totalsize(fdt);
+
+	err = fdt_open_into(fdt, fdt, bufsize);
+	if (err != 0)
+		fatal("fdt_init(): %s\n\r", fdt_strerror(err));
+}
diff --git a/kexec/arch/ppc/libfdt/Makefile.libfdt b/kexec/arch/ppc/libfdt/Makefile.libfdt
new file mode 100644
index 0000000..6c42acf
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/Makefile.libfdt
@@ -0,0 +1,8 @@
+# Makefile.libfdt
+#
+# This is not a complete Makefile of itself.  Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+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)
diff --git a/kexec/arch/ppc/libfdt/TODO b/kexec/arch/ppc/libfdt/TODO
new file mode 100644
index 0000000..288437e
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/TODO
@@ -0,0 +1,3 @@
+- Tree traversal functions
+- Graft function
+- Complete libfdt.h documenting comments
diff --git a/kexec/arch/ppc/libfdt/fdt.c b/kexec/arch/ppc/libfdt/fdt.c
new file mode 100644
index 0000000..2acaec5
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt.c
@@ -0,0 +1,201 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		/* Complete tree */
+		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+		/* Unfinished sequential-write blob */
+		if (fdt_size_dt_struct(fdt) == 0)
+			return -FDT_ERR_BADSTATE;
+	} else {
+		return -FDT_ERR_BADMAGIC;
+	}
+
+	return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int len)
+{
+	const char *p;
+
+	if (fdt_version(fdt) >= 0x11)
+		if (((offset + len) < offset)
+		    || ((offset + len) > fdt_size_dt_struct(fdt)))
+			return NULL;
+
+	p = _fdt_offset_ptr(fdt, offset);
+
+	if (p + len < p)
+		return NULL;
+	return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
+{
+	const uint32_t *tagp, *lenp;
+	uint32_t tag;
+	const char *p;
+
+	if (offset % FDT_TAGSIZE)
+		return -1;
+
+	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+	if (! tagp)
+		return FDT_END; /* premature end */
+	tag = fdt32_to_cpu(*tagp);
+	offset += FDT_TAGSIZE;
+
+	switch (tag) {
+	case FDT_BEGIN_NODE:
+		/* skip name */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (! p)
+			return FDT_END;
+		break;
+	case FDT_PROP:
+		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+		if (! lenp)
+			return FDT_END;
+		/* skip name offset, length and value */
+		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
+		break;
+	}
+
+	if (nextoffset)
+		*nextoffset = FDT_TAGALIGN(offset);
+
+	return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+	if ((offset < 0) || (offset % FDT_TAGSIZE)
+	    || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+		return -FDT_ERR_BADOFFSET;
+
+	return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+	int nextoffset = 0;
+	uint32_t tag;
+
+	if (offset >= 0)
+		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+			return nextoffset;
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		case FDT_BEGIN_NODE:
+			if (depth)
+				(*depth)++;
+			break;
+
+		case FDT_END_NODE:
+			if (depth)
+				(*depth)--;
+			break;
+
+		case FDT_END:
+			return -FDT_ERR_NOTFOUND;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (tag != FDT_BEGIN_NODE);
+
+	return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+	int len = strlen(s) + 1;
+	const char *last = strtab + tabsize - len;
+	const char *p;
+
+	for (p = strtab; p <= last; p++)
+		if (memcmp(p, s, len) == 0)
+			return p;
+	return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+	FDT_CHECK_HEADER(fdt);
+
+	if (fdt_totalsize(fdt) > bufsize)
+		return -FDT_ERR_NOSPACE;
+
+	memmove(buf, fdt, fdt_totalsize(fdt));
+	return 0;
+}
diff --git a/kexec/arch/ppc/libfdt/fdt.h b/kexec/arch/ppc/libfdt/fdt.h
new file mode 100644
index 0000000..48ccfd9
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+	uint32_t magic;			 /* magic word FDT_MAGIC */
+	uint32_t totalsize;		 /* total size of DT block */
+	uint32_t off_dt_struct;		 /* offset to structure */
+	uint32_t off_dt_strings;	 /* offset to strings */
+	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */
+	uint32_t version;		 /* format version */
+	uint32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	uint32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	uint32_t size_dt_struct;	 /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+	uint64_t address;
+	uint64_t size;
+};
+
+struct fdt_node_header {
+	uint32_t tag;
+	char name[0];
+};
+
+struct fdt_property {
+	uint32_t tag;
+	uint32_t len;
+	uint32_t nameoff;
+	char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE	0x1		/* Start node: full name */
+#define FDT_END_NODE	0x2		/* End node */
+#define FDT_PROP	0x3		/* Property: name off,
+					   size, content */
+#define FDT_NOP		0x4		/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(uint32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/kexec/arch/ppc/libfdt/fdt_ro.c b/kexec/arch/ppc/libfdt/fdt_ro.c
new file mode 100644
index 0000000..129b532
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt_ro.c
@@ -0,0 +1,466 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+			    const char *s, int len)
+{
+	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+	if (! p)
+		/* short match */
+		return 0;
+
+	if (memcmp(p, s, len) != 0)
+		return 0;
+
+	if (p[len] == '\0')
+		return 1;
+	else if (!memchr(s, '@', len) && (p[len] == '@'))
+		return 1;
+	else
+		return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+	FDT_CHECK_HEADER(fdt);
+	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+	return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+	int i = 0;
+
+	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+		i++;
+	return i;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+			       const char *name, int namelen)
+{
+	int depth;
+
+	FDT_CHECK_HEADER(fdt);
+
+	for (depth = 0;
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth < 0)
+			return -FDT_ERR_NOTFOUND;
+		else if ((depth == 1)
+			 && _fdt_nodename_eq(fdt, offset, name, namelen))
+			return offset;
+	}
+
+	return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+		       const char *name)
+{
+	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+	const char *end = path + strlen(path);
+	const char *p = path;
+	int offset = 0;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (*path != '/')
+		return -FDT_ERR_BADPATH;
+
+	while (*p) {
+		const char *q;
+
+		while (*p == '/')
+			p++;
+		if (! *p)
+			return offset;
+		q = strchr(p, '/');
+		if (! q)
+			q = end;
+
+		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+		if (offset < 0)
+			return offset;
+
+		p = q;
+	}
+
+	return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+	int err;
+
+	if (((err = fdt_check_header(fdt)) != 0)
+	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+			goto fail;
+
+	if (len)
+		*len = strlen(nh->name);
+
+	return nh->name;
+
+ fail:
+	if (len)
+		*len = err;
+	return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+					    int nodeoffset,
+					    const char *name, int *lenp)
+{
+	uint32_t tag;
+	const struct fdt_property *prop;
+	int namestroff;
+	int offset, nextoffset;
+	int err;
+
+	if (((err = fdt_check_header(fdt)) != 0)
+	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+			goto fail;
+
+	nextoffset = err;
+	do {
+		offset = nextoffset;
+
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		switch (tag) {
+		case FDT_END:
+			err = -FDT_ERR_TRUNCATED;
+			goto fail;
+
+		case FDT_BEGIN_NODE:
+		case FDT_END_NODE:
+		case FDT_NOP:
+			break;
+
+		case FDT_PROP:
+			err = -FDT_ERR_BADSTRUCTURE;
+			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
+			if (! prop)
+				goto fail;
+			namestroff = fdt32_to_cpu(prop->nameoff);
+			if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
+				/* Found it! */
+				int len = fdt32_to_cpu(prop->len);
+				prop = fdt_offset_ptr(fdt, offset,
+						      sizeof(*prop)+len);
+				if (! prop)
+					goto fail;
+
+				if (lenp)
+					*lenp = len;
+
+				return prop;
+			}
+			break;
+
+		default:
+			err = -FDT_ERR_BADSTRUCTURE;
+			goto fail;
+		}
+	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+
+	err = -FDT_ERR_NOTFOUND;
+ fail:
+	if (lenp)
+		*lenp = err;
+	return NULL;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+		  const char *name, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property(fdt, nodeoffset, name, lenp);
+	if (! prop)
+		return NULL;
+
+	return prop->data;
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+	const uint32_t *php;
+	int len;
+
+	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+	if (!php || (len != sizeof(*php)))
+		return 0;
+
+	return fdt32_to_cpu(*php);
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+	int pdepth = 0, p = 0;
+	int offset, depth, namelen;
+	const char *name;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (buflen < 2)
+		return -FDT_ERR_NOSPACE;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (pdepth < depth)
+			continue; /* overflowed buffer */
+
+		while (pdepth > depth) {
+			do {
+				p--;
+			} while (buf[p-1] != '/');
+			pdepth--;
+		}
+
+		name = fdt_get_name(fdt, offset, &namelen);
+		if (!name)
+			return namelen;
+		if ((p + namelen + 1) <= buflen) {
+			memcpy(buf + p, name, namelen);
+			p += namelen;
+			buf[p++] = '/';
+			pdepth++;
+		}
+
+		if (offset == nodeoffset) {
+			if (pdepth < (depth + 1))
+				return -FDT_ERR_NOSPACE;
+
+			if (p > 1) /* special case so that root path is "/", not "" */
+				p--;
+			buf[p] = '\0';
+			return p;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth)
+{
+	int offset, depth;
+	int supernodeoffset = -FDT_ERR_INTERNAL;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (supernodedepth < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth == supernodedepth)
+			supernodeoffset = offset;
+
+		if (offset == nodeoffset) {
+			if (nodedepth)
+				*nodedepth = depth;
+
+			if (supernodedepth > depth)
+				return -FDT_ERR_NOTFOUND;
+			else
+				return supernodeoffset;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+	int nodedepth;
+	int err;
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+	if (err)
+		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+	return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+	int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+	if (nodedepth < 0)
+		return nodedepth;
+	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+					    nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen)
+{
+	int offset;
+	const void *val;
+	int len;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_getprop(), then if that didn't
+	 * find what we want, we scan over them again making our way
+	 * to the next node.  Still it's the easiest to implement
+	 * approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		val = fdt_getprop(fdt, offset, propname, &len);
+		if (val && (len == proplen)
+		    && (memcmp(val, propval, len) == 0))
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+	if ((phandle == 0) || (phandle == -1))
+		return -FDT_ERR_BADPHANDLE;
+	phandle = cpu_to_fdt32(phandle);
+	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
+					     &phandle, sizeof(phandle));
+}
+
+int _stringlist_contains(const char *strlist, int listlen, const char *str)
+{
+	int len = strlen(str);
+	const char *p;
+
+	while (listlen >= len) {
+		if (memcmp(str, strlist, len+1) == 0)
+			return 1;
+		p = memchr(strlist, '\0', listlen);
+		if (!p)
+			return 0; /* malformed strlist.. */
+		listlen -= (p-strlist) + 1;
+		strlist = p + 1;
+	}
+	return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible)
+{
+	const void *prop;
+	int len;
+
+	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+	if (!prop)
+		return len;
+	if (_stringlist_contains(prop, len, compatible))
+		return 0;
+	else
+		return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible)
+{
+	int offset, err;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_node_check_compatible(), then if
+	 * that didn't find what we want, we scan over them again
+	 * making our way to the next node.  Still it's the easiest to
+	 * implement approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		err = fdt_node_check_compatible(fdt, offset, compatible);
+		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+			return err;
+		else if (err == 0)
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
diff --git a/kexec/arch/ppc/libfdt/fdt_rw.c b/kexec/arch/ppc/libfdt/fdt_rw.c
new file mode 100644
index 0000000..8e7ec4c
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt_rw.c
@@ -0,0 +1,463 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+			      int mem_rsv_size, int struct_size)
+{
+	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+		|| (fdt_off_dt_struct(fdt) <
+		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+		|| (fdt_off_dt_strings(fdt) <
+		    (fdt_off_dt_struct(fdt) + struct_size))
+		|| (fdt_totalsize(fdt) <
+		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+	FDT_CHECK_HEADER(fdt);
+
+	if (fdt_version(fdt) < 17)
+		return -FDT_ERR_BADVERSION;
+	if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+				   fdt_size_dt_struct(fdt)))
+		return -FDT_ERR_BADLAYOUT;
+	if (fdt_version(fdt) > 17)
+		fdt_set_version(fdt, 17);
+
+	return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = _fdt_rw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static inline int _fdt_data_size(void *fdt)
+{
+	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+	char *p = splicepoint;
+	char *end = (char *)fdt + _fdt_data_size(fdt);
+
+	if (((p + oldlen) < p) || ((p + oldlen) > end))
+		return -FDT_ERR_BADOFFSET;
+	if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+		return -FDT_ERR_NOSPACE;
+	memmove(p + newlen, p + oldlen, end - p - oldlen);
+	return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+			       int oldn, int newn)
+{
+	int delta = (newn - oldn) * sizeof(*p);
+	int err;
+	err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+	if (err)
+		return err;
+	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+			      int oldlen, int newlen)
+{
+	int delta = newlen - oldlen;
+	int err;
+
+	if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+		return err;
+
+	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+	void *p = (char *)fdt
+		+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+	int err;
+
+	if ((err = _fdt_splice(fdt, p, 0, newlen)))
+		return err;
+
+	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+	return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+	const char *p;
+	char *new;
+	int len = strlen(s) + 1;
+	int err;
+
+	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+	if (p)
+		/* found it */
+		return (p - strtab);
+
+	new = strtab + fdt_size_dt_strings(fdt);
+	err = _fdt_splice_string(fdt, len);
+	if (err)
+		return err;
+
+	memcpy(new, s, len);
+	return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+	err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+	if (err)
+		return err;
+
+	re->address = cpu_to_fdt64(address);
+	re->size = cpu_to_fdt64(size);
+	return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	if (n >= fdt_num_mem_rsv(fdt))
+		return -FDT_ERR_NOTFOUND;
+
+	err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+				int len, struct fdt_property **prop)
+{
+	int oldlen;
+	int err;
+
+	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (! (*prop))
+		return oldlen;
+
+	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+				      FDT_TAGALIGN(len))))
+		return err;
+
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+			     int len, struct fdt_property **prop)
+{
+	int proplen;
+	int nextoffset;
+	int namestroff;
+	int err;
+
+	if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+		return nextoffset;
+
+	namestroff = _fdt_find_add_string(fdt, name);
+	if (namestroff < 0)
+		return namestroff;
+
+	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
+	proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+	err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+	if (err)
+		return err;
+
+	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
+	(*prop)->nameoff = cpu_to_fdt32(namestroff);
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+				 FDT_TAGALIGN(newlen+1));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+	if (err == -FDT_ERR_NOTFOUND)
+		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+	if (err)
+		return err;
+
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len, proplen;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+	return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen)
+{
+	struct fdt_node_header *nh;
+	int offset, nextoffset;
+	int nodelen;
+	int err;
+	uint32_t tag;
+	uint32_t *endtag;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+	if (offset >= 0)
+		return -FDT_ERR_EXISTS;
+	else if (offset != -FDT_ERR_NOTFOUND)
+		return offset;
+
+	/* Try to place the new node after the parent's properties */
+	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+	nh = _fdt_offset_ptr_w(fdt, offset);
+	nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+	err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+	if (err)
+		return err;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+	memcpy(nh->name, name, namelen);
+	endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+	*endtag = cpu_to_fdt32(FDT_END_NODE);
+
+	return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+				  endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+			    int mem_rsv_size, int struct_size)
+{
+	int mem_rsv_off, struct_off, strings_off;
+
+	mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+	struct_off = mem_rsv_off + mem_rsv_size;
+	strings_off = struct_off + struct_size;
+
+	memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+	fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+	memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+	fdt_set_off_dt_struct(new, struct_off);
+	fdt_set_size_dt_struct(new, struct_size);
+
+	memmove(new + strings_off, old + fdt_off_dt_strings(old),
+		fdt_size_dt_strings(old));
+	fdt_set_off_dt_strings(new, strings_off);
+	fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+	int err;
+	int mem_rsv_size, struct_size;
+	int newsize;
+	const char *fdtstart = fdt;
+	const char *fdtend = fdtstart + fdt_totalsize(fdt);
+	char *tmp;
+
+	FDT_CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+
+	if (fdt_version(fdt) >= 17) {
+		struct_size = fdt_size_dt_struct(fdt);
+	} else {
+		struct_size = 0;
+		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+			;
+	}
+
+	if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+		/* no further work necessary */
+		err = fdt_move(fdt, buf, bufsize);
+		if (err)
+			return err;
+		fdt_set_version(buf, 17);
+		fdt_set_size_dt_struct(buf, struct_size);
+		fdt_set_totalsize(buf, bufsize);
+		return 0;
+	}
+
+	/* Need to reorder */
+	newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+		+ struct_size + fdt_size_dt_strings(fdt);
+
+	if (bufsize < newsize)
+		return -FDT_ERR_NOSPACE;
+
+	/* First attempt to build converted tree at beginning of buffer */
+	tmp = buf;
+	/* But if that overlaps with the old tree... */
+	if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+		/* Try right after the old tree instead */
+		tmp = (char *)(uintptr_t)fdtend;
+		if ((tmp + newsize) > ((char *)buf + bufsize))
+			return -FDT_ERR_NOSPACE;
+	}
+
+	_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+	memmove(buf, tmp, newsize);
+
+	fdt_set_magic(buf, FDT_MAGIC);
+	fdt_set_totalsize(buf, bufsize);
+	fdt_set_version(buf, 17);
+	fdt_set_last_comp_version(buf, 16);
+	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+	return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+	int mem_rsv_size;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+	_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+	fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+	return 0;
+}
diff --git a/kexec/arch/ppc/libfdt/fdt_strerror.c b/kexec/arch/ppc/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..e6c3cee
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+	const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+	[(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+	FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+	FDT_ERRTABENT(FDT_ERR_EXISTS),
+	FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+	FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+	FDT_ERRTABENT(FDT_ERR_BADPATH),
+	FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+	FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+	FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+	FDT_ERRTABENT(FDT_ERR_BADVERSION),
+	FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+	FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+	if (errval > 0)
+		return "<valid offset/length>";
+	else if (errval == 0)
+		return "<no error>";
+	else if (errval > -FDT_ERRTABSIZE) {
+		const char *s = fdt_errtable[-errval].str;
+
+		if (s)
+			return s;
+	}
+
+	return "<unknown error>";
+}
diff --git a/kexec/arch/ppc/libfdt/fdt_sw.c b/kexec/arch/ppc/libfdt/fdt_sw.c
new file mode 100644
index 0000000..698329e
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt_sw.c
@@ -0,0 +1,257 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+	if (fdt_magic(fdt) != FDT_SW_MAGIC)
+		return -FDT_ERR_BADMAGIC;
+	/* FIXME: should check more details about the header state */
+	return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = _fdt_sw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static void *_fdt_grab_space(void *fdt, int len)
+{
+	int offset = fdt_size_dt_struct(fdt);
+	int spaceleft;
+
+	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+		- fdt_size_dt_strings(fdt);
+
+	if ((offset + len < offset) || (offset + len > spaceleft))
+		return NULL;
+
+	fdt_set_size_dt_struct(fdt, offset + len);
+	return fdt_offset_ptr_w(fdt, offset, len);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+	void *fdt = buf;
+
+	if (bufsize < sizeof(struct fdt_header))
+		return -FDT_ERR_NOSPACE;
+
+	memset(buf, 0, bufsize);
+
+	fdt_set_magic(fdt, FDT_SW_MAGIC);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+	fdt_set_totalsize(fdt,  bufsize);
+
+	fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+					      sizeof(struct fdt_reserve_entry)));
+	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+	fdt_set_off_dt_strings(fdt, bufsize);
+
+	return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int offset;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	if (fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADSTATE;
+
+	offset = fdt_off_dt_struct(fdt);
+	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+		return -FDT_ERR_NOSPACE;
+
+	re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+	re->address = cpu_to_fdt64(addr);
+	re->size = cpu_to_fdt64(size);
+
+	fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+	return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+	return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+	struct fdt_node_header *nh;
+	int namelen = strlen(name) + 1;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+	if (! nh)
+		return -FDT_ERR_NOSPACE;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memcpy(nh->name, name, namelen);
+	return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+	uint32_t *en;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+	if (! en)
+		return -FDT_ERR_NOSPACE;
+
+	*en = cpu_to_fdt32(FDT_END_NODE);
+	return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_totalsize(fdt);
+	const char *p;
+	int strtabsize = fdt_size_dt_strings(fdt);
+	int len = strlen(s) + 1;
+	int struct_top, offset;
+
+	p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+	if (p)
+		return p - strtab;
+
+	/* Add it */
+	offset = -strtabsize - len;
+	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	if (fdt_totalsize(fdt) + offset < struct_top)
+		return 0; /* no more room :( */
+
+	memcpy(strtab + offset, s, len);
+	fdt_set_size_dt_strings(fdt, strtabsize + len);
+	return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+	struct fdt_property *prop;
+	int nameoff;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	nameoff = _fdt_find_add_string(fdt, name);
+	if (nameoff == 0)
+		return -FDT_ERR_NOSPACE;
+
+	prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+	if (! prop)
+		return -FDT_ERR_NOSPACE;
+
+	prop->tag = cpu_to_fdt32(FDT_PROP);
+	prop->nameoff = cpu_to_fdt32(nameoff);
+	prop->len = cpu_to_fdt32(len);
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+	char *p = (char *)fdt;
+	uint32_t *end;
+	int oldstroffset, newstroffset;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	/* Add terminator */
+	end = _fdt_grab_space(fdt, sizeof(*end));
+	if (! end)
+		return -FDT_ERR_NOSPACE;
+	*end = cpu_to_fdt32(FDT_END);
+
+	/* Relocate the string table */
+	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(fdt, newstroffset);
+
+	/* Walk the structure, correcting string offsets */
+	offset = 0;
+	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+		if (tag == FDT_PROP) {
+			struct fdt_property *prop =
+				fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
+			int nameoff;
+
+			if (! prop)
+				return -FDT_ERR_BADSTRUCTURE;
+
+			nameoff = fdt32_to_cpu(prop->nameoff);
+			nameoff += fdt_size_dt_strings(fdt);
+			prop->nameoff = cpu_to_fdt32(nameoff);
+		}
+		offset = nextoffset;
+	}
+
+	/* Finally, adjust the header */
+	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	return 0;
+}
diff --git a/kexec/arch/ppc/libfdt/fdt_wip.c b/kexec/arch/ppc/libfdt/fdt_wip.c
new file mode 100644
index 0000000..a4652c6
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/fdt_wip.c
@@ -0,0 +1,145 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len)
+{
+	void *propval;
+	int proplen;
+
+	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+	if (! propval)
+		return proplen;
+
+	if (proplen != len)
+		return -FDT_ERR_NOSPACE;
+
+	memcpy(propval, val, len);
+	return 0;
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+	uint32_t *p;
+
+	for (p = start; (char *)p < ((char *)start + len); p++)
+		*p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len;
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	_fdt_nop_region(prop, len + sizeof(*prop));
+
+	return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int nodeoffset)
+{
+	int level = 0;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+	if (tag != FDT_BEGIN_NODE)
+		return -FDT_ERR_BADOFFSET;
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_END:
+			return offset;
+
+		case FDT_BEGIN_NODE:
+			level++;
+			break;
+
+		case FDT_END_NODE:
+			level--;
+			break;
+
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		default:
+			return -FDT_ERR_BADSTRUCTURE;
+		}
+	} while (level >= 0);
+
+	return nextoffset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+			endoffset - nodeoffset);
+	return 0;
+}
diff --git a/kexec/arch/ppc/libfdt/libfdt.h b/kexec/arch/ppc/libfdt/libfdt.h
new file mode 100644
index 0000000..ce80e4f
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/libfdt.h
@@ -0,0 +1,1076 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attemped to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+	 * value.  phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+#define FDT_ERR_MAX		13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+	return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+					    const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+						      const char *name,
+						      int *lenp)
+{
+	return (struct fdt_property *)(uintptr_t)
+		fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+				  const char *name, int *lenp)
+{
+	return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	structure block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary.  This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+  *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+					   const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_property(fdt, name, &val, sizeof(val));
+}
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+				   uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/kexec/arch/ppc/libfdt/libfdt_env.h b/kexec/arch/ppc/libfdt/libfdt_env.h
new file mode 100644
index 0000000..449bf60
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/libfdt_env.h
@@ -0,0 +1,23 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#define _B(n)	((unsigned long long)((uint8_t *)&x)[n])
+static inline uint32_t fdt32_to_cpu(uint32_t x)
+{
+	return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
+}
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+	return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
+		| (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/kexec/arch/ppc/libfdt/libfdt_internal.h b/kexec/arch/ppc/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..46eb93e
--- /dev/null
+++ b/kexec/arch/ppc/libfdt/libfdt_internal.h
@@ -0,0 +1,95 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <fdt.h>
+
+#define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+int _fdt_check_node_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+	return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+	return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+	const struct fdt_reserve_entry *rsv_table =
+		(const struct fdt_reserve_entry *)
+		((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+	return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+	return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC		(~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/kexec/arch/ppc/ops.h b/kexec/arch/ppc/ops.h
new file mode 100644
index 0000000..f33e941
--- /dev/null
+++ b/kexec/arch/ppc/ops.h
@@ -0,0 +1,151 @@
+/*
+ * Global definition of all the bootwrapper operations.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef _PPC_BOOT_OPS_H_
+#define _PPC_BOOT_OPS_H_
+#include "types.h"
+
+#define	COMMAND_LINE_SIZE	512
+#define	MAX_PATH_LEN		256
+#define	MAX_PROP_LEN		256 /* What should this be? */
+
+typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5);
+
+/* Device Tree operations */
+struct dt_ops {
+	void *	(*finddevice)(const char *name);
+	int	(*getprop)(const void *phandle, const char *name, void *buf,
+			const int buflen);
+	int	(*setprop)(const void *phandle, const char *name,
+			const void *buf, const int buflen);
+	void *(*get_parent)(const void *phandle);
+	/* The node must not already exist. */
+	void *(*create_node)(const void *parent, const char *name);
+	void *(*find_node_by_prop_value)(const void *prev,
+					 const char *propname,
+					 const char *propval, int proplen);
+	void *(*find_node_by_compatible)(const void *prev,
+					 const char *compat);
+	unsigned long (*finalize)(void);
+	char *(*get_path)(const void *phandle, char *buf, int len);
+};
+extern struct dt_ops dt_ops;
+
+void fdt_init(void *blob);
+extern void flush_cache(void *, unsigned long);
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
+int dt_is_compatible(void *node, const char *compat);
+void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize);
+int dt_get_virtual_reg(void *node, void **addr, int nres);
+
+static inline void *finddevice(const char *name)
+{
+	return (dt_ops.finddevice) ? dt_ops.finddevice(name) : NULL;
+}
+
+static inline int getprop(void *devp, const char *name, void *buf, int buflen)
+{
+	return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1;
+}
+
+static inline int setprop(void *devp, const char *name,
+			  const void *buf, int buflen)
+{
+	return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1;
+}
+#define setprop_val(devp, name, val) \
+	do { \
+		typeof(val) x = (val); \
+		setprop((devp), (name), &x, sizeof(x)); \
+	} while (0)
+
+static inline int setprop_str(void *devp, const char *name, const char *buf)
+{
+	if (dt_ops.setprop)
+		return dt_ops.setprop(devp, name, buf, strlen(buf) + 1);
+
+	return -1;
+}
+
+static inline void *get_parent(const char *devp)
+{
+	return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL;
+}
+
+static inline void *create_node(const void *parent, const char *name)
+{
+	return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL;
+}
+
+
+static inline void *find_node_by_prop_value(const void *prev,
+					    const char *propname,
+					    const char *propval, int proplen)
+{
+	if (dt_ops.find_node_by_prop_value)
+		return dt_ops.find_node_by_prop_value(prev, propname,
+						      propval, proplen);
+
+	return NULL;
+}
+
+static inline void *find_node_by_prop_value_str(const void *prev,
+						const char *propname,
+						const char *propval)
+{
+	return find_node_by_prop_value(prev, propname, propval,
+				       strlen(propval) + 1);
+}
+
+static inline void *find_node_by_devtype(const void *prev,
+					 const char *type)
+{
+	return find_node_by_prop_value_str(prev, "device_type", type);
+}
+
+static inline void *find_node_by_alias(const char *alias)
+{
+	void *devp = finddevice("/aliases");
+
+	if (devp) {
+		char path[MAX_PATH_LEN];
+		if (getprop(devp, alias, path, MAX_PATH_LEN) > 0)
+			return finddevice(path);
+	}
+
+	return NULL;
+}
+
+static inline void *find_node_by_compatible(const void *prev,
+					    const char *compat)
+{
+	if (dt_ops.find_node_by_compatible)
+		return dt_ops.find_node_by_compatible(prev, compat);
+
+	return NULL;
+}
+
+#define dt_fixup_mac_addresses(...) \
+	__dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+
+
+static inline char *get_path(const void *phandle, char *buf, int len)
+{
+	if (dt_ops.get_path)
+		return dt_ops.get_path(phandle, buf, len);
+
+	return NULL;
+}
+
+#define fatal(args...) { printf(args); exit(1); }
+
+char *fixup_dtb_nodes(char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline);
+#endif /* _PPC_BOOT_OPS_H_ */
-- 
1.6.5.2


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

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

* [PATCH 4/7] powerpc32: add support to fixup the dtb
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
                   ` (2 preceding siblings ...)
  2010-03-31  8:24 ` [PATCH 3/7] powerpc32: pull in libfdt Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 5/7] powerpc32: add support for uImage Sebastian Andrzej Siewior
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: Sebastian Andrzej Siewior, kexec

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

A few device nodes are dynamically determined by the bootloader (MAC address,
memory size, ..) and are not part of the device tree. The kernel command line
is also read from dtb and usually not part of the device tree.
With the libfdt it is now easy to add/replace nodes in the device tree.
The user may specify "--reuse-node=/memory/reg" to update the memory/reg
node to what ever is now. This requires the kernel to export the device
tree via the procfs in /proc/device-tree.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kexec/arch/ppc/Makefile        |    1 +
 kexec/arch/ppc/fixup_dtb.c     |  105 ++++++++++++++++++++++++++++++++++++++++
 kexec/arch/ppc/fixup_dtb.h     |    6 ++
 kexec/arch/ppc/kexec-elf-ppc.c |   29 ++++++++++--
 4 files changed, 137 insertions(+), 4 deletions(-)
 create mode 100644 kexec/arch/ppc/fixup_dtb.c
 create mode 100644 kexec/arch/ppc/fixup_dtb.h

diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index 0ef7ca4..5e01237 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -9,6 +9,7 @@ ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-rel-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-dol-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
+ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c
 
 libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c
 libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/arch/ppc/libfdt/%)
diff --git a/kexec/arch/ppc/fixup_dtb.c b/kexec/arch/ppc/fixup_dtb.c
new file mode 100644
index 0000000..40e9350
--- /dev/null
+++ b/kexec/arch/ppc/fixup_dtb.c
@@ -0,0 +1,105 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "../../kexec.h"
+#include <libfdt.h>
+#include "ops.h"
+#include "page.h"
+#include "fixup_dtb.h"
+
+const char proc_dts[] = "/proc/device-tree";
+
+static void fixup_nodes(char *nodes[])
+{
+	int index = 0;
+	char *fname;
+	char *prop_name;
+	char *node_name;
+	void *node;
+	int len;
+	char *content;
+	off_t content_size;
+	int ret;
+
+	while (nodes[index]) {
+
+		len = asprintf(&fname, "%s%s", proc_dts, nodes[index]);
+		if (len < 0)
+			fatal("asprintf() failed\n");
+
+		content = slurp_file(fname, &content_size);
+		if (!content) {
+			fprintf(stderr, "Can't open %s: %s\n",
+					fname, strerror(errno));
+			exit(1);
+		}
+
+		prop_name = fname + len;
+		while (*prop_name != '/')
+			prop_name--;
+
+		*prop_name = '\0';
+		prop_name++;
+
+		node_name = fname + sizeof(proc_dts) - 1;
+
+		node = finddevice(node_name);
+		if (!node)
+			node = create_node(NULL, node_name + 1);
+
+		ret = setprop(node, prop_name, content, content_size);
+		if (ret < 0)
+			fatal("setprop of %s/%s size: %ld failed: %s\n",
+					node_name, prop_name, content_size,
+					fdt_strerror(ret));
+
+		free(content);
+		free(fname);
+		index++;
+	};
+}
+
+/*
+ * command line priority:
+ * - use the supplied command line
+ * - if none available use the command line from .dtb
+ * - if not available use the current command line
+ */
+static void fixup_cmdline(const char *cmdline)
+{
+	void *chosen;
+	char *fixup_cmd_node[] = {
+		"/chosen/bootargs",
+		NULL,
+	};
+
+	chosen = finddevice("/chosen");
+
+	if (!cmdline) {
+		if (!chosen)
+			fixup_nodes(fixup_cmd_node);
+	} else {
+		if (!chosen)
+			chosen = create_node(NULL, "chosen");
+		setprop_str(chosen, "bootargs", cmdline);
+	}
+	return;
+}
+
+char *fixup_dtb_nodes(char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline)
+{
+	fdt_init(blob_buf);
+
+	fixup_nodes(nodes);
+	fixup_cmdline(cmdline);
+
+	blob_buf = (char *)dt_ops.finalize();
+	*blob_size = fdt_totalsize(blob_buf);
+	return blob_buf;
+}
diff --git a/kexec/arch/ppc/fixup_dtb.h b/kexec/arch/ppc/fixup_dtb.h
new file mode 100644
index 0000000..0ff981e
--- /dev/null
+++ b/kexec/arch/ppc/fixup_dtb.h
@@ -0,0 +1,6 @@
+#ifndef __FIXUP_DTB_H
+#define __FIXUP_DTB_H
+
+char *fixup_dtb_nodes(char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline);
+
+#endif
diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c
index 03b8a94..a54a5d5 100644
--- a/kexec/arch/ppc/kexec-elf-ppc.c
+++ b/kexec/arch/ppc/kexec-elf-ppc.c
@@ -25,6 +25,7 @@
 #include <arch/options.h>
 
 #include "config.h"
+#include "fixup_dtb.h"
 
 static const int probe_debug = 0;
 
@@ -115,12 +116,14 @@ static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 #define OPT_APPEND	(OPT_ARCH_MAX+0)
 #define OPT_GAMECUBE	(OPT_ARCH_MAX+1)
 #define OPT_DTB		(OPT_ARCH_MAX+2)
+#define OPT_NODES	(OPT_ARCH_MAX+3)
 static const struct option options[] = {
 	KEXEC_ARCH_OPTIONS
 	{"command-line", 1, 0, OPT_APPEND},
 	{"append",       1, 0, OPT_APPEND},
 	{"gamecube",     1, 0, OPT_GAMECUBE},
 	{"dtb",     1, 0, OPT_DTB},
+	{"reuse-node",     1, 0, OPT_NODES},
 	{0, 0, 0, 0},
 };
 static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
@@ -132,7 +135,9 @@ void elf_ppc_usage(void)
 	     "    --append=STRING       Set the kernel command line to STRING.\n"
 	     "    --gamecube=1|0        Enable/disable support for ELFs with changed\n"
 	     "                          addresses suitable for the GameCube.\n"
-	     "     --dtb=<filename> Specify device tree blob file.\n"
+	     "     --dtb=<filename>     Specify device tree blob file.\n"
+	     "     --reuse-node=node    Specify nodes which should be taken from /proc/device-tree.\n"
+	     "                          Can be set multiple times.\n"
 	     );
 }
 
@@ -157,6 +162,9 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 	int target_is_gamecube = 0;
 	unsigned int addr;
 	unsigned long dtb_addr;
+#define FIXUP_ENTRYS	(20)
+	char *fixup_nodes[FIXUP_ENTRYS + 1];
+	int cur_fixup = 0;
 #endif
 	int opt;
 
@@ -182,13 +190,25 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		case OPT_DTB:
 			dtb = optarg;
 			break;
+
+		case OPT_NODES:
+			if (cur_fixup >= FIXUP_ENTRYS) {
+				fprintf(stderr, "The number of entries for the fixup is too large\n");
+				exit(1);
+			}
+			fixup_nodes[cur_fixup] = optarg;
+			cur_fixup++;
+			break;
 		}
 	}
+
 	command_line_len = 0;
 	if (command_line) {
 		command_line_len = strlen(command_line) + 1;
 	}
 
+	fixup_nodes[cur_fixup] = NULL;
+
 	/* Parse the Elf file */
 	result = build_elf_exec_info(buf, len, &ehdr, 0);
 	if (result < 0) {
@@ -247,12 +267,13 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 
 		/* Grab device tree from buffer */
 		blob_buf = slurp_file(dtb, &blob_size);
+		if (!blob_buf || !blob_size)
+			die("Device tree seems to be an empty file.\n");
+		blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, command_line);
 		dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
 				KERNEL_ACCESS_TOP, -1);
-		if (command_line)
-			die("Don't consider command line because dtb is supplied\n");
 	} else {
-		die("Missing dtb.\n");
+		dtb_addr = 0;
 	}
 
 	/* set various variables for the purgatory */
-- 
1.6.5.2


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

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

* [PATCH 5/7] powerpc32: add support for uImage
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
                   ` (3 preceding siblings ...)
  2010-03-31  8:24 ` [PATCH 4/7] powerpc32: add support to fixup the dtb Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 6/7] Split Powerpc's uImage code Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 7/7] Let SH adn ARM use common uImage probe code Sebastian Andrzej Siewior
  6 siblings, 0 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: Sebastian Andrzej Siewior, kexec

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

On PowerPC the uImage usually contains the compressed "final" kernel and
not a tiny wrapper which relocates itself und uncomprosses the final
kernel to its final position. Instead we uncompress the gzip image and
put it the its final position.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kexec/arch/ppc/Makefile           |    1 +
 kexec/arch/ppc/kexec-ppc.c        |    3 +-
 kexec/arch/ppc/kexec-ppc.h        |    5 +
 kexec/arch/ppc/kexec-uImage-ppc.c |  348 +++++++++++++++++++++++++++++++++++++
 4 files changed, 356 insertions(+), 1 deletions(-)
 create mode 100644 kexec/arch/ppc/kexec-uImage-ppc.c

diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index 5e01237..698fd03 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -7,6 +7,7 @@ ppc_KEXEC_SRCS =  kexec/arch/ppc/kexec-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-rel-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-dol-ppc.c
+ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-uImage-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c
diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
index ac0daad..f552d79 100644
--- a/kexec/arch/ppc/kexec-ppc.c
+++ b/kexec/arch/ppc/kexec-ppc.c
@@ -250,7 +250,7 @@ static int get_base_ranges(void)
 /* Get devtree details and create exclude_range array
  * Also create usablemem_ranges for KEXEC_ON_CRASH
  */
-static int get_devtree_details(unsigned long kexec_flags)
+static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 {
 	uint64_t rmo_base;
 	char buf[MAXBYTES];
@@ -485,6 +485,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 struct file_type file_type[] = {
 	{"elf-ppc", elf_ppc_probe, elf_ppc_load, elf_ppc_usage},
 	{"dol-ppc", dol_ppc_probe, dol_ppc_load, dol_ppc_usage},
+	{"uImage-ppc", uImage_ppc_probe, uImage_ppc_load, uImage_ppc_usage },
 };
 int file_types = sizeof(file_type) / sizeof(file_type[0]);
 
diff --git a/kexec/arch/ppc/kexec-ppc.h b/kexec/arch/ppc/kexec-ppc.h
index 1b2b015..6cec467 100644
--- a/kexec/arch/ppc/kexec-ppc.h
+++ b/kexec/arch/ppc/kexec-ppc.h
@@ -21,6 +21,11 @@ int elf_ppc_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
 void elf_ppc_usage(void);
 
+int uImage_ppc_probe(const char *buf, off_t len);
+int uImage_ppc_load(int argc, char **argv, const char *buf, off_t len,
+	struct kexec_info *info);
+void uImage_ppc_usage(void);
+
 int dol_ppc_probe(const char *buf, off_t len);
 int dol_ppc_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
diff --git a/kexec/arch/ppc/kexec-uImage-ppc.c b/kexec/arch/ppc/kexec-uImage-ppc.c
new file mode 100644
index 0000000..47e6c10
--- /dev/null
+++ b/kexec/arch/ppc/kexec-uImage-ppc.c
@@ -0,0 +1,348 @@
+/*
+ * uImage support for PowerPC
+ */
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+#include <image.h>
+#include <getopt.h>
+#include <arch/options.h>
+#include "../../kexec.h"
+#include "kexec-ppc.h"
+#include "fixup_dtb.h"
+
+#define OPT_APPEND      (OPT_ARCH_MAX+0)
+#define OPT_DTB         (OPT_ARCH_MAX+1)
+#define OPT_NODES       (OPT_ARCH_MAX+2)
+static const struct option options[] = {
+	KEXEC_ARCH_OPTIONS
+	{"command-line",	1, 0, OPT_APPEND},
+	{"append",	1, 0, OPT_APPEND},
+	{"dtb",		1, 0, OPT_DTB},
+	{"reuse-node",	1, 0, OPT_NODES},
+	{0, 0, 0, 0},
+};
+static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
+
+void uImage_ppc_usage(void)
+{
+	printf(
+			"    --command-line=STRING Set the kernel command line to STRING.\n"
+			"    --append=STRING       Set the kernel command line to STRING.\n"
+			"     --dtb=<filename>     Specify device tree blob file.\n"
+			"     --reuse-node=node    Specify nodes which should be taken from /proc/device-tree.\n"
+			"                          Can be set multiple times.\n"
+	);
+}
+
+int uImage_ppc_probe(const char *buf, off_t len)
+{
+	struct image_header header;
+#ifdef HAVE_LIBZ
+	unsigned int crc;
+	unsigned int hcrc;
+#endif
+
+	if (len < sizeof(header))
+		return -1;
+
+	memcpy(&header, buf, sizeof(header));
+
+	if (cpu_to_be32(header.ih_magic) != IH_MAGIC)
+		return -1;
+#ifdef HAVE_LIBZ
+	hcrc = be32_to_cpu(header.ih_hcrc);
+	header.ih_hcrc = 0;
+	crc = crc32(0, (void *)&header, sizeof(header));
+	if (crc != hcrc) {
+		printf("Header checksum of the uImage does not match\n");
+		return -1;
+	}
+#endif
+
+	if (header.ih_type != IH_TYPE_KERNEL) {
+		printf("uImage type %d unsupported\n", header.ih_type);
+		return -1;
+	}
+
+	if (header.ih_os != IH_OS_LINUX) {
+		printf("uImage os %d unsupported\n", header.ih_os);
+		return -1;
+	}
+
+	if (header.ih_arch != IH_ARCH_PPC) {
+		printf("uImage arch %d unsupported\n", header.ih_arch);
+		return -1;
+	}
+
+	switch (header.ih_comp) {
+	case IH_COMP_NONE:
+#ifdef HAVE_LIBZ
+	case IH_COMP_GZIP:
+#endif
+		break;
+
+	default:
+		printf("uImage uses unsupported compression method\n");
+		return -1;
+	}
+#ifdef HAVE_LIBZ
+	crc = crc32(0, (void *)buf + sizeof(header), len - sizeof(header));
+	if (crc != be32_to_cpu(header.ih_dcrc)) {
+		printf("The data CRC does not match. Computed: %08x expected %08x\n",
+			crc, be32_to_cpu(header.ih_dcrc));
+		return -1;
+	}
+#endif
+	return 0;
+}
+
+static int ppc_load_bare_bits(int argc, char **argv, const char *buf,
+		off_t len, struct kexec_info *info, unsigned int load_addr,
+		unsigned int ep)
+{
+	char *command_line;
+	int command_line_len;
+	char *dtb;
+	unsigned int addr;
+	unsigned long dtb_addr;
+#define FIXUP_ENTRYS    (20)
+	char *fixup_nodes[FIXUP_ENTRYS + 1];
+	int cur_fixup = 0;
+	int opt;
+	int ret;
+
+	command_line = NULL;
+	dtb = NULL;
+
+	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+		switch (opt) {
+		default:
+			/* Ignore core options */
+			if (opt < OPT_ARCH_MAX) {
+				break;
+			}
+		case '?':
+			usage();
+			return -1;
+		case OPT_APPEND:
+			command_line = optarg;
+			break;
+
+		case OPT_DTB:
+			dtb = optarg;
+			break;
+
+		case OPT_NODES:
+			if (cur_fixup >= FIXUP_ENTRYS) {
+				fprintf(stderr, "The number of entries for the fixup is too large\n");
+				exit(1);
+			}
+			fixup_nodes[cur_fixup] = optarg;
+			cur_fixup++;
+			break;
+		}
+	}
+
+	command_line_len = 0;
+	if (command_line)
+		command_line_len = strlen(command_line) + 1;
+
+	fixup_nodes[cur_fixup] = NULL;
+
+	/*
+	 * len contains the length of the whole kernel image except the bss
+	 * section. The 3 MiB should cover it. The purgatory and the dtb are
+	 * allocated from memtop down towards zero so we should never get too
+	 * close to the bss :)
+	 */
+	ret = valid_memory_range(info, load_addr, len + 3 * 1024 * 1024);
+	if (!ret) {
+		printf("Can't add kernel to addr 0x%08x len %ld\n",
+				load_addr, len + 3 * 1024 * 1024);
+		return -1;
+	}
+	add_segment(info, buf, len, load_addr, len + 3 * 1024 * 1024);
+	if (dtb) {
+		char *blob_buf;
+		off_t blob_size = 0;
+
+		/* Grab device tree from buffer */
+		blob_buf = slurp_file(dtb, &blob_size);
+		if (!blob_buf || !blob_size)
+			die("Device tree seems to be an empty file.\n");
+		blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, command_line);
+
+		dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
+				KERNEL_ACCESS_TOP, -1);
+	} else {
+		dtb_addr = 0;
+	}
+
+	elf_rel_build_load(info, &info->rhdr, (const char *)purgatory,
+			purgatory_size, 0, -1, -1, 0);
+
+	/* set various variables for the purgatory */
+	addr = ep;
+	elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
+
+	addr = dtb_addr;
+	elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr));
+
+	addr = rmo_top;
+	elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr));
+
+#define PUL_STACK_SIZE  (16 * 1024)
+	addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, -1, 1);
+	addr += PUL_STACK_SIZE;
+	elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr));
+	/* No allocation past here in order not to overwrite the stack */
+#undef PUL_STACK_SIZE
+
+	addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
+	info->entry = (void *)addr;
+	return 0;
+}
+
+#ifdef HAVE_LIBZ
+/* gzip flag byte */
+#define ASCII_FLAG	0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC	0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD	0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME	0x08 /* bit 3 set: original file name present */
+#define COMMENT		0x10 /* bit 4 set: file comment present */
+#define RESERVED	0xE0 /* bits 5..7: reserved */
+
+static int uImage_gz_load(int argc, char **argv, const char *buf, off_t len,
+		struct kexec_info *info, unsigned int load_addr,
+		unsigned int ep)
+{
+	int ret;
+	z_stream strm;
+	unsigned int skip;
+	unsigned int flags;
+	unsigned char *uncomp_buf;
+	unsigned int mem_alloc;
+
+	mem_alloc = 10 * 1024 * 1024;
+	uncomp_buf = malloc(mem_alloc);
+	if (!uncomp_buf)
+		return -1;
+
+	memset(&strm, 0, sizeof(strm));
+
+	/* Skip magic, method, time, flags, os code ... */
+	skip = 10;
+
+	/* check GZ magic */
+	if (buf[0] != 0x1f || buf[1] != 0x8b)
+		return -1;
+
+	flags = buf[3];
+	if (buf[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
+		puts ("Error: Bad gzipped data\n");
+		return -1;
+	}
+
+	if (flags & EXTRA_FIELD) {
+		skip += 2;
+		skip += buf[10];
+		skip += buf[11] << 8;
+	}
+	if (flags & ORIG_NAME) {
+		while (buf[skip++])
+			;
+	}
+	if (flags & COMMENT) {
+		while (buf[skip++])
+			;
+	}
+	if (flags & HEAD_CRC)
+		skip += 2;
+
+	strm.avail_in = len - skip;
+	strm.next_in = (void *)buf + skip;
+
+	/* - activates parsing gz headers */
+	ret = inflateInit2(&strm, -MAX_WBITS);
+	if (ret != Z_OK)
+		return -1;
+
+	strm.next_out = uncomp_buf;
+	strm.avail_out = mem_alloc;
+
+	do {
+		ret = inflate(&strm, Z_FINISH);
+		if (ret == Z_STREAM_END)
+			break;
+
+		if (ret == Z_OK || ret == Z_BUF_ERROR) {
+			void *new_buf;
+			int inc_buf = 5 * 1024 * 1024;
+
+			mem_alloc += inc_buf;
+			new_buf = realloc(uncomp_buf, mem_alloc);
+			if (!new_buf) {
+				inflateEnd(&strm);
+				free(uncomp_buf);
+				return -1;
+			}
+
+			strm.next_out = uncomp_buf + mem_alloc - inc_buf;
+			strm.avail_out = inc_buf;
+			uncomp_buf = new_buf;
+		} else {
+			printf("Error during decompression %d\n", ret);
+			return -1;
+		}
+	} while (1);
+
+	inflateEnd(&strm);
+
+	ret = ppc_load_bare_bits(argc, argv, (char *)uncomp_buf,
+			mem_alloc - strm.avail_out, info,
+			load_addr, ep);
+
+	/* leak uncomp_buf since the buffer has to remain past this function */
+	return ret;
+}
+
+#else
+
+static int uImage_gz_load(int argc, char **argv, const char *buf, off_t len,
+		struct kexec_info *info, unsigned int load_addr,
+		unsigned int ep)
+{
+	return -1;
+}
+#endif
+
+int uImage_ppc_load(int argc, char **argv, const char *buf, off_t len,
+		struct kexec_info *info)
+{
+	const struct image_header *header = (const struct image_header *)buf;
+	const char *img_buf = buf + sizeof(struct image_header);
+	off_t img_len = len - sizeof(struct image_header);
+	unsigned int img_base = cpu_to_be32(header->ih_load);
+	unsigned int img_entry = cpu_to_be32(header->ih_ep);
+
+	switch (header->ih_comp) {
+	case IH_COMP_NONE:
+		return ppc_load_bare_bits(argc, argv, img_buf, img_len, info,
+				img_base, img_entry);
+		break;
+
+	case IH_COMP_GZIP:
+		return uImage_gz_load(argc, argv, img_buf, img_len, info,
+				img_base, img_entry);
+		break;
+
+	default:
+		return -1;
+	}
+}
-- 
1.6.5.2


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

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

* [PATCH 6/7] Split Powerpc's uImage code
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
                   ` (4 preceding siblings ...)
  2010-03-31  8:24 ` [PATCH 5/7] powerpc32: add support for uImage Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  2010-03-31  8:24 ` [PATCH 7/7] Let SH adn ARM use common uImage probe code Sebastian Andrzej Siewior
  6 siblings, 0 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman; +Cc: Sebastian Andrzej Siewior, kexec

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The check and uncompress code could be split and recycled by other arch.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/kexec-uImage.h            |   13 +++
 kexec/arch/ppc/Makefile           |    1 +
 kexec/arch/ppc/kexec-uImage-ppc.c |  201 ++---------------------------------
 kexec/kexec-uImage.c              |  213 +++++++++++++++++++++++++++++++++++++
 4 files changed, 236 insertions(+), 192 deletions(-)
 create mode 100644 include/kexec-uImage.h
 create mode 100644 kexec/kexec-uImage.c

diff --git a/include/kexec-uImage.h b/include/kexec-uImage.h
new file mode 100644
index 0000000..e8a4b69
--- /dev/null
+++ b/include/kexec-uImage.h
@@ -0,0 +1,13 @@
+#ifndef __KEXEC_UIMAGE_H__
+#define __KEXEC_UIMAGE_H__
+
+struct Image_info {
+	const char *buf;
+	off_t len;
+	unsigned int base;
+	unsigned int ep;
+};
+
+int uImage_probe(const char *buf, off_t len, unsigned int arch);
+int uImage_load(const char *buf, off_t len, struct Image_info *info);
+#endif
diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index 698fd03..1c7441c 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -11,6 +11,7 @@ ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-uImage-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c
+ppc_KEXEC_SRCS += kexec/kexec-uImage.c
 
 libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c
 libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/arch/ppc/libfdt/%)
diff --git a/kexec/arch/ppc/kexec-uImage-ppc.c b/kexec/arch/ppc/kexec-uImage-ppc.c
index 47e6c10..0a655a3 100644
--- a/kexec/arch/ppc/kexec-uImage-ppc.c
+++ b/kexec/arch/ppc/kexec-uImage-ppc.c
@@ -6,15 +6,13 @@
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
-#ifdef HAVE_LIBZ
-#include <zlib.h>
-#endif
 #include <image.h>
 #include <getopt.h>
 #include <arch/options.h>
 #include "../../kexec.h"
 #include "kexec-ppc.h"
 #include "fixup_dtb.h"
+#include <kexec-uImage.h>
 
 #define OPT_APPEND      (OPT_ARCH_MAX+0)
 #define OPT_DTB         (OPT_ARCH_MAX+1)
@@ -42,64 +40,7 @@ void uImage_ppc_usage(void)
 
 int uImage_ppc_probe(const char *buf, off_t len)
 {
-	struct image_header header;
-#ifdef HAVE_LIBZ
-	unsigned int crc;
-	unsigned int hcrc;
-#endif
-
-	if (len < sizeof(header))
-		return -1;
-
-	memcpy(&header, buf, sizeof(header));
-
-	if (cpu_to_be32(header.ih_magic) != IH_MAGIC)
-		return -1;
-#ifdef HAVE_LIBZ
-	hcrc = be32_to_cpu(header.ih_hcrc);
-	header.ih_hcrc = 0;
-	crc = crc32(0, (void *)&header, sizeof(header));
-	if (crc != hcrc) {
-		printf("Header checksum of the uImage does not match\n");
-		return -1;
-	}
-#endif
-
-	if (header.ih_type != IH_TYPE_KERNEL) {
-		printf("uImage type %d unsupported\n", header.ih_type);
-		return -1;
-	}
-
-	if (header.ih_os != IH_OS_LINUX) {
-		printf("uImage os %d unsupported\n", header.ih_os);
-		return -1;
-	}
-
-	if (header.ih_arch != IH_ARCH_PPC) {
-		printf("uImage arch %d unsupported\n", header.ih_arch);
-		return -1;
-	}
-
-	switch (header.ih_comp) {
-	case IH_COMP_NONE:
-#ifdef HAVE_LIBZ
-	case IH_COMP_GZIP:
-#endif
-		break;
-
-	default:
-		printf("uImage uses unsupported compression method\n");
-		return -1;
-	}
-#ifdef HAVE_LIBZ
-	crc = crc32(0, (void *)buf + sizeof(header), len - sizeof(header));
-	if (crc != be32_to_cpu(header.ih_dcrc)) {
-		printf("The data CRC does not match. Computed: %08x expected %08x\n",
-			crc, be32_to_cpu(header.ih_dcrc));
-		return -1;
-	}
-#endif
-	return 0;
+	return uImage_probe(buf, len, IH_ARCH_PPC);
 }
 
 static int ppc_load_bare_bits(int argc, char **argv, const char *buf,
@@ -209,140 +150,16 @@ static int ppc_load_bare_bits(int argc, char **argv, const char *buf,
 	return 0;
 }
 
-#ifdef HAVE_LIBZ
-/* gzip flag byte */
-#define ASCII_FLAG	0x01 /* bit 0 set: file probably ascii text */
-#define HEAD_CRC	0x02 /* bit 1 set: header CRC present */
-#define EXTRA_FIELD	0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME	0x08 /* bit 3 set: original file name present */
-#define COMMENT		0x10 /* bit 4 set: file comment present */
-#define RESERVED	0xE0 /* bits 5..7: reserved */
-
-static int uImage_gz_load(int argc, char **argv, const char *buf, off_t len,
-		struct kexec_info *info, unsigned int load_addr,
-		unsigned int ep)
-{
-	int ret;
-	z_stream strm;
-	unsigned int skip;
-	unsigned int flags;
-	unsigned char *uncomp_buf;
-	unsigned int mem_alloc;
-
-	mem_alloc = 10 * 1024 * 1024;
-	uncomp_buf = malloc(mem_alloc);
-	if (!uncomp_buf)
-		return -1;
-
-	memset(&strm, 0, sizeof(strm));
-
-	/* Skip magic, method, time, flags, os code ... */
-	skip = 10;
-
-	/* check GZ magic */
-	if (buf[0] != 0x1f || buf[1] != 0x8b)
-		return -1;
-
-	flags = buf[3];
-	if (buf[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
-		puts ("Error: Bad gzipped data\n");
-		return -1;
-	}
-
-	if (flags & EXTRA_FIELD) {
-		skip += 2;
-		skip += buf[10];
-		skip += buf[11] << 8;
-	}
-	if (flags & ORIG_NAME) {
-		while (buf[skip++])
-			;
-	}
-	if (flags & COMMENT) {
-		while (buf[skip++])
-			;
-	}
-	if (flags & HEAD_CRC)
-		skip += 2;
-
-	strm.avail_in = len - skip;
-	strm.next_in = (void *)buf + skip;
-
-	/* - activates parsing gz headers */
-	ret = inflateInit2(&strm, -MAX_WBITS);
-	if (ret != Z_OK)
-		return -1;
-
-	strm.next_out = uncomp_buf;
-	strm.avail_out = mem_alloc;
-
-	do {
-		ret = inflate(&strm, Z_FINISH);
-		if (ret == Z_STREAM_END)
-			break;
-
-		if (ret == Z_OK || ret == Z_BUF_ERROR) {
-			void *new_buf;
-			int inc_buf = 5 * 1024 * 1024;
-
-			mem_alloc += inc_buf;
-			new_buf = realloc(uncomp_buf, mem_alloc);
-			if (!new_buf) {
-				inflateEnd(&strm);
-				free(uncomp_buf);
-				return -1;
-			}
-
-			strm.next_out = uncomp_buf + mem_alloc - inc_buf;
-			strm.avail_out = inc_buf;
-			uncomp_buf = new_buf;
-		} else {
-			printf("Error during decompression %d\n", ret);
-			return -1;
-		}
-	} while (1);
-
-	inflateEnd(&strm);
-
-	ret = ppc_load_bare_bits(argc, argv, (char *)uncomp_buf,
-			mem_alloc - strm.avail_out, info,
-			load_addr, ep);
-
-	/* leak uncomp_buf since the buffer has to remain past this function */
-	return ret;
-}
-
-#else
-
-static int uImage_gz_load(int argc, char **argv, const char *buf, off_t len,
-		struct kexec_info *info, unsigned int load_addr,
-		unsigned int ep)
-{
-	return -1;
-}
-#endif
-
 int uImage_ppc_load(int argc, char **argv, const char *buf, off_t len,
 		struct kexec_info *info)
 {
-	const struct image_header *header = (const struct image_header *)buf;
-	const char *img_buf = buf + sizeof(struct image_header);
-	off_t img_len = len - sizeof(struct image_header);
-	unsigned int img_base = cpu_to_be32(header->ih_load);
-	unsigned int img_entry = cpu_to_be32(header->ih_ep);
-
-	switch (header->ih_comp) {
-	case IH_COMP_NONE:
-		return ppc_load_bare_bits(argc, argv, img_buf, img_len, info,
-				img_base, img_entry);
-		break;
+	struct Image_info img;
+	int ret;
 
-	case IH_COMP_GZIP:
-		return uImage_gz_load(argc, argv, img_buf, img_len, info,
-				img_base, img_entry);
-		break;
+	ret = uImage_load(buf, len, &img);
+	if (ret)
+		return ret;
 
-	default:
-		return -1;
-	}
+	return	ppc_load_bare_bits(argc, argv, img.buf, img.len, info,
+				img.base, img.ep);
 }
diff --git a/kexec/kexec-uImage.c b/kexec/kexec-uImage.c
new file mode 100644
index 0000000..4ce0f38
--- /dev/null
+++ b/kexec/kexec-uImage.c
@@ -0,0 +1,213 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <image.h>
+#include <getopt.h>
+#include <arch/options.h>
+#include "kexec.h"
+#include <kexec-uImage.h>
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+/*
+ * Basic uImage loader. Not rocket science.
+ */
+
+int uImage_probe(const char *buf, off_t len, unsigned int arch)
+{
+	struct image_header header;
+#ifdef HAVE_LIBZ
+	unsigned int crc;
+	unsigned int hcrc;
+#endif
+
+	if ((uintmax_t)len < (uintmax_t)sizeof(header))
+		return -1;
+
+	memcpy(&header, buf, sizeof(header));
+	if (be32_to_cpu(header.ih_magic) != IH_MAGIC)
+		return -1;
+#ifdef HAVE_LIBZ
+	hcrc = be32_to_cpu(header.ih_hcrc);
+	header.ih_hcrc = 0;
+	crc = crc32(0, (void *)&header, sizeof(header));
+	if (crc != hcrc) {
+		printf("Header checksum of the uImage does not match\n");
+		return -1;
+	}
+#endif
+	if (header.ih_type != IH_TYPE_KERNEL) {
+		printf("uImage type %d unsupported\n", header.ih_type);
+		return -1;
+	}
+
+	if (header.ih_os != IH_OS_LINUX) {
+		printf("uImage os %d unsupported\n", header.ih_os);
+		return -1;
+	}
+
+	if (header.ih_arch != arch) {
+		printf("uImage arch %d unsupported\n", header.ih_arch);
+		return -1;
+	}
+
+	switch (header.ih_comp) {
+	case IH_COMP_NONE:
+#ifdef HAVE_LIBZ
+	case IH_COMP_GZIP:
+#endif
+		break;
+	default:
+		printf("uImage uses unsupported compression method\n");
+		return -1;
+	}
+
+	if (be32_to_cpu(header.ih_size) > len - sizeof(header)) {
+		printf("uImage header claims that image has %d bytes\n",
+				be32_to_cpu(header.ih_size));
+		printf("we read only %ld bytes.\n", len - sizeof(header));
+		return -1;
+	}
+#ifdef HAVE_LIBZ
+	crc = crc32(0, (void *)buf + sizeof(header), len - sizeof(header));
+	if (crc != be32_to_cpu(header.ih_dcrc)) {
+		printf("The data CRC does not match. Computed: %08x "
+				"expected %08x\n", crc,
+				be32_to_cpu(header.ih_dcrc));
+		return -1;
+	}
+#endif
+	return 0;
+}
+
+#ifdef HAVE_LIBZ
+/* gzip flag byte */
+#define ASCII_FLAG	0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC	0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD	0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME	0x08 /* bit 3 set: original file name present */
+#define COMMENT		0x10 /* bit 4 set: file comment present */
+#define RESERVED	0xE0 /* bits 5..7: reserved */
+
+static int uImage_gz_load(const char *buf, off_t len,
+		struct Image_info *image)
+{
+	int ret;
+	z_stream strm;
+	unsigned int skip;
+	unsigned int flags;
+	unsigned char *uncomp_buf;
+	unsigned int mem_alloc;
+
+	mem_alloc = 10 * 1024 * 1024;
+	uncomp_buf = malloc(mem_alloc);
+	if (!uncomp_buf)
+		return -1;
+
+	memset(&strm, 0, sizeof(strm));
+
+	/* Skip magic, method, time, flags, os code ... */
+	skip = 10;
+
+	/* check GZ magic */
+	if (buf[0] != 0x1f || buf[1] != 0x8b)
+		return -1;
+
+	flags = buf[3];
+	if (buf[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
+		puts ("Error: Bad gzipped data\n");
+		return -1;
+	}
+
+	if (flags & EXTRA_FIELD) {
+		skip += 2;
+		skip += buf[10];
+		skip += buf[11] << 8;
+	}
+	if (flags & ORIG_NAME) {
+		while (buf[skip++])
+			;
+	}
+	if (flags & COMMENT) {
+		while (buf[skip++])
+			;
+	}
+	if (flags & HEAD_CRC)
+		skip += 2;
+
+	strm.avail_in = len - skip;
+	strm.next_in = (void *)buf + skip;
+
+	/* - activates parsing gz headers */
+	ret = inflateInit2(&strm, -MAX_WBITS);
+	if (ret != Z_OK)
+		return -1;
+
+	strm.next_out = uncomp_buf;
+	strm.avail_out = mem_alloc;
+
+	do {
+		ret = inflate(&strm, Z_FINISH);
+		if (ret == Z_STREAM_END)
+			break;
+
+		if (ret == Z_OK || ret == Z_BUF_ERROR) {
+			void *new_buf;
+			int inc_buf = 5 * 1024 * 1024;
+
+			mem_alloc += inc_buf;
+			new_buf = realloc(uncomp_buf, mem_alloc);
+			if (!new_buf) {
+				inflateEnd(&strm);
+				free(uncomp_buf);
+				return -1;
+			}
+
+			strm.next_out = uncomp_buf + mem_alloc - inc_buf;
+			strm.avail_out = inc_buf;
+			uncomp_buf = new_buf;
+		} else {
+			printf("Error during decompression %d\n", ret);
+			return -1;
+		}
+	} while (1);
+
+	inflateEnd(&strm);
+	image->buf = (char *)uncomp_buf;
+	image->len = mem_alloc - strm.avail_out;
+	return 0;
+}
+#else
+static int uImage_gz_load(const char *UNUSED(buf), off_t UNUSED(len),
+		struct Image_info *UNUSED(image))
+{
+	return -1;
+}
+#endif
+
+int uImage_load(const char *buf, off_t len, struct Image_info *image)
+{
+	const struct image_header *header = (const struct image_header *)buf;
+	const char *img_buf = buf + sizeof(struct image_header);
+	off_t img_len = len - sizeof(struct image_header);
+
+	image->base = cpu_to_be32(header->ih_load);
+	image->ep = cpu_to_be32(header->ih_ep);
+	switch (header->ih_comp) {
+	case IH_COMP_NONE:
+		image->buf = img_buf;
+		image->len = len;
+		return 0;
+		break;
+
+	case IH_COMP_GZIP:
+		return uImage_gz_load(img_buf, img_len, image);
+		break;
+
+	default:
+		return -1;
+	}
+}
-- 
1.6.5.2


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

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

* [PATCH 7/7] Let SH adn ARM use common uImage probe code
  2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
                   ` (5 preceding siblings ...)
  2010-03-31  8:24 ` [PATCH 6/7] Split Powerpc's uImage code Sebastian Andrzej Siewior
@ 2010-03-31  8:24 ` Sebastian Andrzej Siewior
  6 siblings, 0 replies; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-03-31  8:24 UTC (permalink / raw)
  To: Simon Horman
  Cc: Sebastian Andrzej Siewior, Paul Mundt, kexec, Marc Andre Tanner

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The now generic probe function is more complete than the currently used.
It seems that ARM's and SH's uImage are always uncompressed so it might
be good to check for this.

Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Marc Andre Tanner <mat@brain-dump.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 kexec/arch/arm/Makefile           |    1 +
 kexec/arch/arm/kexec-uImage-arm.c |   15 ++-------------
 kexec/arch/sh/Makefile            |    1 +
 kexec/arch/sh/kexec-uImage-sh.c   |   15 ++-------------
 4 files changed, 6 insertions(+), 26 deletions(-)

diff --git a/kexec/arch/arm/Makefile b/kexec/arch/arm/Makefile
index 9416339..2ecdb66 100644
--- a/kexec/arch/arm/Makefile
+++ b/kexec/arch/arm/Makefile
@@ -5,6 +5,7 @@ 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/kexec-uImage.c
 
 dist += kexec/arch/arm/Makefile $(arm_KEXEC_SRCS)			\
 	kexec/arch/arm/kexec-arm.h					\
diff --git a/kexec/arch/arm/kexec-uImage-arm.c b/kexec/arch/arm/kexec-uImage-arm.c
index e881fd8..4875185 100644
--- a/kexec/arch/arm/kexec-uImage-arm.c
+++ b/kexec/arch/arm/kexec-uImage-arm.c
@@ -5,24 +5,13 @@
 #include <string.h>
 #include <sys/types.h>
 #include <image.h>
+#include <kexec-uImage.h>
 #include "../../kexec.h"
 #include "kexec-arm.h"
 
 int uImage_arm_probe(const char *buf, off_t len)
 {
-	struct image_header header;
-
-	if ((uintmax_t)len < (uintmax_t)sizeof(header))
-		return -1;
-
-	memcpy(&header, buf, sizeof(header));
-
-	if (cpu_to_be32(header.ih_magic) != IH_MAGIC)
-		return -1;
-
-	/* XXX: check CRC Checksum? */
-
-	return 0;
+	return uImage_probe(buf, len, IH_ARCH_ARM);
 }
 
 int uImage_arm_load(int argc, char **argv, const char *buf, off_t len,
diff --git a/kexec/arch/sh/Makefile b/kexec/arch/sh/Makefile
index 9ccd008..a9f6081 100644
--- a/kexec/arch/sh/Makefile
+++ b/kexec/arch/sh/Makefile
@@ -9,6 +9,7 @@ sh_KEXEC_SRCS += kexec/arch/sh/kexec-elf-sh.c
 sh_KEXEC_SRCS += kexec/arch/sh/kexec-elf-rel-sh.c
 sh_KEXEC_SRCS += kexec/arch/sh/netbsd_booter.S
 sh_KEXEC_SRCS += kexec/arch/sh/crashdump-sh.c
+sh_KEXEC_SRCS += kexec/kexec-uImage.c
 
 sh_ADD_BUFFER =
 sh_ADD_SEGMENT =
diff --git a/kexec/arch/sh/kexec-uImage-sh.c b/kexec/arch/sh/kexec-uImage-sh.c
index c2bce53..e983165 100644
--- a/kexec/arch/sh/kexec-uImage-sh.c
+++ b/kexec/arch/sh/kexec-uImage-sh.c
@@ -7,24 +7,13 @@
 #include <string.h>
 #include <sys/types.h>
 #include <image.h>
+#include <kexec-uImage.h>
 #include "../../kexec.h"
 #include "kexec-sh.h"
 
 int uImage_sh_probe(const char *buf, off_t len)
 {
-	struct image_header header;
-
-	if ((uintmax_t)len < (uintmax_t)sizeof(header))
-		return -1;
-
-	memcpy(&header, buf, sizeof(header));
-
-	if (cpu_to_be32(header.ih_magic) != IH_MAGIC)
-		return -1;
-
-	/* XXX: check CRC Checksum? */
-
-	return 0;
+	return uImage_probe(buf, len, IH_ARCH_SH);
 }
 
 int uImage_sh_load(int argc, char **argv, const char *buf, off_t len,
-- 
1.6.5.2


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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-03-31  8:24 ` [PATCH 3/7] powerpc32: pull in libfdt Sebastian Andrzej Siewior
@ 2010-03-31 22:58   ` Simon Horman
  2010-04-01  7:05     ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 17+ messages in thread
From: Simon Horman @ 2010-03-31 22:58 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: Sebastian Andrzej Siewior, kexec

On Wed, Mar 31, 2010 at 10:24:14AM +0200, Sebastian Andrzej Siewior wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> This is v1.2.0 of libfdt from the dtc project which is available at
>  git://www.jdl.com/software/dtc.git
> 
> The other files
> - include/page.h
> - include/types.h
> - libfdt-wrapper.c
> - ops.h
> 
> are part of the glue code which is used the powerpc boot wrapper code
> is comming from the Linux kernel v2.6.27-rc6 and has been modified a
> little to fit.

Hi,

I'm seeing some signed vs unsigned comparison warnings in this code.
Here is a stab that I took at fixing them. Do they seem reasonable to you?
If so, we could either merge them into your patch or just apply them
as another patch.

Index: kexec-tools/kexec/arch/ppc/libfdt/fdt.c
===================================================================
--- kexec-tools.orig/kexec/arch/ppc/libfdt/fdt.c	2010-04-01 09:15:34.000000000 +1100
+++ kexec-tools/kexec/arch/ppc/libfdt/fdt.c	2010-04-01 09:28:56.000000000 +1100
@@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt)
 	return 0;
 }
 
-const void *fdt_offset_ptr(const void *fdt, int offset, int len)
+const void *fdt_offset_ptr(const void *fdt, unsigned offset, unsigned len)
 {
 	const char *p;
 
@@ -189,7 +189,7 @@ const char *_fdt_find_string(const char
 	return NULL;
 }
 
-int fdt_move(const void *fdt, void *buf, int bufsize)
+int fdt_move(const void *fdt, void *buf, unsigned bufsize)
 {
 	FDT_CHECK_HEADER(fdt);
 
Index: kexec-tools/kexec/arch/ppc/libfdt/libfdt.h
===================================================================
--- kexec-tools.orig/kexec/arch/ppc/libfdt/libfdt.h	2010-04-01 09:29:38.000000000 +1100
+++ kexec-tools/kexec/arch/ppc/libfdt/libfdt.h	2010-04-01 09:34:31.000000000 +1100
@@ -122,7 +122,7 @@
 /* Low-level functions (you probably don't need these)                */
 /**********************************************************************/
 
-const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
+const void *fdt_offset_ptr(const void *fdt, unsigned offset, unsigned checklen);
 static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
 {
 	return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
@@ -206,7 +206,7 @@ int fdt_check_header(const void *fdt);
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE, standard meanings
  */
-int fdt_move(const void *fdt, void *buf, int bufsize);
+int fdt_move(const void *fdt, void *buf, unsigned bufsize);
 
 /**********************************************************************/
 /* Read-only functions                                                */
@@ -781,7 +781,7 @@ int fdt_nop_node(void *fdt, int nodeoffs
 /* Sequential write functions                                         */
 /**********************************************************************/
 
-int fdt_create(void *buf, int bufsize);
+int fdt_create(void *buf, unsigned bufsize);
 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
 int fdt_finish_reservemap(void *fdt);
 int fdt_begin_node(void *fdt, const char *name);
@@ -1071,6 +1071,6 @@ int fdt_del_node(void *fdt, int nodeoffs
 /* Debugging / informational functions                                */
 /**********************************************************************/
 
-const char *fdt_strerror(int errval);
+const char *fdt_strerror(unsigned errval);
 
 #endif /* _LIBFDT_H */

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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-03-31 22:58   ` Simon Horman
@ 2010-04-01  7:05     ` Sebastian Andrzej Siewior
  2010-04-06  6:12       ` Simon Horman
  0 siblings, 1 reply; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-04-01  7:05 UTC (permalink / raw)
  To: Simon Horman; +Cc: kexec

* Simon Horman | 2010-04-01 09:58:19 [+1100]:

>Hi,
Hi,

>I'm seeing some signed vs unsigned comparison warnings in this code.
>Here is a stab that I took at fixing them. Do they seem reasonable to you?
All but fdt_create() and fdt_strerror() look fine on the first look. The
two mentioned don't have the .c file updated. fdt_strerror() should
remain unsigned as the error code is negative.

>If so, we could either merge them into your patch or just apply them
>as another patch.
I would prefer leaving it as it. It is an external library and the time
we update it, we lose this changes. If you are going to compile this
with -Werror could you add -Wno-sign-compare for the libfdt part? If not
please apply it as a separate patch and I try to forward it upstream if
you don't.

Sebastian

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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-01  7:05     ` Sebastian Andrzej Siewior
@ 2010-04-06  6:12       ` Simon Horman
  2010-04-06  7:51         ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 17+ messages in thread
From: Simon Horman @ 2010-04-06  6:12 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: kexec

On Thu, Apr 01, 2010 at 09:05:59AM +0200, Sebastian Andrzej Siewior wrote:
> * Simon Horman | 2010-04-01 09:58:19 [+1100]:
> 
> >Hi,
> Hi,
> 
> >I'm seeing some signed vs unsigned comparison warnings in this code.
> >Here is a stab that I took at fixing them. Do they seem reasonable to you?
> All but fdt_create() and fdt_strerror() look fine on the first look. The
> two mentioned don't have the .c file updated. fdt_strerror() should
> remain unsigned as the error code is negative.
> 
> >If so, we could either merge them into your patch or just apply them
> >as another patch.
> I would prefer leaving it as it. It is an external library and the time
> we update it, we lose this changes. If you are going to compile this
> with -Werror could you add -Wno-sign-compare for the libfdt part? If not
> please apply it as a separate patch and I try to forward it upstream if
> you don't.

Ok, how about we a) merge your changes as is and b) try and get a patch
upstream that we add to kexec-tools later. I understand your reasoning
behind not wanting to diverge from libfdt-upstream, but at the same
time, I'd like to get this fixed if possible.


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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-06  6:12       ` Simon Horman
@ 2010-04-06  7:51         ` Sebastian Andrzej Siewior
  2010-04-06  8:41           ` Simon Horman
  0 siblings, 1 reply; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-04-06  7:51 UTC (permalink / raw)
  To: Simon Horman; +Cc: kexec

* Simon Horman | 2010-04-06 16:12:52 [+1000]:

>Ok, how about we a) merge your changes as is and b) try and get a patch
>upstream that we add to kexec-tools later. I understand your reasoning
>behind not wanting to diverge from libfdt-upstream, but at the same
>time, I'd like to get this fixed if possible.
Yeah, this sounds good to me. One of your fixes has allready been
applied [0]. There is no newer version of libfdt taged at this time.
Current HEAD of it produces a .so file. Is it okay with you if pull the
lib in and switch to a library once there is a official one?

[0] http://git.jdl.com/gitweb/?p=dtc.git;a=commit;h=b236893fc4bc173877adfa4270b14d7d7209fb10

Sebastian

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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-06  7:51         ` Sebastian Andrzej Siewior
@ 2010-04-06  8:41           ` Simon Horman
  2010-04-06  9:47             ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 17+ messages in thread
From: Simon Horman @ 2010-04-06  8:41 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: kexec

On Tue, Apr 06, 2010 at 09:51:08AM +0200, Sebastian Andrzej Siewior wrote:
> * Simon Horman | 2010-04-06 16:12:52 [+1000]:
> 
> >Ok, how about we a) merge your changes as is and b) try and get a patch
> >upstream that we add to kexec-tools later. I understand your reasoning
> >behind not wanting to diverge from libfdt-upstream, but at the same
> >time, I'd like to get this fixed if possible.
> Yeah, this sounds good to me. One of your fixes has allready been
> applied [0]. There is no newer version of libfdt taged at this time.
> Current HEAD of it produces a .so file. Is it okay with you if pull the
> lib in and switch to a library once there is a official one?

Yes, I think that is fine. Do you want me to just take the changes that you
posted last week?


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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-06  8:41           ` Simon Horman
@ 2010-04-06  9:47             ` Sebastian Andrzej Siewior
  2010-04-06 23:40               ` Simon Horman
  0 siblings, 1 reply; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-04-06  9:47 UTC (permalink / raw)
  To: Simon Horman; +Cc: kexec

* Simon Horman | 2010-04-06 18:41:34 [+1000]:

>Do you want me to just take the changes that you
>posted last week?

Please do it.

Sebastian

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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-06  9:47             ` Sebastian Andrzej Siewior
@ 2010-04-06 23:40               ` Simon Horman
  2010-04-21 14:13                 ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 17+ messages in thread
From: Simon Horman @ 2010-04-06 23:40 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: kexec

On Tue, Apr 06, 2010 at 11:47:59AM +0200, Sebastian Andrzej Siewior wrote:
> * Simon Horman | 2010-04-06 18:41:34 [+1000]:
> 
> >Do you want me to just take the changes that you
> >posted last week?
> 
> Please do it.

Done :-)

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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-06 23:40               ` Simon Horman
@ 2010-04-21 14:13                 ` Sebastian Andrzej Siewior
  2010-05-21 23:20                   ` Simon Horman
  0 siblings, 1 reply; 17+ messages in thread
From: Sebastian Andrzej Siewior @ 2010-04-21 14:13 UTC (permalink / raw)
  To: Simon Horman; +Cc: kexec

* Simon Horman | 2010-04-07 09:40:44 [+1000]:

>Done :-)

I kinda forgot: What is the status on fixing the signed/unsigned things
in here?
Am I looking after it or did you want to push some patches first?

Sebastian

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

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

* Re: [PATCH 3/7] powerpc32: pull in libfdt
  2010-04-21 14:13                 ` Sebastian Andrzej Siewior
@ 2010-05-21 23:20                   ` Simon Horman
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Horman @ 2010-05-21 23:20 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: kexec

On Wed, Apr 21, 2010 at 04:13:58PM +0200, Sebastian Andrzej Siewior wrote:
> * Simon Horman | 2010-04-07 09:40:44 [+1000]:
> 
> >Done :-)
> 
> I kinda forgot: What is the status on fixing the signed/unsigned things
> in here?
> Am I looking after it or did you want to push some patches first?

I was hoping you would forward either my patch of a variant upstream.
I'm happy to send it directly if you think that would be better.


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

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

end of thread, other threads:[~2010-05-22  3:54 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-31  8:24 PPC32 kexec v3 Sebastian Andrzej Siewior
2010-03-31  8:24 ` [PATCH 1/7] slurpfile: use lseek() on character nodes instead of fstat() for file size Sebastian Andrzej Siewior
2010-03-31  8:24 ` [PATCH 2/7] powerpc: dtb and purgatory support for ppc32 Sebastian Andrzej Siewior
2010-03-31  8:24 ` [PATCH 3/7] powerpc32: pull in libfdt Sebastian Andrzej Siewior
2010-03-31 22:58   ` Simon Horman
2010-04-01  7:05     ` Sebastian Andrzej Siewior
2010-04-06  6:12       ` Simon Horman
2010-04-06  7:51         ` Sebastian Andrzej Siewior
2010-04-06  8:41           ` Simon Horman
2010-04-06  9:47             ` Sebastian Andrzej Siewior
2010-04-06 23:40               ` Simon Horman
2010-04-21 14:13                 ` Sebastian Andrzej Siewior
2010-05-21 23:20                   ` Simon Horman
2010-03-31  8:24 ` [PATCH 4/7] powerpc32: add support to fixup the dtb Sebastian Andrzej Siewior
2010-03-31  8:24 ` [PATCH 5/7] powerpc32: add support for uImage Sebastian Andrzej Siewior
2010-03-31  8:24 ` [PATCH 6/7] Split Powerpc's uImage code Sebastian Andrzej Siewior
2010-03-31  8:24 ` [PATCH 7/7] Let SH adn ARM use common uImage probe code Sebastian Andrzej Siewior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox