[PATCH 2/2] kexec ppc64: Add arch specific --reuseinitrd hooks

Michael Neuling mikey at neuling.org
Fri Apr 27 00:53:19 EDT 2007


Adds ppc64 specific hooks for the --reuseinitrd option.

Signed-off-by: Michael Neuling <mikey at neuling.org>
---

 kexec/arch/ppc64/fs2dt.c           |   30 +++++++++++-----
 kexec/arch/ppc64/kexec-elf-ppc64.c |   12 +++++-
 kexec/arch/ppc64/kexec-ppc64.c     |   69 +++++++++++++++++++++++++++++++++++++
 kexec/arch/ppc64/kexec-ppc64.h     |    1 
 4 files changed, 103 insertions(+), 9 deletions(-)

Index: kexec-tools-testing/kexec/arch/ppc64/fs2dt.c
===================================================================
--- kexec-tools-testing.orig/kexec/arch/ppc64/fs2dt.c
+++ kexec-tools-testing/kexec/arch/ppc64/fs2dt.c
@@ -66,11 +66,11 @@ void reserve(unsigned long long where, u
 }
 
 /* look for properties we need to reserve memory space for */
-static void checkprop(char *name, unsigned *data)
+static void checkprop(char *name, unsigned *data, int len)
 {
-	static unsigned long long base, size;
+	static unsigned long long base, size, end;
 
-	if ((data == NULL) && (base || size))
+	if ((data == NULL) && (base || size || end))
 		die("unrecoverable error: no property data");
 	else if (!strcmp(name, "linux,rtas-base"))
 		base = *data;
@@ -79,11 +79,24 @@ static void checkprop(char *name, unsign
 	else if (!strcmp(name, "rtas-size") ||
 			!strcmp(name, "linux,tce-size"))
 		size = *data;
+	else if (reuse_initrd && !strcmp(name, "linux,initrd-start"))
+		if (len == 8)
+			base = *(unsigned long long *) data;
+		else
+			base = *data;
+	else if (reuse_initrd && !strcmp(name, "linux,initrd-end"))
+		end = *(unsigned long long *) data;
 
+	if (size && end)
+		die("unrecoverable error: size and end set at same time\n");
 	if (base && size) {
 		reserve(base, size);
 		base = size = 0;
 	}
+	if (base && end) {
+		reserve(base, end-base);
+		base = end = 0;
+	}
 }
 
 /*
@@ -213,10 +226,11 @@ static void putprops(char *fn, struct di
 				continue;
 
 		/* This property will be created/modified later in putnode()
-		 * So ignore it.
+		 * So ignore it, unless we are reusing the initrd.
 		 */
-		if (!strcmp(dp->d_name, "linux,initrd-start") ||
-			!strcmp(dp->d_name, "linux,initrd-end"))
+		if ((!strcmp(dp->d_name, "linux,initrd-start") ||
+		     !strcmp(dp->d_name, "linux,initrd-end")) &&
+		    !reuse_initrd)
 				continue;
 
 		if (! S_ISREG(statbuf.st_mode))
@@ -241,7 +255,7 @@ static void putprops(char *fn, struct di
 			die("unrecoverable error: could not read \"%s\": %s\n",
 			    pathname, strerror(errno));
 
-		checkprop(fn, dt);
+		checkprop(fn, dt, len);
 
 		/* Get the cmdline from the device-tree and modify it */
 		if (!strcmp(dp->d_name, "bootargs")) {
@@ -282,7 +296,7 @@ static void putprops(char *fn, struct di
 	}
 
 	fn[0] = '\0';
-	checkprop(pathname, NULL);
+	checkprop(pathname, NULL, 0);
 }
 
 /*
Index: kexec-tools-testing/kexec/arch/ppc64/kexec-elf-ppc64.c
===================================================================
--- kexec-tools-testing.orig/kexec/arch/ppc64/kexec-elf-ppc64.c
+++ kexec-tools-testing/kexec/arch/ppc64/kexec-elf-ppc64.c
@@ -43,6 +43,8 @@
 #define BOOTLOADER_VERSION VERSION
 
 unsigned long initrd_base, initrd_size;
+unsigned char reuse_initrd = 0;
+const char *ramdisk;
 
 int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
 			char *);
@@ -69,12 +71,17 @@ int elf_ppc64_probe(const char *buf, off
 	return result;
 }
 
+void arch_reuse_initrd(void)
+{
+	reuse_initrd = 1;
+}
+
 int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
 			struct kexec_info *info)
 {
 	struct mem_ehdr ehdr;
 	char *cmdline, *modified_cmdline;
-	const char *ramdisk, *devicetreeblob;
+	const char *devicetreeblob;
 	int cmdline_len, modified_cmdline_len;
 	unsigned long long max_addr, hole_addr;
 	unsigned char *seg_buf = NULL;
@@ -148,6 +155,9 @@ int elf_ppc64_load(int argc, char **argv
 	else
 		fprintf(stdout, "Warning: append= option is not passed. Using the first kernel root partition\n");
 
+	if (ramdisk && reuse_initrd)
+		die("Can't specify --ramdisk or --initrd with --reuseinitrd\n");
+
 	setup_memory_ranges(info->kexec_flags);
 
 	/* Need to append some command line parameters internally in case of
Index: kexec-tools-testing/kexec/arch/ppc64/kexec-ppc64.c
===================================================================
--- kexec-tools-testing.orig/kexec/arch/ppc64/kexec-ppc64.c
+++ kexec-tools-testing/kexec/arch/ppc64/kexec-ppc64.c
@@ -122,6 +122,11 @@ static int count_memory_ranges()
 			continue;
 		max_memory_ranges++;
 	}
+	/* need to add extra region for retained initrd */
+	if (reuse_initrd) {
+		max_memory_ranges++;
+	}
+
 	closedir(dir);
 
 	return 0;
@@ -253,12 +258,14 @@ static int get_devtree_details(unsigned 
 	unsigned int tce_size;
 	unsigned long long htab_base, htab_size;
 	unsigned long long kernel_end;
+	unsigned long long initrd_start, initrd_end;
 	char buf[MAXBYTES-1];
 	char device_tree[256] = "/proc/device-tree/";
 	char fname[256];
 	DIR *dir, *cdir;
 	FILE *file;
 	struct dirent *dentry;
+	struct stat *fstat = malloc(sizeof(struct stat));
 	int n, i = 0;
 
 	if ((dir = opendir(device_tree)) == NULL) {
@@ -394,6 +401,68 @@ static int get_devtree_details(unsigned 
 			exclude_range[i].start = htab_base;
 			exclude_range[i].end = htab_base + htab_size;
 			i++;
+
+			/* reserve the initrd_start and end locations. */
+			if (reuse_initrd) {
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,initrd-start");
+				if ((file = fopen(fname, "r")) == NULL) {
+					perror(fname);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				/* check for 4 and 8 byte initrd offset sizes */
+				if (stat(fname, fstat) != 0) {
+					perror(fname);
+					fclose(file);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+ 				if (fread(&initrd_start, fstat->st_size, 1, file) != 1) {
+					perror(fname);
+					fclose(file);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				fclose(file);
+
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,initrd-end");
+				if ((file = fopen(fname, "r")) == NULL) {
+					perror(fname);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				/* check for 4 and 8 byte initrd offset sizes */
+				if (stat(fname, fstat) != 0) {
+					perror(fname);
+					fclose(file);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+ 				if (fread(&initrd_end, fstat->st_size, 1, file) != 1) {
+					perror(fname);
+					fclose(file);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				fclose(file);
+
+				/* Add initrd address to exclude_range */
+				exclude_range[i].start = initrd_start;
+				exclude_range[i].end = initrd_end;
+				i++;
+			}
 		} /* chosen */
 
 		if (strncmp(dentry->d_name, "rtas", 4) == 0) {
Index: kexec-tools-testing/kexec/arch/ppc64/kexec-ppc64.h
===================================================================
--- kexec-tools-testing.orig/kexec/arch/ppc64/kexec-ppc64.h
+++ kexec-tools-testing/kexec/arch/ppc64/kexec-ppc64.h
@@ -16,6 +16,7 @@ void reserve(unsigned long long where, u
 
 extern unsigned long initrd_base, initrd_size;
 extern int max_memory_ranges;
+extern unsigned char reuse_initrd;
 
 /* boot block version 2 as defined by the linux kernel */
 struct bootblock {



More information about the kexec mailing list