summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@armlinux.org.uk>2017-10-23 11:05:48 +0100
committerSimon Horman <horms@verge.net.au>2017-11-01 09:09:39 +0100
commit34bf700f981ad3cf591cafb8b4598324cddf8489 (patch)
tree0e64ee8a0e8ee2194a482abc69dfe4b0c1a20ee9
parentc06753313db7f18ff98c0f0fdeb2aa1209ed2564 (diff)
ARM: cleanup initrd and dtb handing
There is no difference in the way the initrd is handled between an ATAG-based kernel and a DTB-based kernel. Therefore, this should be handled identically in both cases. Rearrange the code to achieve this. Signed-off-by: Russell King <rmk@armlinux.org.uk> Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r--kexec/arch/arm/kexec-zImage-arm.c116
1 files changed, 57 insertions, 59 deletions
diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
index 7f02b93..c6ecb04 100644
--- a/kexec/arch/arm/kexec-zImage-arm.c
+++ b/kexec/arch/arm/kexec-zImage-arm.c
@@ -24,7 +24,7 @@
#define BOOT_PARAMS_SIZE 1536
-off_t initrd_base = 0, initrd_size = 0;
+off_t initrd_base, initrd_size;
unsigned int kexec_arm_image_size = 0;
unsigned long long user_page_offset = (-1ULL);
@@ -200,14 +200,12 @@ int create_mem32_tag(struct tag_mem32 *tag_mem32)
static
int atag_arm_load(struct kexec_info *info, unsigned long base,
- const char *command_line, off_t command_line_len,
- const char *initrd, off_t initrd_len, off_t initrd_off)
+ const char *command_line, off_t command_line_len, const char *initrd)
{
struct tag *saved_tags = atag_read_tags();
char *buf;
off_t len;
struct tag *params;
- uint32_t *initrd_start = NULL;
buf = xmalloc(getpagesize());
if (!buf) {
@@ -251,8 +249,8 @@ int atag_arm_load(struct kexec_info *info, unsigned long base,
if (initrd) {
params->hdr.size = tag_size(tag_initrd);
params->hdr.tag = ATAG_INITRD2;
- initrd_start = &params->u.initrd.start;
- params->u.initrd.size = initrd_len;
+ params->u.initrd.start = initrd_base;
+ params->u.initrd.size = initrd_size;
params = tag_next(params);
}
@@ -272,14 +270,6 @@ int atag_arm_load(struct kexec_info *info, unsigned long base,
add_segment(info, buf, len, base, len);
- if (initrd) {
- *initrd_start = locate_hole(info, initrd_len, getpagesize(),
- initrd_off, ULONG_MAX, INT_MAX);
- if (*initrd_start == ULONG_MAX)
- return -1;
- add_segment(info, initrd, initrd_len, *initrd_start, initrd_len);
- }
-
return 0;
}
@@ -348,6 +338,7 @@ static int setup_dtb_prop(char **bufp, off_t *sizep, int parentoffset,
int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
+ unsigned long page_size = getpagesize();
unsigned long base, kernel_base;
unsigned int atag_offset = 0x1000; /* 4k offset from memory start */
unsigned int extra_size = 0x8000; /* TEXT_OFFSET */
@@ -513,6 +504,14 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
kernel_mem_size = len + 4;
/*
+ * If the user didn't specify the size of the image, assume the
+ * maximum kernel compression ratio is 4. Note that we must
+ * include space for the compressed image here as well.
+ */
+ if (!kexec_arm_image_size)
+ kexec_arm_image_size = len * 5;
+
+ /*
* If we are loading a dump capture kernel, we need to update kernel
* command line and also add some additional segments.
*/
@@ -562,17 +561,28 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
kernel_base = base + extra_size;
- if (kexec_arm_image_size) {
- /* If the image size was passed as command line argument,
- * use that value for determining the address for initrd,
- * atags and dtb images. page-align the given length.*/
- initrd_base = kernel_base + _ALIGN(kexec_arm_image_size, getpagesize());
- } else {
- /* Otherwise, assume the maximum kernel compression ratio
- * is 4, and just to be safe, place ramdisk after that.
- * Note that we must include space for the compressed
- * image here as well. */
- initrd_base = kernel_base + _ALIGN(len * 5, getpagesize());
+ /*
+ * Calculate the minimum address of the initrd, which must be
+ * above the memory used by the zImage while it runs. This
+ * needs to be page-size aligned.
+ */
+ initrd_base = kernel_base + _ALIGN(kexec_arm_image_size, page_size);
+
+ if (ramdisk_buf) {
+ /*
+ * Find a hole to place the initrd. The crash kernel use
+ * fixed address, so no check is ok.
+ */
+ if (!(info->kexec_flags & KEXEC_ON_CRASH)) {
+ initrd_base = locate_hole(info, initrd_size, page_size,
+ initrd_base,
+ ULONG_MAX, INT_MAX);
+ if (initrd_base == ULONG_MAX)
+ return -1;
+ }
+
+ add_segment(info, ramdisk_buf, initrd_size, initrd_base,
+ initrd_size);
}
if (use_atags) {
@@ -581,7 +591,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
*/
if (atag_arm_load(info, base + atag_offset,
command_line, command_line_len,
- ramdisk_buf, initrd_size, initrd_base) == -1)
+ ramdisk_buf) == -1)
return -1;
} else {
/*
@@ -611,36 +621,11 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
}
/*
- * Search in memory to make sure there is enough memory
- * to hold initrd and dtb.
- *
- * Even if no initrd is used, this check is still
- * required for dtb.
- *
- * Crash kernel use fixed address, no check is ok.
+ * Add the initrd parameters to the dtb
*/
- if ((info->kexec_flags & KEXEC_ON_CRASH) == 0) {
- unsigned long page_size = getpagesize();
- /*
- * DTB size may be increase a little
- * when setup initrd size. Add a full page
- * for it is enough.
- */
- unsigned long hole_size = _ALIGN_UP(initrd_size, page_size) +
- _ALIGN(dtb_length + page_size, page_size);
- unsigned long initrd_base_new = locate_hole(info,
- hole_size, page_size,
- initrd_base, ULONG_MAX, INT_MAX);
- if (initrd_base_new == ULONG_MAX)
- return -1;
- initrd_base = initrd_base_new;
- }
-
if (ramdisk_buf) {
- add_segment(info, ramdisk_buf, initrd_size,
- initrd_base, initrd_size);
-
unsigned long start, end;
+
start = cpu_to_be32((unsigned long)(initrd_base));
end = cpu_to_be32((unsigned long)(initrd_base + initrd_size));
@@ -654,14 +639,27 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
return -1;
}
- /* Stick the dtb at the end of the initrd and page
- * align it.
+ /*
+ * The dtb must also be placed above the memory used by
+ * the zImage. We don't care about its position wrt the
+ * ramdisk, but we might as well place it after the initrd.
+ * We leave a buffer page between the initrd and the dtb.
*/
- dtb_offset = initrd_base + initrd_size + getpagesize();
- dtb_offset = _ALIGN_DOWN(dtb_offset, getpagesize());
+ dtb_offset = initrd_base + initrd_size + page_size;
+ dtb_offset = _ALIGN_DOWN(dtb_offset, page_size);
+
+ /*
+ * Find a hole to place the dtb above the initrd.
+ * Crash kernel use fixed address, no check is ok.
+ */
+ if (!(info->kexec_flags & KEXEC_ON_CRASH)) {
+ dtb_offset = locate_hole(info, dtb_length, page_size,
+ dtb_offset, ULONG_MAX, INT_MAX);
+ if (dtb_offset == ULONG_MAX)
+ return -1;
+ }
- add_segment(info, dtb_buf, dtb_length,
- dtb_offset, dtb_length);
+ add_segment(info, dtb_buf, dtb_length, dtb_offset, dtb_length);
}
add_segment(info, buf, len, kernel_base, kernel_mem_size);