[PATCH 1/2] ARM: cleanup initrd and dtb handing

Russell King rmk at armlinux.org.uk
Mon Oct 23 03:05:48 PDT 2017


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 at armlinux.org.uk>
---
 kexec/arch/arm/kexec-zImage-arm.c | 116 +++++++++++++++++++-------------------
 1 file 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);
-- 
2.7.4


-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up



More information about the kexec mailing list