summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Leach <matthew.leach@arm.com>2012-09-07 10:11:26 +0100
committerSimon Horman <horms@verge.net.au>2012-09-12 09:32:34 +0900
commitf0839230276d32a67b5a4a65e199c1937adb3643 (patch)
tree778edaa15d14ca1cd3e626c3010f969b7f8d1360
parent7f4d00a19a56a3b9ffd0b793ae31082ad926b68c (diff)
ARM: Add device tree support to the ARM platform
To allow newer ARM platforms to use kexec, pass device tree information to the kernel during boot. By default the dtb is found from /proc/device-tree. A user can specify a dtb file or use legacy ATAGs Signed-off-by: Matthew Leach <matthew.leach@arm.com> Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r--kexec/arch/arm/Makefile13
-rw-r--r--kexec/arch/arm/include/arch/options.h6
-rw-r--r--kexec/arch/arm/kexec-arm.h7
-rw-r--r--kexec/arch/arm/kexec-zImage-arm.c87
4 files changed, 103 insertions, 10 deletions
diff --git a/kexec/arch/arm/Makefile b/kexec/arch/arm/Makefile
index 288ec33..192e6ec 100644
--- a/kexec/arch/arm/Makefile
+++ b/kexec/arch/arm/Makefile
@@ -1,11 +1,24 @@
#
# 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/arch/arm/kexec-elf-rel-arm.c
arm_KEXEC_SRCS+= kexec/arch/arm/kexec-zImage-arm.c
arm_KEXEC_SRCS+= kexec/arch/arm/kexec-uImage-arm.c
arm_KEXEC_SRCS+= kexec/arch/arm/kexec-arm.c
arm_KEXEC_SRCS+= kexec/arch/arm/crashdump-arm.c
+arm_KEXEC_SRCS+= kexec/fs2dt.c
+
+libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%)
+
+CPPFLAGS+=-I$(srcdir)/kexec/libfdt
+
+arm_KEXEC_SRCS += $(libfdt_SRCS)
arm_UIMAGE = kexec/kexec-uImage.c
arm_PHYS_TO_VIRT = kexec/arch/arm/phys_to_virt.c
diff --git a/kexec/arch/arm/include/arch/options.h b/kexec/arch/arm/include/arch/options.h
index d89c91f..b355c26 100644
--- a/kexec/arch/arm/include/arch/options.h
+++ b/kexec/arch/arm/include/arch/options.h
@@ -5,6 +5,8 @@
#define OPT_APPEND 'a'
#define OPT_RAMDISK 'r'
+#define OPT_DTB (OPT_ARCH_MAX+0)
+#define OPT_ATAGS (OPT_ARCH_MAX+1)
/* Options relevant to the architecture (excluding loader-specific ones),
* in this case none:
@@ -33,7 +35,9 @@
{ "command-line", 1, 0, OPT_APPEND }, \
{ "append", 1, 0, OPT_APPEND }, \
{ "initrd", 1, 0, OPT_RAMDISK }, \
- { "ramdisk", 1, 0, OPT_RAMDISK },
+ { "ramdisk", 1, 0, OPT_RAMDISK }, \
+ { "dtb", 1, 0, OPT_DTB }, \
+ { "atags", 0, 0, OPT_ATAGS },
#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR "a:r:"
diff --git a/kexec/arch/arm/kexec-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..46cedbf 100644
--- a/kexec/arch/arm/kexec-zImage-arm.c
+++ b/kexec/arch/arm/kexec-zImage-arm.c
@@ -13,13 +13,18 @@
#include <unistd.h>
#include <getopt.h>
#include <unistd.h>
+#include <libfdt.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;
@@ -96,6 +101,8 @@ void zImage_arm_usage(void)
" --append=STRING Set the kernel command line to STRING.\n"
" --initrd=FILE Use FILE as the kernel's initial ramdisk.\n"
" --ramdisk=FILE Use FILE as the kernel's initial ramdisk.\n"
+ " --dtb=FILE Use FILE as the fdt blob.\n"
+ " --atags Use ATAGs instead of device-tree.\n"
);
}
@@ -219,9 +226,13 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
off_t command_line_len;
const char *ramdisk;
char *ramdisk_buf;
- off_t ramdisk_length;
- off_t ramdisk_offset;
int opt;
+ int use_atags;
+ char *dtb_buf;
+ off_t dtb_length;
+ char *dtb_file;
+ off_t dtb_offset;
+
/* See options.h -- add any more there, too. */
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
@@ -229,6 +240,8 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
{ "append", 1, 0, OPT_APPEND },
{ "initrd", 1, 0, OPT_RAMDISK },
{ "ramdisk", 1, 0, OPT_RAMDISK },
+ { "dtb", 1, 0, OPT_DTB },
+ { "atags", 0, 0, OPT_ATAGS },
{ 0, 0, 0, 0 },
};
static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:";
@@ -240,7 +253,9 @@ 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;
+ initrd_size = 0;
+ use_atags = 0;
+ dtb_file = NULL;
while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch(opt) {
default:
@@ -257,15 +272,28 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
case OPT_RAMDISK:
ramdisk = optarg;
break;
+ case OPT_DTB:
+ dtb_file = optarg;
+ break;
+ case OPT_ATAGS:
+ use_atags = 1;
+ break;
}
}
+
+ if (use_atags && dtb_file) {
+ fprintf(stderr, "You can only use ATAGs if you don't specify a "
+ "dtb file.\n");
+ return -1;
+ }
+
if (command_line) {
command_line_len = strlen(command_line) + 1;
if (command_line_len > COMMAND_LINE_SIZE)
command_line_len = COMMAND_LINE_SIZE;
}
if (ramdisk) {
- ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+ ramdisk_buf = slurp_file(ramdisk, &initrd_size);
}
/*
@@ -315,12 +343,53 @@ 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 (atag_arm_load(info, base + atag_offset,
- command_line, command_line_len,
- ramdisk_buf, ramdisk_length, ramdisk_offset) == -1)
- return -1;
+ if (use_atags) {
+ /*
+ * use ATAGs from /proc/atags
+ */
+ if (atag_arm_load(info, base + atag_offset,
+ command_line, command_line_len,
+ ramdisk_buf, initrd_size, initrd_base) == -1)
+ return -1;
+ } else {
+ /*
+ * Read a user-specified DTB file.
+ */
+ if (dtb_file) {
+ dtb_buf = slurp_file(dtb_file, &dtb_length);
+ } else {
+ /*
+ * Extract the DTB from /proc/device-tree.
+ */
+ create_flatten_tree(&dtb_buf, &dtb_length, command_line);
+ }
+
+ if (fdt_check_header(dtb_buf) != 0) {
+ fprintf(stderr, "Invalid FDT buffer.\n");
+ return -1;
+ }
+
+ if (base + atag_offset + dtb_length > base + offset) {
+ fprintf(stderr, "DTB too large!\n");
+ return -1;
+ }
+
+ if (ramdisk) {
+ add_segment(info, ramdisk_buf, initrd_size,
+ initrd_base, initrd_size);
+ }
+
+ /* Stick the dtb at the end of the initrd and page
+ * align it.
+ */
+ dtb_offset = initrd_base + initrd_size + getpagesize();
+ dtb_offset &= ~(getpagesize() - 1);
+
+ add_segment(info, dtb_buf, dtb_length,
+ dtb_offset, dtb_length);
+ }
add_segment(info, buf, len, base + offset, len);