[PATCH] Fix case where phys_addr_t != unsigned long when reading proc entries

Matthew McClintock msm at freescale.com
Wed Jul 14 11:32:32 EDT 2010


On some actitectures the physical memory can be 64 bits, therefore
the code that reads proc entries needs to take into account it could
read either a 32 bit or 64bit value for the physical addresses.

Signed-off-by: Matthew McClintock <msm at freescale.com>
---
 kexec/arch/ppc/kexec-elf-ppc.c |    1 -
 kexec/arch/ppc/kexec-ppc.c     |  210 ++++++++++++++++++++++++++++------------
 kexec/arch/ppc/kexec-ppc.h     |    1 +
 3 files changed, 148 insertions(+), 64 deletions(-)

diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c
index d155bde..ab2d343 100644
--- a/kexec/arch/ppc/kexec-elf-ppc.c
+++ b/kexec/arch/ppc/kexec-elf-ppc.c
@@ -32,7 +32,6 @@
 
 static const int probe_debug = 0;
 
-unsigned long long initrd_base, initrd_size;
 unsigned char reuse_initrd;
 const char *ramdisk;
 int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
index c073f56..d7afad6 100644
--- a/kexec/arch/ppc/kexec-ppc.c
+++ b/kexec/arch/ppc/kexec-ppc.c
@@ -28,6 +28,8 @@
 
 uint64_t rmo_top;
 unsigned long long crash_base, crash_size;
+unsigned long long initrd_base, initrd_size;
+unsigned long long devicetree_base, devicetree_size;
 unsigned int rtas_base, rtas_size;
 int max_memory_ranges;
 
@@ -320,9 +322,7 @@ static int get_devtree_details(unsigned long kexec_flags)
 	DIR *dir, *cdir;
 	FILE *file;
 	struct dirent *dentry;
-	struct stat fstat;
 	int n, i = 0;
-	unsigned long tmp_long;
 
 	if ((dir = opendir(device_tree)) == NULL) {
 		perror(device_tree);
@@ -352,12 +352,18 @@ static int get_devtree_details(unsigned long kexec_flags)
 					perror(fname);
 					goto error_opencdir;
 				}
-				if (fread(&tmp_long, sizeof(unsigned long), 1, file)
-						!= 1) {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
 					perror(fname);
 					goto error_openfile;
 				}
-				kernel_end = tmp_long;
+				if (n == 4) {
+					kernel_end = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					kernel_end = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
 				fclose(file);
 
 				/* Add kernel memory to exclude_range */
@@ -375,12 +381,18 @@ static int get_devtree_details(unsigned long kexec_flags)
 					perror(fname);
 					goto error_opencdir;
 				}
-				if (fread(&tmp_long, sizeof(unsigned long), 1,
-						file) != 1) {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
 					perror(fname);
 					goto error_openfile;
 				}
-				crash_base = tmp_long;
+				if (n == 4) {
+					crash_base = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					crash_base = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
 				fclose(file);
 
 				memset(fname, 0, sizeof(fname));
@@ -392,12 +404,19 @@ static int get_devtree_details(unsigned long kexec_flags)
 					perror(fname);
 					goto error_opencdir;
 				}
-				if (fread(&tmp_long, sizeof(unsigned long), 1,
-						file) != 1) {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
 					perror(fname);
 					goto error_openfile;
 				}
-				crash_size = tmp_long;
+				if (n == 4) {
+					crash_size = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					crash_size = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
+				fclose(file);
 
 				if (crash_base > mem_min)
 					mem_min = crash_base;
@@ -408,6 +427,123 @@ static int get_devtree_details(unsigned long kexec_flags)
 				reserve(KDUMP_BACKUP_LIMIT,
 						crash_base-KDUMP_BACKUP_LIMIT);
 			}
+			/* reserve the initrd_start and end locations. */
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,initrd-start");
+			file = fopen(fname, "r");
+			if (!file) {
+				errno = 0;
+				initrd_start = 0;
+			} else {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (n == 4) {
+					initrd_start = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					initrd_start = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
+				fclose(file);
+			}
+
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,initrd-end");
+			file = fopen(fname, "r");
+			if (!file) {
+				errno = 0;
+				initrd_end = 0;
+			} else {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (n == 4) {
+					initrd_end = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					initrd_end = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
+				fclose(file);
+			}
+
+			if ((initrd_end - initrd_start) != 0 )
+			{
+				initrd_base = initrd_start;
+				initrd_size = initrd_end - initrd_start + 1;
+			}
+
+			if (reuse_initrd) {
+				/* Add initrd address to exclude_range */
+				exclude_range[i].start = initrd_start;
+				exclude_range[i].end = initrd_end;
+				i++;
+				if (i >= max_memory_ranges)
+					realloc_memory_ranges();
+			}
+
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,devicetree-start");
+			file = fopen(fname, "r");
+			if (!file) {
+				errno = 0;
+				devicetree_base = 0;
+			} else {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (n == 4) {
+					devicetree_base = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					devicetree_base = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
+				fclose(file);
+			}
+
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,devicetree-end");
+			file = fopen(fname, "r");
+			if (!file) {
+				errno = 0;
+				devicetree_size = 0;
+			} else {
+				if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (n == 4) {
+					devicetree_size = ((uint32_t *)buf)[0];
+				} else if (n == 8) {
+					devicetree_size = ((uint64_t *)buf)[0];
+				} else {
+					fprintf(stderr, "%s node has invalid size: %d\n", fname, n);
+					goto error_openfile;
+				}
+				fclose(file);
+			}
+
+			/* Fixup device tree size */
+			if (devicetree_size != 0)
+				devicetree_size -= devicetree_base;
+
+			/* HTAB */
 			memset(fname, 0, sizeof(fname));
 			strcpy(fname, device_tree);
 			strcat(fname, dentry->d_name);
@@ -449,59 +585,7 @@ static int get_devtree_details(unsigned long kexec_flags)
 			if (i >= max_memory_ranges)
 				realloc_memory_ranges();
 
-			/* 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");
-				file = fopen(fname, "r");
-				if (!file) {
-					perror(fname);
-					goto error_opencdir;
-				}
-				/* check for 4 and 8 byte initrd offset sizes */
-				if (stat(fname, &fstat) != 0) {
-					perror(fname);
-					goto error_openfile;
-				}
-				if (fread(&initrd_start, fstat.st_size, 1, file)
-						!= 1) {
-					perror(fname);
-					goto error_openfile;
-				}
-				fclose(file);
-
-				memset(fname, 0, sizeof(fname));
-				strcpy(fname, device_tree);
-				strcat(fname, dentry->d_name);
-				strcat(fname, "/linux,initrd-end");
-				file = fopen(fname, "r");
-				if (!file) {
-					perror(fname);
-					goto error_opencdir;
-				}
-				/* check for 4 and 8 byte initrd offset sizes */
-				if (stat(fname, &fstat) != 0) {
-					perror(fname);
-					goto error_openfile;
-				}
-				if (fread(&initrd_end, fstat.st_size, 1, file)
-						!= 1) {
-					perror(fname);
-					goto error_openfile;
-				}
-				fclose(file);
-
-				/* Add initrd address to exclude_range */
-				exclude_range[i].start = initrd_start;
-				exclude_range[i].end = initrd_end;
-				i++;
-				if (i >= max_memory_ranges)
-					realloc_memory_ranges();
-			}
 		} /* chosen */
-
 		if (strncmp(dentry->d_name, "rtas", 4) == 0) {
 			strcat(fname, "/linux,rtas-base");
 			if ((file = fopen(fname, "r")) == NULL) {
diff --git a/kexec/arch/ppc/kexec-ppc.h b/kexec/arch/ppc/kexec-ppc.h
index fc0471f..aefdc6f 100644
--- a/kexec/arch/ppc/kexec-ppc.h
+++ b/kexec/arch/ppc/kexec-ppc.h
@@ -65,6 +65,7 @@ typedef struct mem_rgns {
 extern mem_rgns_t usablemem_rgns;
 extern int max_memory_ranges;
 extern unsigned long long initrd_base, initrd_size;
+extern unsigned long long devicetree_base, devicetree_size;
 extern unsigned char reuse_initrd;
 #define COMMAND_LINE_SIZE	512 /* from kernel */
 /*fs2dt*/
-- 
1.6.0.6





More information about the kexec mailing list