Remove support for creating dtb from /proc/device-tree

* It never actually worked, and crashes on m8
This commit is contained in:
Vojtech Bocek
2015-06-02 02:19:03 +02:00
parent da2f043f33
commit 95ebaf9af1
7 changed files with 63 additions and 910 deletions

View File

@@ -45,11 +45,10 @@ LOCAL_SRC_FILES := kexec/kexec.c kexec/ifdown.c \
kexec/arch/arm/kexec-arm.c \
kexec/arch/arm/mach.c \
kexec/arch/arm/mach-hammerhead.c \
kexec/arch/arm/mach-m8.c \
kexec/arch/arm/mach-m8.c \
kexec/arch/arm/mach-shamu.c \
kexec/arch/arm/crashdump-arm.c \
kexec/kexec-uImage.c kexec/purgatory.c \
kexec/fs2dt.c \
kexec/libfdt/fdt.c kexec/libfdt/fdt_ro.c \
kexec/libfdt/fdt_rw.c kexec/libfdt/fdt_strerror.c \
kexec/libfdt/fdt_sw.c kexec/libfdt/fdt_wip.c

View File

@@ -21,7 +21,6 @@
#include "../../kexec.h"
#include "../../kexec-syscall.h"
#include "crashdump-arm.h"
#include "../../fs2dt.h"
#include "mach.h"
off_t initrd_base = 0, initrd_size = 0;
@@ -510,6 +509,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
off_t dtb_img_len = 0;
int free_dtb_img = 0;
int choose_res = 0;
int ret, off;
if(!mach)
{
@@ -538,85 +538,78 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
if(free_dtb_img)
free(dtb_img);
if(choose_res)
if(!choose_res)
{
int ret, off;
fprintf(stderr, "Failed to load DTB!\n");
return -1;
}
dtb_length = fdt_totalsize(dtb_buf) + DTB_PAD_SIZE;
dtb_buf = xrealloc(dtb_buf, dtb_length);
ret = fdt_open_into(dtb_buf, dtb_buf, dtb_length);
if(ret)
die("DTB: fdt_open_into failed");
dtb_length = fdt_totalsize(dtb_buf) + DTB_PAD_SIZE;
dtb_buf = xrealloc(dtb_buf, dtb_length);
ret = fdt_open_into(dtb_buf, dtb_buf, dtb_length);
if(ret)
die("DTB: fdt_open_into failed");
ret = (mach->add_extra_regs)(dtb_buf);
if (ret < 0)
{
fprintf(stderr, "DTB: error while adding mach-specific extra regs\n");
ret = (mach->add_extra_regs)(dtb_buf);
if (ret < 0)
{
fprintf(stderr, "DTB: error while adding mach-specific extra regs\n");
return -1;
}
if (command_line) {
const char *node_name = "/chosen";
const char *prop_name = "bootargs";
/* check if a /choosen subnode already exists */
off = fdt_path_offset(dtb_buf, node_name);
if (off == -FDT_ERR_NOTFOUND)
off = fdt_add_subnode(dtb_buf, off, node_name);
if (off < 0) {
fprintf(stderr, "DTB: Error adding %s node.\n", node_name);
return -1;
}
if (command_line) {
const char *node_name = "/chosen";
const char *prop_name = "bootargs";
/* check if a /choosen subnode already exists */
off = fdt_path_offset(dtb_buf, node_name);
if (off == -FDT_ERR_NOTFOUND)
off = fdt_add_subnode(dtb_buf, off, node_name);
if (off < 0) {
fprintf(stderr, "DTB: Error adding %s node.\n", node_name);
return -1;
}
if (fdt_setprop(dtb_buf, off, prop_name,
command_line, strlen(command_line) + 1) != 0) {
fprintf(stderr, "DTB: Error setting %s/%s property.\n",
node_name, prop_name);
return -1;
}
if (fdt_setprop(dtb_buf, off, prop_name,
command_line, strlen(command_line) + 1) != 0) {
fprintf(stderr, "DTB: Error setting %s/%s property.\n",
node_name, prop_name);
return -1;
}
if(ramdisk)
{
const char *node_name = "/chosen";
uint32_t initrd_start, initrd_end;
/* check if a /choosen subnode already exists */
off = fdt_path_offset(dtb_buf, node_name);
if (off == -FDT_ERR_NOTFOUND)
off = fdt_add_subnode(dtb_buf, off, node_name);
if (off < 0) {
fprintf(stderr, "DTB: Error adding %s node.\n", node_name);
return -1;
}
initrd_start = cpu_to_fdt32(initrd_base);
initrd_end = cpu_to_fdt32(initrd_base + initrd_size);
ret = fdt_setprop(dtb_buf, off, "linux,initrd-start", &initrd_start, sizeof(initrd_start));
if (ret)
die("DTB: Error setting %s/linux,initrd-start property.\n", node_name);
ret = fdt_setprop(dtb_buf, off, "linux,initrd-end", &initrd_end, sizeof(initrd_end));
if (ret)
die("DTB: Error setting %s/linux,initrd-end property.\n", node_name);
}
fdt_pack(dtb_buf);
}
else
if(ramdisk)
{
/*
* Extract the DTB from /proc/device-tree.
*/
printf("DTB: Failed to load dtb from zImage or dtb.img, using /proc/device-tree. This is unlikely to work.\n");
create_flatten_tree(&dtb_buf, &dtb_length, command_line);
const char *node_name = "/chosen";
uint32_t initrd_start, initrd_end;
/* check if a /choosen subnode already exists */
off = fdt_path_offset(dtb_buf, node_name);
if (off == -FDT_ERR_NOTFOUND)
off = fdt_add_subnode(dtb_buf, off, node_name);
if (off < 0) {
fprintf(stderr, "DTB: Error adding %s node.\n", node_name);
return -1;
}
initrd_start = cpu_to_fdt32(initrd_base);
initrd_end = cpu_to_fdt32(initrd_base + initrd_size);
ret = fdt_setprop(dtb_buf, off, "linux,initrd-start", &initrd_start, sizeof(initrd_start));
if (ret)
die("DTB: Error setting %s/linux,initrd-start property.\n", node_name);
ret = fdt_setprop(dtb_buf, off, "linux,initrd-end", &initrd_end, sizeof(initrd_end));
if (ret)
die("DTB: Error setting %s/linux,initrd-end property.\n", node_name);
}
fdt_pack(dtb_buf);
if(ramdisk)
{
add_segment(info, ramdisk_buf, initrd_size, initrd_base,

View File

@@ -3,7 +3,6 @@
#include <libfdt.h>
#include "../../kexec.h"
#include "../../fs2dt.h"
#include "mach.h"
#define INVALID_SOC_REV_ID 0xFFFFFFFF

View File

@@ -3,7 +3,6 @@
#include <libfdt.h>
#include "../../kexec.h"
#include "../../fs2dt.h"
#include "mach.h"
#define INVALID_SOC_REV_ID 0xFFFFFFFF

View File

@@ -4,7 +4,6 @@
#include <dirent.h>
#include "../../kexec.h"
#include "../../fs2dt.h"
#include "mach.h"
#define INVALID_SOC_REV_ID 0xFFFFFFFF

View File

@@ -1,795 +0,0 @@
/*
* 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 32768 /* 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] = { "" };
unsigned char reuse_initrd = 0;
/* 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 = 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 = be32_to_cpu(*data);
else if (!strcmp(name, "linux,tce-base"))
base = be64_to_cpu(*(unsigned long long *) data);
else if (!strcmp(name, "rtas-size") ||
!strcmp(name, "linux,tce-size"))
size = be32_to_cpu(*data);
else if (reuse_initrd && !strcmp(name, "linux,initrd-start"))
{
if (len == 8)
base = be64_to_cpu(*(unsigned long long *) data);
else
base = be32_to_cpu(*data);
}
else if (reuse_initrd && !strcmp(name, "linux,initrd-end"))
{
if (len == 8)
end = be64_to_cpu(*(unsigned long long *) data);
else
end = be32_to_cpu(*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 += (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 ((uint32_t)(~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 && initrd_size && !strcmp(basename,"chosen/")) {
int len = 4;
off_t initrd_start, initrd_end;
initrd_start = cpu_to_be32(initrd_base);
initrd_end = cpu_to_be32(initrd_base + initrd_size);
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_start,len);
dt += (len + 3)/4;
len = 4;
*dt++ = cpu_to_be32(3);
*dt++ = cpu_to_be32(len);
*dt++ = cpu_to_be32(propnum("linux,initrd-end"));
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 result;
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;
}
result = read(fd, buff, statbuf.st_size);
close(fd);
if (result <= 0) {
printf("Unable to read %s, printing from purgatory is diabled\n",
filename);
goto no_debug;
}
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;
}
result = read(fd, buff, statbuf.st_size);
if (result && (!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 = _ALIGN(sizeof(bb[0]), 8);
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 = _ALIGN(len, 4);
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);
}

View File

@@ -1,41 +0,0 @@
#ifndef FS2DT_H
#define FS2DT_H
#include "arch/arm/kexec-arm.h"
#include "arch/arm/crashdump-arm.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 */