summaryrefslogtreecommitdiff
path: root/kexec/arch/ppc/kexec-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/ppc/kexec-ppc.c')
-rw-r--r--kexec/arch/ppc/kexec-ppc.c158
1 files changed, 114 insertions, 44 deletions
diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
index db00b96..4e3569f 100644
--- a/kexec/arch/ppc/kexec-ppc.c
+++ b/kexec/arch/ppc/kexec-ppc.c
@@ -16,6 +16,7 @@
#include <dirent.h>
#include <stdlib.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
#include "../../kexec.h"
@@ -26,6 +27,7 @@
#include "config.h"
+unsigned long dt_address_cells = 0, dt_size_cells = 0;
uint64_t rmo_top;
unsigned long long crash_base = 0, crash_size = 0;
unsigned long long initrd_base = 0, initrd_size = 0;
@@ -34,6 +36,98 @@ unsigned int rtas_base, rtas_size;
int max_memory_ranges;
const char *ramdisk;
+/*
+ * Reads the #address-cells and #size-cells on this platform.
+ * This is used to parse the memory/reg info from the device-tree
+ */
+int init_memory_region_info()
+{
+ size_t res = 0;
+ int fd;
+ char *file;
+
+ file = "/proc/device-tree/#address-cells";
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s\n", file);
+ return -1;
+ }
+
+ res = read(fd, &dt_address_cells, sizeof(dt_address_cells));
+ if (res != sizeof(dt_address_cells)) {
+ fprintf(stderr, "Error reading %s\n", file);
+ return -1;
+ }
+ close(fd);
+
+ file = "/proc/device-tree/#size-cells";
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s\n", file);
+ return -1;
+ }
+
+ res = read(fd, &dt_size_cells, sizeof(dt_size_cells));
+ if (res != sizeof(dt_size_cells)) {
+ fprintf(stderr, "Error reading %s\n", file);
+ return -1;
+ }
+ close(fd);
+
+ /* Convert the sizes into bytes */
+ dt_size_cells *= sizeof(unsigned long);
+ dt_address_cells *= sizeof(unsigned long);
+
+ return 0;
+}
+
+#define MAXBYTES 128
+/*
+ * Reads the memory region info from the device-tree node pointed
+ * by @fd and fills the *start, *end with the boundaries of the region
+ */
+int read_memory_region_limits(int fd, unsigned long long *start,
+ unsigned long long *end)
+{
+ char buf[MAXBYTES];
+ unsigned long *p;
+ unsigned long nbytes = dt_address_cells + dt_size_cells;
+
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ fprintf(stderr, "Error in file seek\n");
+ return -1;
+ }
+ if (read(fd, buf, nbytes) != nbytes) {
+ fprintf(stderr, "Error reading the memory region info\n");
+ return -1;
+ }
+
+ p = (unsigned long*)buf;
+ if (dt_address_cells == sizeof(unsigned long)) {
+ *start = p[0];
+ p++;
+ } else if (dt_address_cells == sizeof(unsigned long long)) {
+ *start = ((unsigned long long *)p)[0];
+ p = (unsigned long long *)p + 1;
+ } else {
+ fprintf(stderr, "Unsupported value for #address-cells : %ld\n",
+ dt_address_cells);
+ return -1;
+ }
+
+ if (dt_size_cells == sizeof(unsigned long))
+ *end = *start + p[0];
+ else if (dt_size_cells == sizeof(unsigned long long))
+ *end = *start + ((unsigned long long *)p)[0];
+ else {
+ fprintf(stderr, "Unsupported value for #size-cells : %ld\n",
+ dt_size_cells);
+ return -1;
+ }
+
+ return 0;
+}
+
void arch_reuse_initrd(void)
{
reuse_initrd = 1;
@@ -182,9 +276,6 @@ static int sort_base_ranges(void)
return 0;
}
-
-#define MAXBYTES 128
-
static int realloc_memory_ranges(void)
{
size_t memory_range_len;
@@ -228,9 +319,8 @@ static int get_base_ranges(void)
char fname[256];
char buf[MAXBYTES];
DIR *dir, *dmem;
- FILE *file;
struct dirent *dentry, *mentry;
- int n;
+ int n, fd;
if ((dir = opendir(device_tree)) == NULL) {
perror(device_tree);
@@ -248,54 +338,39 @@ static int get_base_ranges(void)
return -1;
}
while ((mentry = readdir(dmem)) != NULL) {
+ unsigned long long start, end;
+
if (strcmp(mentry->d_name, "reg"))
continue;
strcat(fname, "/reg");
- if ((file = fopen(fname, "r")) == NULL) {
+ if ((fd = open(fname, O_RDONLY)) < 0) {
perror(fname);
closedir(dmem);
closedir(dir);
return -1;
}
- if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
- perror(fname);
- fclose(file);
+ if (read_memory_region_limits(fd, &start, &end) != 0) {
+ close(fd);
closedir(dmem);
closedir(dir);
return -1;
}
if (local_memory_ranges >= max_memory_ranges) {
if (realloc_memory_ranges() < 0){
- fclose(file);
+ close(fd);
break;
}
}
- if (n == sizeof(uint32_t) * 2) {
- base_memory_range[local_memory_ranges].start =
- ((uint32_t *)buf)[0];
- base_memory_range[local_memory_ranges].end =
- base_memory_range[local_memory_ranges].start +
- ((uint32_t *)buf)[1];
- }
- else if (n == sizeof(uint64_t) * 2) {
- base_memory_range[local_memory_ranges].start =
- ((uint64_t *)buf)[0];
- base_memory_range[local_memory_ranges].end =
- base_memory_range[local_memory_ranges].start +
- ((uint64_t *)buf)[1];
- }
- else {
- fprintf(stderr, "Mem node has invalid size: %d\n", n);
- return -1;
- }
+ base_memory_range[local_memory_ranges].start = start;
+ base_memory_range[local_memory_ranges].end = end;
base_memory_range[local_memory_ranges].type = RANGE_RAM;
local_memory_ranges++;
dbgprintf("%016llx-%016llx : %x\n",
base_memory_range[local_memory_ranges-1].start,
base_memory_range[local_memory_ranges-1].end,
base_memory_range[local_memory_ranges-1].type);
- fclose(file);
+ close(fd);
}
closedir(dmem);
}
@@ -572,29 +647,19 @@ static int get_devtree_details(unsigned long kexec_flags)
if (!strncmp(dentry->d_name, "memory@", 7) ||
!strcmp(dentry->d_name, "memory")) {
+ int fd;
strcat(fname, "/reg");
- if ((file = fopen(fname, "r")) == NULL) {
+ if ((fd = open(fname, O_RDONLY)) < 0) {
perror(fname);
goto error_opencdir;
}
- if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
- perror(fname);
- goto error_openfile;
- }
- if (n == sizeof(uint64_t)) {
- rmo_base = ((uint32_t *)buf)[0];
- rmo_top = rmo_base + ((uint32_t *)buf)[1];
- } else if (n == 16) {
- rmo_base = ((uint64_t *)buf)[0];
- rmo_top = rmo_base + ((uint64_t *)buf)[1];
- } else {
- fprintf(stderr, "Mem node has invalid size: %d\n", n);
+ if (read_memory_region_limits(fd, &rmo_base, &rmo_top) != 0)
goto error_openfile;
- }
+
if (rmo_top > 0x30000000UL)
rmo_top = 0x30000000UL;
- fclose(file);
+ close(fd);
closedir(cdir);
} /* memory */
@@ -778,6 +843,11 @@ int get_memory_ranges_dt(struct memory_range **range, int *ranges,
int get_memory_ranges(struct memory_range **range, int *ranges,
unsigned long kexec_flags)
{
+ int res = 0;
+
+ res = init_memory_region_info();
+ if (res != 0)
+ return res;
#ifdef WITH_GAMECUBE
return get_memory_ranges_gc(range, ranges, kexec_flags);
#else