[PATCH 7/7] arm: Add Device Tree support

Simon Horman horms at verge.net.au
Tue Aug 28 04:18:30 EDT 2012


This should mirror the functionality available in 32 and 64 bit powerpc.

1. A dtb may be provided on the command line using the --dtb command line option
2. Else, if /proc/device-tree is present a flattened devices tree will
   be synthesised from there
3. Otherwise kexec-tools will fall back to the existing atags behaviour,
   synthesising atags from /proc/atags

This patch has undergone light testing using an Armadillo 800 EVA board
in conjunction with a 3.6-rc3 kernel.

Signed-off-by: Simon Horman <horms at verge.net.au>
---
 kexec/arch/arm/Makefile               |   8 +++
 kexec/arch/arm/include/arch/options.h |   4 +-
 kexec/arch/arm/kexec-arm.h            |   7 +++
 kexec/arch/arm/kexec-zImage-arm.c     | 100 +++++++++++++++++++++++++++++++---
 kexec/fs2dt.h                         |   1 -
 5 files changed, 109 insertions(+), 11 deletions(-)

diff --git a/kexec/arch/arm/Makefile b/kexec/arch/arm/Makefile
index 288ec33..00e6acd 100644
--- a/kexec/arch/arm/Makefile
+++ b/kexec/arch/arm/Makefile
@@ -1,6 +1,14 @@
 #
 # kexec arm (linux booting linux)
 #
+include $(srcdir)/kexec/libfdt/Makefile.libfdt
+
+arm_FS2DT		= kexec/fs2dt.c
+arm_FS2DT_INCLUDE	= -include kexec/arch/arm/crashdump-arm.h \
+			  -include kexec/arch/arm/kexec-arm.h
+
+arm_KEXEC_SRCS += kexec/fs2dt.c
+
 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
diff --git a/kexec/arch/arm/include/arch/options.h b/kexec/arch/arm/include/arch/options.h
index d89c91f..de08471 100644
--- a/kexec/arch/arm/include/arch/options.h
+++ b/kexec/arch/arm/include/arch/options.h
@@ -5,6 +5,7 @@
 
 #define OPT_APPEND	'a'
 #define OPT_RAMDISK	'r'
+#define OPT_DTB		(OPT_ARCH_MAX+0)
 
 /* Options relevant to the architecture (excluding loader-specific ones),
  * in this case none:
@@ -33,7 +34,8 @@
 	{ "command-line",	1, 0, OPT_APPEND },	\
 	{ "append",		1, 0, OPT_APPEND },	\
 	{ "initrd",		1, 0, OPT_RAMDISK },	\
-	{ "ramdisk",		1, 0, OPT_RAMDISK },
+	{ "ramdisk",		1, 0, OPT_RAMDISK },	\
+	{ "dtb",		1, 0, OPT_DTB },
 
 #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR "a:r:"
 
diff --git a/kexec/arch/arm/kexec-arm.h b/kexec/arch/arm/kexec-arm.h
index 0d9a066..79663e3 100644
--- a/kexec/arch/arm/kexec-arm.h
+++ b/kexec/arch/arm/kexec-arm.h
@@ -1,6 +1,13 @@
 #ifndef KEXEC_ARM_H
 #define KEXEC_ARM_H
 
+#include <sys/types.h>
+
+#define BOOT_BLOCK_VERSION 17
+#define BOOT_BLOCK_LAST_COMP_VERSION 16
+
+extern off_t initrd_base, initrd_size;
+
 int zImage_arm_probe(const char *buf, off_t len);
 int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 		        struct kexec_info *info);
diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
index 88a6c29..788b941 100644
--- a/kexec/arch/arm/kexec-zImage-arm.c
+++ b/kexec/arch/arm/kexec-zImage-arm.c
@@ -7,19 +7,25 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdint.h>
 #include <unistd.h>
 #include <getopt.h>
 #include <unistd.h>
+#include <ctype.h>
 #include <arch/options.h>
 #include "../../kexec.h"
 #include "../../kexec-syscall.h"
+#include "kexec-arm.h"
+#include "../../fs2dt.h"
 #include "crashdump-arm.h"
 
 #define BOOT_PARAMS_SIZE 1536
 
+off_t initrd_base = 0, initrd_size = 0;
+
 struct tag_header {
 	uint32_t size;
 	uint32_t tag;
@@ -208,20 +214,80 @@ int atag_arm_load(struct kexec_info *info, unsigned long base,
 	return 0;
 }
 
+static
+void dtb_arm_load(struct kexec_info *info, unsigned long base,
+		 const char *dtb, const char *command_line)
+{
+	char *blob_buf = NULL;
+	off_t blob_size = 0;
+
+	/* Here we need to initialize the device tree, and find out where
+	 * it is going to live so we can place it directly after the
+	 * kernel image */
+	if (dtb) {
+		/* Grab device tree from buffer */
+		blob_buf = slurp_file(dtb, &blob_size);
+	} else {
+		create_flatten_tree(&blob_buf, &blob_size, command_line);
+	}
+
+	if (!blob_buf || !blob_size)
+		die("Device tree seems to be an empty file.\n");
+
+	{
+		int i = 0, j = 0, k, alt = 0;
+		while (i < blob_size && j < blob_size) {
+			if (!(k % 16)) {
+				if (!alt)
+					fprintf(stderr, "%04x ", i);
+				else
+					fprintf(stderr, "     ");
+			}
+			if (!alt) {
+				if (isprint(blob_buf[i]))
+					fprintf(stderr, " %c", blob_buf[i]);
+				else
+					fprintf(stderr, "%02x", blob_buf[i]);
+				k = ++i;
+			} else {
+				fprintf(stderr, "%02x", blob_buf[j]);
+				k = ++j;
+			}
+			switch (k % 16) {
+			case 0:
+				fprintf(stderr, "\n");
+				if (alt)
+					fprintf(stderr, "\n");
+				alt = alt ? 0 : 1;
+				break;
+			case 8:
+				fprintf(stderr, "  ");
+				break;
+			default:
+				fprintf(stderr, " ");
+				break;
+			}
+		}
+		fprintf(stderr, "\n");
+	}
+
+	add_segment(info, blob_buf, blob_size, base, blob_size);
+}
+
 int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info)
 {
 	unsigned long base;
-	unsigned int atag_offset = 0x1000; /* 4k offset from memory start */
+	unsigned int base_offset = 0x1000; /* 4k offset from memory start */
 	unsigned int offset = 0x8000;      /* 32k offset from memory start */
 	const char *command_line;
 	char *modified_cmdline = NULL;
 	off_t command_line_len;
 	const char *ramdisk;
 	char *ramdisk_buf;
-	off_t ramdisk_length;
-	off_t ramdisk_offset;
+	const char *dtb = NULL;
 	int opt;
+	bool have_proc_device_tree = false;
 	/* See options.h -- add any more there, too. */
 	static const struct option options[] = {
 		KEXEC_ARCH_OPTIONS
@@ -229,6 +295,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 		{ "append",		1, 0, OPT_APPEND },
 		{ "initrd",		1, 0, OPT_RAMDISK },
 		{ "ramdisk",		1, 0, OPT_RAMDISK },
+		{ "dtb",		1, 0, OPT_DTB },
 		{ 0, 			0, 0, 0 },
 	};
 	static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:";
@@ -240,7 +307,6 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	command_line_len = 0;
 	ramdisk = 0;
 	ramdisk_buf = 0;
-	ramdisk_length = 0;
 	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch(opt) {
 		default:
@@ -257,6 +323,9 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 		case OPT_RAMDISK:
 			ramdisk = optarg;
 			break;
+		case OPT_DTB:
+			dtb = optarg;
+			break;
 		}
 	}
 	if (command_line) {
@@ -265,7 +334,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 			command_line_len = COMMAND_LINE_SIZE;
 	}
 	if (ramdisk) {
-		ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+		ramdisk_buf = slurp_file(ramdisk, &initrd_size);
 	}
 
 	/*
@@ -315,11 +384,24 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
 	/* assume the maximum kernel compression ratio is 4,
 	 * and just to be safe, place ramdisk after that
 	 */
-	ramdisk_offset = base + len * 4;
+	initrd_base = base + len * 4;
+
+	if (!dtb) {
+		const char *fn = "/proc/device-tree/";
+
+		if (!access(fn, F_OK))
+			have_proc_device_tree = true;
+		else if (errno == ENOENT)
+			have_proc_device_tree = false;
+		else
+			die("Failed to check for the presence of %s", fn);
+	}
 
-	if (atag_arm_load(info, base + atag_offset,
-			 command_line, command_line_len,
-			 ramdisk_buf, ramdisk_length, ramdisk_offset) == -1)
+	if (dtb || have_proc_device_tree)
+	    dtb_arm_load(info, base + base_offset, dtb, command_line);
+	else if (atag_arm_load(info, base + base_offset, command_line,
+			       command_line_len, ramdisk_buf,
+			       initrd_size, initrd_base) == -1)
 		return -1;
 
 	add_segment(info, buf, len, base + offset, len);
diff --git a/kexec/fs2dt.h b/kexec/fs2dt.h
index 6c5c3b2..99e616f 100644
--- a/kexec/fs2dt.h
+++ b/kexec/fs2dt.h
@@ -32,7 +32,6 @@ extern struct bootblock bb[1];
  * Only has implemented for PPC64 */
 int my_debug;
 
-void reserve(unsigned long long where, unsigned long long length);
 void create_flatten_tree(char **, off_t *, const char *);
 
 #endif /* KEXEC_H */
-- 
1.7.10.2.484.gcd07cc5




More information about the kexec mailing list