diff options
-rw-r--r-- | kexec/Makefile | 6 | ||||
-rw-r--r-- | kexec/arch_reuse_initrd.c | 2 | ||||
-rw-r--r-- | kexec/fs2dt.c | 781 | ||||
-rw-r--r-- | kexec/fs2dt.h | 38 | ||||
-rw-r--r-- | kexec/kexec.h | 5 |
5 files changed, 832 insertions, 0 deletions
diff --git a/kexec/Makefile b/kexec/Makefile index dff8da6..8a6138d 100644 --- a/kexec/Makefile +++ b/kexec/Makefile @@ -64,6 +64,10 @@ dist += kexec/kexec-uImage.c $(ARCH)_UIMAGE = KEXEC_SRCS += $($(ARCH)_UIMAGE) +dist += kexec/fs2dt.c kexec/fs2dt.h +$(ARCH)_FS2DT = +KEXEC_SRCS += $($(ARCH)_FS2DT) + include $(srcdir)/kexec/arch/alpha/Makefile include $(srcdir)/kexec/arch/arm/Makefile include $(srcdir)/kexec/arch/i386/Makefile @@ -95,6 +99,8 @@ $(KEXEC): $(KEXEC_OBJS) $(UTIL_LIB) $(KEXEC): CPPFLAGS+=-I$(srcdir)/kexec/arch/$(ARCH)/include +kexec/fs2dt.o: CPPFLAGS+=$($(ARCH)_FS2DT_INCLUDE) + $(KEXEC_MANPAGE): kexec/kexec.8 @$(MKDIR) -p $(MANDIR)/man8 cp $^ $(KEXEC_MANPAGE) diff --git a/kexec/arch_reuse_initrd.c b/kexec/arch_reuse_initrd.c index 477a76d..b92b8d8 100644 --- a/kexec/arch_reuse_initrd.c +++ b/kexec/arch_reuse_initrd.c @@ -1,5 +1,7 @@ #include "kexec.h" +unsigned char reuse_initrd = 0; + void arch_reuse_initrd(void) { die("--reuseinitrd not implemented on this architecture\n"); diff --git a/kexec/fs2dt.c b/kexec/fs2dt.c new file mode 100644 index 0000000..b7eda8f --- /dev/null +++ b/kexec/fs2dt.c @@ -0,0 +1,781 @@ +/* + * fs2dt: creates a flattened device-tree + * + * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation + * Copyright (C) 2005 R Sharada (sharada@in.ibm.com), IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define _GNU_SOURCE + +#include <sys/types.h> +#include <sys/stat.h> + +#include <fcntl.h> +#include <dirent.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include "kexec.h" +#include "fs2dt.h" + +#define MAXPATH 1024 /* max path name length */ +#define NAMESPACE 16384 /* max bytes for property names */ +#define INIT_TREE_WORDS 65536 /* Initial num words for prop values */ +#define MEMRESERVE 256 /* max number of reserved memory blocks */ +#define MEM_RANGE_CHUNK_SZ 2048 /* Initial num dwords for mem ranges */ + +static char pathname[MAXPATH], *pathstart; +static char propnames[NAMESPACE] = { 0 }; +static unsigned *dt_base, *dt; +static unsigned int dt_cur_size; +static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0ULL, 0ULL }; + +static int crash_param = 0; +static char local_cmdline[COMMAND_LINE_SIZE] = { "" }; + +extern unsigned char reuse_initrd; + +/* Used for enabling printing message from purgatory code + * Only has implemented for PPC64 */ +int my_debug; + +/* This provides the behaviour of hte existing ppc64 implementation */ +static void pad_structure_block(size_t len) { +#ifdef NEED_STRUCTURE_BLOCK_EXTRA_PAD + if ((len >= 8) && ((unsigned long)dt & 0x4)) + dt++; +#endif +} + +/* Before we add something to the dt, reserve N words using this. + * If there isn't enough room, it's realloced -- and you don't overflow and + * splat bits of your heap. + */ +static void dt_reserve(unsigned **dt_ptr, unsigned words) +{ + unsigned int sz = INIT_TREE_WORDS; + + if (sz < words) + sz = words; + + if (((*dt_ptr - dt_base) + words) >= dt_cur_size) { + int offset; + unsigned int new_size = dt_cur_size + sz; + unsigned *new_dt = realloc(dt_base, new_size*4); + + if (!new_dt) + die("unrecoverable error: Can't realloc %d bytes for " + "device tree\n", new_size*4); + offset = *dt_ptr - dt_base; + dt_base = new_dt; + dt_cur_size = new_size; + *dt_ptr = cpu_to_be32((unsigned)dt_base + offset); + memset(*dt_ptr, 0, (new_size - offset)*4); + } +} + +void reserve(unsigned long long where, unsigned long long length) +{ + size_t offset; + + for (offset = 0; be64_to_cpu(mem_rsrv[offset + 1]); offset += 2) + ; + + if (offset + 4 >= 2 * MEMRESERVE) + die("unrecoverable error: exhasuted reservation meta data\n"); + + mem_rsrv[offset] = cpu_to_be64(where); + mem_rsrv[offset + 1] = cpu_to_be64(length); + mem_rsrv[offset + 2] = mem_rsrv[offset + 3] = cpu_to_be64(0); +} + +/* look for properties we need to reserve memory space for */ +static void checkprop(char *name, unsigned *data, int len) +{ + static unsigned long long base, size, end; + + if ((data == NULL) && (base || size || end)) + die("unrecoverable error: no property data"); + else if (!strcmp(name, "linux,rtas-base")) + base = *data; + else if (!strcmp(name, "linux,tce-base")) + base = *(unsigned long long *) data; + 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; + } +} + +/* + * return the property index for a property name, creating a new one + * if needed. + */ +static unsigned propnum(const char *name) +{ + unsigned offset = 0; + + while(propnames[offset]) + if (strcmp(name, propnames+offset)) + offset += strlen(propnames+offset)+1; + else + return offset; + + if (NAMESPACE - offset < strlen(name) + 1) + die("unrecoverable error: propnames overrun\n"); + + strcpy(propnames+offset, name); + + return offset; +} + +#ifdef HAVE_DYNAMIC_MEMORY +static void add_dyn_reconf_usable_mem_property__(int fd) +{ + char fname[MAXPATH], *bname; + uint64_t buf[32]; + uint64_t *ranges; + int ranges_size = MEM_RANGE_CHUNK_SZ; + uint64_t base, end, loc_base, loc_end; + size_t i, rngs_cnt, range; + int rlen = 0; + int tmp_indx; + + strcpy(fname, pathname); + bname = strrchr(fname, '/'); + bname[0] = '\0'; + bname = strrchr(fname, '/'); + if (strncmp(bname, "/ibm,dynamic-reconfiguration-memory", 36)) + return; + + if (lseek(fd, 4, SEEK_SET) < 0) + die("unrecoverable error: error seeking in \"%s\": %s\n", + pathname, strerror(errno)); + + ranges = malloc(ranges_size*8); + if (!ranges) + die("unrecoverable error: can't alloc %d bytes for ranges.\n", + ranges_size*8); + + rlen = 0; + for (i = 0; i < num_of_lmbs; i++) { + if (read(fd, buf, 24) < 0) + die("unrecoverable error: error reading \"%s\": %s\n", + pathname, strerror(errno)); + + base = (uint64_t) buf[0]; + end = base + lmb_size; + if (~0ULL - base < end) + die("unrecoverable error: mem property overflow\n"); + + tmp_indx = rlen++; + + rngs_cnt = 0; + for (range = 0; range < usablemem_rgns.size; range++) { + int add = 0; + loc_base = usablemem_rgns.ranges[range].start; + loc_end = usablemem_rgns.ranges[range].end; + if (loc_base >= base && loc_end <= end) { + add = 1; + } else if (base < loc_end && end > loc_base) { + if (loc_base < base) + loc_base = base; + if (loc_end > end) + loc_end = end; + add = 1; + } + + if (add) { + if (rlen >= (ranges_size-2)) { + ranges_size += MEM_RANGE_CHUNK_SZ; + ranges = realloc(ranges, ranges_size*8); + if (!ranges) + die("unrecoverable error: can't" + " realloc %d bytes for" + " ranges.\n", + ranges_size*8); + } + ranges[rlen++] = loc_base; + ranges[rlen++] = loc_end - loc_base; + rngs_cnt++; + } + } + if (rngs_cnt == 0) { + /* We still need to add a counter for every LMB because + * the kernel parsing code is dumb. We just have + * a zero in this case, with no following base/len. + */ + ranges[tmp_indx] = 0; + /* rlen is already just tmp_indx+1 as we didn't write + * anything. Check array size here, as we'll probably + * go on for a while writing zeros now. + */ + if (rlen >= (ranges_size-1)) { + ranges_size += MEM_RANGE_CHUNK_SZ; + ranges = realloc(ranges, ranges_size*8); + if (!ranges) + die("unrecoverable error: can't" + " realloc %d bytes for" + " ranges.\n", + ranges_size*8); + } + } else { + /* Store the count of (base, size) duple */ + ranges[tmp_indx] = rngs_cnt; + } + } + + rlen = rlen * sizeof(uint64_t); + /* + * Add linux,drconf-usable-memory property. + */ + dt_reserve(&dt, 4+((rlen + 3)/4)); + *dt++ = cpu_to_be32(3); + *dt++ = cpu_to_be32(rlen); + *dt++ = cpu_to_be32(propnum("linux,drconf-usable-memory")); + pad_structure_block(rlen); + memcpy(dt, ranges, rlen); + free(ranges); + dt += cpu_to_be32((rlen + 3)/4); +} + +static void add_dyn_reconf_usable_mem_property(struct dirent *dp, int fd) +{ + if (!strcmp(dp->d_name, "ibm,dynamic-memory") && usablemem_rgns.size) + add_dyn_reconf_usable_mem_property__(fd); +} +#else +static void add_dyn_reconf_usable_mem_property(struct dirent *dp, int fd) {} +#endif + +static void add_usable_mem_property(int fd, size_t len) +{ + char fname[MAXPATH], *bname; + uint32_t buf[2]; + uint32_t *ranges; + int ranges_size = MEM_RANGE_CHUNK_SZ; + uint64_t base, end, loc_base, loc_end; + size_t range; + int rlen = 0; + + strcpy(fname, pathname); + bname = strrchr(fname,'/'); + bname[0] = '\0'; + bname = strrchr(fname,'/'); + if (strncmp(bname, "/memory@", 8) && strcmp(bname, "/memory")) + return; + + if (len < sizeof(buf)) + die("unrecoverable error: not enough data for mem property\n"); + + if (lseek(fd, 0, SEEK_SET) < 0) + die("unrecoverable error: error seeking in \"%s\": %s\n", + pathname, strerror(errno)); + if (read(fd, buf, sizeof(buf)) != sizeof(buf)) + die("unrecoverable error: error reading \"%s\": %s\n", + pathname, strerror(errno)); + + if (~0ULL - buf[0] < buf[1]) + die("unrecoverable error: mem property overflow\n"); + base = be32_to_cpu(buf[0]); + end = base + be32_to_cpu(buf[1]); + + ranges = malloc(ranges_size * sizeof(*ranges)); + if (!ranges) + die("unrecoverable error: can't alloc %d bytes for ranges.\n", + ranges_size * sizeof(*ranges)); + + for (range = 0; range < usablemem_rgns.size; range++) { + int add = 0; + loc_base = usablemem_rgns.ranges[range].start; + loc_end = usablemem_rgns.ranges[range].end; + if (loc_base >= base && loc_end <= end) { + add = 1; + } else if (base < loc_end && end > loc_base) { + if (loc_base < base) + loc_base = base; + if (loc_end > end) + loc_end = end; + add = 1; + } + if (add) { + if (rlen >= (ranges_size-2)) { + ranges_size += MEM_RANGE_CHUNK_SZ; + ranges = realloc(ranges, ranges_size * + sizeof(*ranges)); + if (!ranges) + die("unrecoverable error: can't realloc" + "%d bytes for ranges.\n", + ranges_size*sizeof(*ranges)); + } + ranges[rlen++] = loc_base; + ranges[rlen++] = loc_end - loc_base; + } + } + + if (!rlen) { + /* + * User did not pass any ranges for thsi region. Hence, write + * (0,0) duple in linux,usable-memory property such that + * this region will be ignored. + */ + ranges[rlen++] = 0; + ranges[rlen++] = 0; + } + + rlen = rlen * sizeof(*ranges); + /* + * No add linux,usable-memory property. + */ + dt_reserve(&dt, 4+((rlen + 3)/4)); + *dt++ = cpu_to_be32(3); + *dt++ = cpu_to_be32(rlen); + *dt++ = cpu_to_be32(propnum("linux,usable-memory")); + pad_structure_block(rlen); + memcpy(dt, ranges, rlen); + free(ranges); + dt += (rlen + 3)/4; +} + +/* put all properties (files) in the property structure */ +static void putprops(char *fn, struct dirent **nlist, int numlist) +{ + struct dirent *dp; + int i = 0, fd; + size_t len; + ssize_t slen; + struct stat statbuf; + + for (i = 0; i < numlist; i++) { + dp = nlist[i]; + strcpy(fn, dp->d_name); + + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + + /* Empirically, this seems to need to be ecluded. + * Observed on ARM with 3.6-rc2 kernel + */ + if (!strcmp(dp->d_name, "name")) + continue; + + if (lstat(pathname, &statbuf)) + die("unrecoverable error: could not stat \"%s\": %s\n", + pathname, strerror(errno)); + + if (!crash_param && !strcmp(fn,"linux,crashkernel-base")) + continue; + + if (!crash_param && !strcmp(fn,"linux,crashkernel-size")) + continue; + + /* + * This property will be created for each node during kexec + * boot. So, ignore it. + */ + if (!strcmp(dp->d_name, "linux,pci-domain") || + !strcmp(dp->d_name, "linux,htab-base") || + !strcmp(dp->d_name, "linux,htab-size") || + !strcmp(dp->d_name, "linux,kernel-end")) + continue; + + /* This property will be created/modified later in putnode() + * So ignore it, unless we are reusing the initrd. + */ + if ((!strcmp(dp->d_name, "linux,initrd-start") || + !strcmp(dp->d_name, "linux,initrd-end")) && + !reuse_initrd) + continue; + + /* This property will be created later in putnode() So + * ignore it now. + */ + if (!strcmp(dp->d_name, "bootargs")) + continue; + + if (! S_ISREG(statbuf.st_mode)) + continue; + + len = statbuf.st_size; + + dt_reserve(&dt, 4+((len + 3)/4)); + *dt++ = cpu_to_be32(3); + *dt++ = cpu_to_be32(len); + *dt++ = cpu_to_be32(propnum(fn)); + pad_structure_block(len); + + fd = open(pathname, O_RDONLY); + if (fd == -1) + die("unrecoverable error: could not open \"%s\": %s\n", + pathname, strerror(errno)); + + slen = read(fd, dt, len); + if (slen < 0) + die("unrecoverable error: could not read \"%s\": %s\n", + pathname, strerror(errno)); + if ((size_t)slen != len) + die("unrecoverable error: short read from\"%s\"\n", + pathname); + + checkprop(fn, dt, len); + + dt += (len + 3)/4; + + if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size) + add_usable_mem_property(fd, len); + add_dyn_reconf_usable_mem_property(dp, fd); + close(fd); + } + + fn[0] = '\0'; + checkprop(pathname, NULL, 0); +} + +/* + * Compare function used to sort the device-tree directories + * This function will be passed to scandir. + */ +static int comparefunc(const struct dirent **dentry1, + const struct dirent **dentry2) +{ + char *str1 = (*(struct dirent **)dentry1)->d_name; + char *str2 = (*(struct dirent **)dentry2)->d_name; + + /* + * strcmp scans from left to right and fails to idetify for some + * strings such as memory@10000000 and memory@f000000. + * Therefore, we get the wrong sorted order like memory@10000000 and + * memory@f000000. + */ + if (strchr(str1, '@') && strchr(str2, '@') && + (strlen(str1) > strlen(str2))) + return 1; + + return strcmp(str1, str2); +} + +/* + * put a node (directory) in the property structure. first properties + * then children. + */ +static void putnode(void) +{ + char *dn; + struct dirent *dp; + char *basename; + struct dirent **namelist; + int numlist, i; + struct stat statbuf; + int plen; + + numlist = scandir(pathname, &namelist, 0, comparefunc); + if (numlist < 0) + die("unrecoverable error: could not scan \"%s\": %s\n", + pathname, strerror(errno)); + if (numlist == 0) + die("unrecoverable error: no directory entries in \"%s\"", + pathname); + + basename = strrchr(pathname,'/') + 1; + + plen = *basename ? strlen(basename) : 0; + /* Reserve space for string packed to words; e.g. string length 10 + * occupies 3 words, length 12 occupies 4 (for terminating \0s). + * So round up & include the \0: + */ + dt_reserve(&dt, 1+((plen + 4)/4)); + *dt++ = cpu_to_be32(1); + strcpy((void *)dt, *basename ? basename : ""); + dt += ((plen + 4)/4); + + strcat(pathname, "/"); + dn = pathname + strlen(pathname); + + putprops(dn, namelist, numlist); + + /* Add initrd entries to the second kernel */ + if (initrd_base && !strcmp(basename,"/chosen/")) { + int len = 8; + unsigned long long initrd_end; + + dt_reserve(&dt, 12); /* both props, of 6 words ea. */ + *dt++ = cpu_to_be32(3); + *dt++ = cpu_to_be32(len); + *dt++ = cpu_to_be32(propnum("linux,initrd-start")); + pad_structure_block(len); + + memcpy(dt,&initrd_base,len); + dt += (len + 3)/4; + + len = 8; + *dt++ = cpu_to_be32(3); + *dt++ = cpu_to_be32(len); + *dt++ = cpu_to_be32(propnum("linux,initrd-end")); + + initrd_end = initrd_base + initrd_size; + pad_structure_block(len); + + memcpy(dt,&initrd_end,len); + dt += (len + 3)/4; + + reserve(initrd_base, initrd_size); + } + + /* Add cmdline to the second kernel. Check to see if the new + * cmdline has a root=. If not, use the old root= cmdline. */ + if (!strcmp(basename,"/chosen/")) { + size_t cmd_len = 0; + char *param = NULL; + char filename[MAXPATH]; + char *buff; + int fd; + + cmd_len = strlen(local_cmdline); + if (cmd_len != 0) { + param = strstr(local_cmdline, "crashkernel="); + if (param) + crash_param = 1; + /* does the new cmdline have a root= ? ... */ + param = strstr(local_cmdline, "root="); + } + + /* ... if not, grab root= from the old command line */ + if (!param) { + FILE *fp; + char *last_cmdline = NULL; + char *old_param; + + strcpy(filename, pathname); + strcat(filename, "bootargs"); + fp = fopen(filename, "r"); + if (fp) { + if (getline(&last_cmdline, &cmd_len, fp) == -1) + die("unable to read %s\n", filename); + + param = strstr(last_cmdline, "root="); + if (param) { + old_param = strtok(param, " "); + if (cmd_len != 0) + strcat(local_cmdline, " "); + strcat(local_cmdline, old_param); + } + } + if (last_cmdline) + free(last_cmdline); + } + strcat(local_cmdline, " "); + cmd_len = strlen(local_cmdline); + cmd_len = cmd_len + 1; + + /* add new bootargs */ + dt_reserve(&dt, 4+((cmd_len+3)/4)); + *dt++ = cpu_to_be32(3); + *dt++ = cpu_to_be32(cmd_len); + *dt++ = cpu_to_be32(propnum("bootargs")); + pad_structure_block(cmd_len); + memcpy(dt, local_cmdline,cmd_len); + dt += (cmd_len + 3)/4; + + fprintf(stderr, "Modified cmdline:%s\n", local_cmdline); + + /* + * Determine the platform type/stdout type, so that purgatory + * code can print 'I'm in purgatory' message. Currently only + * pseries/hvcterminal is supported. + */ + strcpy(filename, pathname); + strncat(filename, "linux,stdout-path", MAXPATH); + fd = open(filename, O_RDONLY); + if (fd == -1) { + printf("Unable to find %s, printing from purgatory is diabled\n", + filename); + goto no_debug; + } + if (fstat(fd, &statbuf)) { + printf("Unable to stat %s, printing from purgatory is diabled\n", + filename); + close(fd); + goto no_debug; + + } + + buff = malloc(statbuf.st_size); + if (!buff) { + printf("Can not allocate memory for buff\n"); + close(fd); + goto no_debug; + } + read(fd, buff, statbuf.st_size); + close(fd); + strncpy(filename, "/proc/device-tree/", MAXPATH); + strncat(filename, buff, MAXPATH); + strncat(filename, "/compatible", MAXPATH); + fd = open(filename, O_RDONLY); + if (fd == -1) { + printf("Unable to find %s printing from purgatory is diabled\n", + filename); + goto no_debug; + } + if (fstat(fd, &statbuf)) { + printf("Unable to stat %s printing from purgatory is diabled\n", + filename); + close(fd); + goto no_debug; + } + buff = realloc(buff, statbuf.st_size); + if (!buff) { + printf("Can not allocate memory for buff\n"); + close(fd); + goto no_debug; + } + read(fd, buff, statbuf.st_size); + if (!strcmp(buff, "hvterm1") || !strcmp(buff, "hvterm-protocol")) + my_debug = 1; + close(fd); + free(buff); + } + +no_debug: + for (i=0; i < numlist; i++) { + dp = namelist[i]; + strcpy(dn, dp->d_name); + free(namelist[i]); + + if (!strcmp(dn, ".") || !strcmp(dn, "..")) + continue; + + if (lstat(pathname, &statbuf)) + die("unrecoverable error: could not stat \"%s\": %s\n", + pathname, strerror(errno)); + + if (S_ISDIR(statbuf.st_mode)) + putnode(); + } + + dt_reserve(&dt, 1); + *dt++ = cpu_to_be32(2); + dn[-1] = '\0'; + free(namelist); +} + +struct bootblock bb[1]; + +static void add_boot_block(char **bufp, off_t *sizep) +{ + unsigned long len; + unsigned long tlen, toff; + char *buf; + + len = sizeof(bb[0]); + len += 7; len &= ~7; + + bb->off_mem_rsvmap = cpu_to_be32(len); + + for (len = 1; be64_to_cpu(mem_rsrv[len]); len += 2) + ; + len++; +#ifdef NEED_RESERVE_DTB + len+= 3; /* Leave space for totalsize reservation */ +#endif + len *= sizeof(mem_rsrv[0]); + + bb->off_dt_struct = cpu_to_be32(be32_to_cpu(bb->off_mem_rsvmap) + len); + + len = dt - dt_base; + len *= sizeof(unsigned); +#if (BOOT_BLOCK_VERSION >= 17) + bb->dt_struct_size = cpu_to_be32(len); +#endif + bb->off_dt_strings = cpu_to_be32(be32_to_cpu(bb->off_dt_struct) + len); + + len = propnum(""); + bb->dt_strings_size = cpu_to_be32(len); + len += 3; len &= ~3; + bb->totalsize = cpu_to_be32(be32_to_cpu(bb->off_dt_strings) + len); + + bb->magic = cpu_to_be32(0xd00dfeed); + bb->version = cpu_to_be32(BOOT_BLOCK_VERSION); + bb->last_comp_version = cpu_to_be32(BOOT_BLOCK_LAST_COMP_VERSION); + +#ifdef NEED_RESERVE_DTB + reserve(0, be32_to_cpu(bb->totalsize)); /* patched later in kexec_load */ +#endif + + buf = malloc(be32_to_cpu(bb->totalsize)); + *bufp = buf; + + tlen = be32_to_cpu(bb->off_mem_rsvmap); + memcpy(buf, bb, tlen); + + toff = be32_to_cpu(bb->off_mem_rsvmap); + tlen = be32_to_cpu(bb->off_dt_struct) - be32_to_cpu(bb->off_mem_rsvmap); + memcpy(buf + toff, mem_rsrv, tlen); + + toff += be32_to_cpu(bb->off_dt_struct) - be32_to_cpu(bb->off_mem_rsvmap); + tlen = be32_to_cpu(bb->off_dt_strings) - be32_to_cpu(bb->off_dt_struct); + memcpy(buf + toff, dt_base, tlen); + + toff += be32_to_cpu(bb->off_dt_strings) - be32_to_cpu(bb->off_dt_struct); + tlen = be32_to_cpu(bb->totalsize) - be32_to_cpu(bb->off_dt_strings); + memcpy(buf + toff, propnames, tlen); + + *sizep = toff + be32_to_cpu(bb->totalsize) - + be32_to_cpu(bb->off_dt_strings); +} + +void create_flatten_tree(char **bufp, off_t *sizep, const char *cmdline) +{ + strcpy(pathname, "/proc/device-tree/"); + + pathstart = pathname + strlen(pathname); + + dt_cur_size = INIT_TREE_WORDS; + dt_base = malloc(dt_cur_size*4); + if (!dt_base) { + die("Can't malloc %d bytes for dt struct!\n", dt_cur_size*4); + } + memset(dt_base, 0, dt_cur_size*4); + + dt = dt_base; + + if (cmdline) + strcpy(local_cmdline, cmdline); + + putnode(); + dt_reserve(&dt, 1); + *dt++ = cpu_to_be32(9); + + add_boot_block(bufp, sizep); + free(dt_base); +} diff --git a/kexec/fs2dt.h b/kexec/fs2dt.h new file mode 100644 index 0000000..6c5c3b2 --- /dev/null +++ b/kexec/fs2dt.h @@ -0,0 +1,38 @@ +#ifndef FS2DT_H +#define FS2DT_H + +#if (BOOT_BLOCK_VERSION != 2 && BOOT_BLOCK_VERSION != 17) +#error Please add or correct definition of BOOT_BLOCK_VERSION +#endif + +/* boot block as defined by the linux kernel */ +struct bootblock { + unsigned magic; + unsigned totalsize; + unsigned off_dt_struct; + unsigned off_dt_strings; + unsigned off_mem_rsvmap; + unsigned version; + unsigned last_comp_version; +#if (BOOT_BLOCK_VERSION >= 2) + /* version 2 fields below */ + unsigned boot_physid; + /* version 3 fields below */ + unsigned dt_strings_size; +#if (BOOT_BLOCK_VERSION >= 17) + /* version 17 fields below */ + unsigned dt_struct_size; +#endif +#endif +}; + +extern struct bootblock bb[1]; + +/* Used for enabling printing message from purgatory code + * Only has implemented for PPC64 */ +int my_debug; + +void reserve(unsigned long long where, unsigned long long length); +void create_flatten_tree(char **, off_t *, const char *); + +#endif /* KEXEC_H */ diff --git a/kexec/kexec.h b/kexec/kexec.h index d24b3fa..1f46bcb 100644 --- a/kexec/kexec.h +++ b/kexec/kexec.h @@ -126,6 +126,11 @@ struct memory_range { #define RANGE_UNCACHED 4 }; +struct memory_ranges { + unsigned int size; + struct memory_range *ranges; +}; + struct kexec_info { struct kexec_segment *segment; int nr_segments; |