[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