[PATCH 1/4] create flat device-tree
R Sharada
sharada at in.ibm.com
Wed Sep 14 22:45:34 EST 2005
This patch adds the functionality to create a flat device-tree from
/proc/device-tree. It also adds support to modify the initrd address within
the flat device-tree.
Signed-off-by: R Sharada <sharada at in.ibm.com>
---
kexec-tools-1.101-sharada/kexec/arch/ppc64/Makefile | 3
kexec-tools-1.101-sharada/kexec/arch/ppc64/fs2dt.c | 340 +++++++++++++++
kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-ppc64.h | 13
3 files changed, 354 insertions(+), 2 deletions(-)
diff -puN kexec/arch/ppc64/Makefile~create_flat_devtree kexec/arch/ppc64/Makefile
--- kexec-tools-1.101/kexec/arch/ppc64/Makefile~create_flat_devtree 2005-09-14 12:56:03.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/Makefile 2005-09-14 12:56:33.000000000 +0530
@@ -2,6 +2,7 @@
# kexec ppc64 (linux booting linux)
#
KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-elf-rel-ppc64.c
-KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zImage-ppc64.c
+KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zImage-ppc64.c
+KEXEC_C_SRCS+= kexec/arch/ppc64/fs2dt.c
KEXEC_S_SRCS+=
diff -puN /dev/null kexec/arch/ppc64/fs2dt.c
--- /dev/null 2005-09-09 01:53:00.469998000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/fs2dt.c 2005-09-14 12:57:10.000000000 +0530
@@ -0,0 +1,340 @@
+/*
+ * fs2dt: creates a flattened device-tree
+ *
+ * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation
+ * Copyright (C) 2005 R Sharada (sharada at 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.
+ */
+
+#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-ppc64.h"
+
+#define MAXPATH 1024 /* max path name length */
+#define NAMESPACE 16384 /* max bytes for property names */
+#define TREEWORDS 65536 /* max 32 bit words for property values */
+#define MEMRESERVE 256 /* max number of reserved memory blocks */
+
+enum {
+ ERR_NONE,
+ ERR_USAGE,
+ ERR_OPENDIR,
+ ERR_READDIR,
+ ERR_STAT,
+ ERR_OPEN,
+ ERR_READ,
+ ERR_RESERVE,
+};
+
+void err(const char *str, int rc)
+{
+ if (errno)
+ perror(str);
+ else
+ fprintf(stderr, "%s: unrecoverable error\n", str);
+ exit(rc);
+}
+
+typedef unsigned dvt;
+struct stat statbuf[1];
+char pathname[MAXPATH], *pathstart;
+char propnames[NAMESPACE];
+dvt dtstruct[TREEWORDS], *dt;
+unsigned long long mem_rsrv[2*MEMRESERVE];
+
+extern unsigned long initrd_base;
+extern unsigned long initrd_size;
+static int initrd_found = 0;
+
+void reserve(unsigned long long where, unsigned long long length)
+{
+ unsigned long long *mr;
+
+ mr = mem_rsrv;
+
+ while(mr[1])
+ mr += 2;
+
+ mr[0] = where;
+ mr[1] = length;
+}
+
+/* look for properties we need to reserve memory space for */
+void checkprop(char *name, dvt *data)
+{
+ static unsigned long long base, size, end;
+
+ if ((data == NULL) && (base || size || end))
+ err((void *)data, ERR_RESERVE);
+ else if (!strcmp(name, "linux,rtas-base"))
+ base = *data;
+ else if (!strcmp(name, "linux,initrd-start")) {
+ if (initrd_base)
+ *(unsigned long long *) data = initrd_base;
+ base = *(unsigned long long *)data;
+ initrd_found = 1;
+ }
+ 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 (!strcmp(name, "linux,initrd-end")) {
+ if (initrd_size) {
+ *(unsigned long long *) data = initrd_base +
+ initrd_size;
+ size = initrd_size;
+ } else
+ end = *(unsigned long long *)data;
+ initrd_found = 1;
+ }
+ if (size && end)
+ err(name, ERR_RESERVE);
+ 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.
+ */
+dvt propnum(const char *name)
+{
+ dvt offset = 0;
+
+ while(propnames[offset])
+ if (strcmp(name, propnames+offset))
+ offset += strlen(propnames+offset)+1;
+ else
+ return offset;
+
+ strcpy(propnames+offset, name);
+
+ return offset;
+}
+
+/* put all properties (files) in the property structure */
+void putprops(char *fn, DIR *dir)
+{
+ struct dirent *dp;
+
+ while ((dp = readdir(dir)) != NULL) {
+ strcpy(fn, dp->d_name);
+
+ if (lstat(pathname, statbuf))
+ err(pathname, ERR_STAT);
+
+ /* skip initrd entries if 2nd kernel does not need them */
+ if (!initrd_base && !strcmp(fn,"linux,initrd-end"))
+ continue;
+
+ if (!initrd_base && !strcmp(fn,"linux,initrd-start"))
+ 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, "htab_base") ||
+ !strcmp(dp->d_name, "htab_size") ||
+ !strcmp(dp->d_name, "kernel_end"))
+ continue;
+
+ if (S_ISREG(statbuf[0].st_mode)) {
+ int fd, len = statbuf[0].st_size;
+
+ *dt++ = 3;
+ *dt++ = len;
+ *dt++ = propnum(fn);
+
+ if ((len >= 8) && ((unsigned long)dt & 0x4))
+ dt++;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd == -1)
+ err(pathname, ERR_OPEN);
+ if (read(fd, dt, len) != len)
+ err(pathname, ERR_READ);
+ close(fd);
+
+ checkprop(fn, dt);
+
+ dt += (len + 3)/4;
+ }
+ }
+ fn[0] = '\0';
+ if(errno == ENOSYS)
+ errno = 0;
+ if (errno)
+ err(pathname, ERR_READDIR);
+ checkprop(pathname, NULL);
+}
+
+/*
+ * put a node (directory) in the property structure. first properties
+ * then children.
+ */
+void putnode(void)
+{
+ DIR *dir;
+ char *dn;
+ struct dirent *dp;
+ char *basename;
+
+ *dt++ = 1;
+ strcpy((void *)dt, *pathstart ? pathstart : "/");
+ while(*dt)
+ dt++;
+ if (dt[-1] & 0xff)
+ dt++;
+
+ dir = opendir(pathname);
+
+ if (!dir)
+ err(pathname, ERR_OPENDIR);
+
+ basename = strrchr(pathname,'/');
+
+ strcat(pathname, "/");
+ dn = pathname + strlen(pathname);
+
+ putprops(dn, dir);
+
+ /* Add initrd entries to the second kernel if first kernel does not
+ * have and second kernel needs.
+ */
+ if (initrd_base && !initrd_found && !strcmp(basename,"/chosen/")) {
+ int len = 8;
+ unsigned long long initrd_end;
+ *dt++ = 3;
+ *dt++ = len;
+ *dt++ = propnum("linux,initrd-start");
+
+ if ((len >= 8) && ((unsigned long)dt & 0x4))
+ dt++;
+
+ memcpy(dt,&initrd_base,len);
+ dt += (len + 3)/4;
+
+ len = 8;
+ *dt++ = 3;
+ *dt++ = len;
+ *dt++ = propnum("linux,initrd-end");
+
+ initrd_end = initrd_base + initrd_size;
+ if ((len >= 8) && ((unsigned long)dt & 0x4))
+ dt++;
+
+ memcpy(dt,&initrd_end,8);
+ dt += (len + 3)/4;
+
+ reserve(initrd_base, initrd_size);
+ }
+
+ rewinddir(dir);
+
+ while ((dp = readdir(dir)) != NULL) {
+ strcpy(dn, dp->d_name);
+
+ if (!strcmp(dn, ".") || !strcmp(dn, ".."))
+ continue;
+
+ if (lstat(pathname, statbuf))
+ err(pathname, ERR_STAT);
+
+ if (S_ISDIR(statbuf[0].st_mode))
+ putnode();
+ }
+ if (errno)
+ err(pathname, ERR_READDIR);
+
+ *dt++ = 2;
+ closedir(dir);
+ dn[-1] = '\0';
+}
+
+struct bootblock bb[1];
+
+int create_flatten_tree(struct kexec_info *info, unsigned char **bufp, unsigned long *sizep)
+{
+ unsigned long len;
+ unsigned long tlen;
+ unsigned char *buf;
+ unsigned long me;
+
+ me = 0;
+
+ strcpy(pathname, "/proc/device-tree/");
+
+ pathstart = pathname + strlen(pathname);
+ dt = dtstruct;
+
+ putnode();
+ *dt++ = 9;
+
+ len = sizeof(bb[0]);
+ len += 7; len &= ~7;
+
+ bb->off_mem_rsvmap = len;
+
+ for (len = 1; mem_rsrv[len]; len += 2)
+ ;
+ len+= 3;
+ len *= sizeof(mem_rsrv[0]);
+
+ bb->off_dt_struct = bb->off_mem_rsvmap + len;
+
+ len = dt - dtstruct;
+ len *= sizeof(dvt);
+ bb->off_dt_strings = bb->off_dt_struct + len;
+
+ len = propnum("");
+ len += 3; len &= ~3;
+ bb->totalsize = bb->off_dt_strings + len;
+
+ bb->magic = 0xd00dfeed;
+ bb->version = 2;
+ bb->last_comp_version = 2;
+
+ reserve(me, bb->totalsize); /* patched later in kexec_load */
+
+ buf = (unsigned char *) realloc(*bufp, *sizep + bb->totalsize);
+ *bufp = buf;
+ memcpy(buf+(*sizep), bb, bb->off_mem_rsvmap);
+ tlen = *sizep + bb->off_mem_rsvmap;
+ memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
+ tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
+ memcpy(buf+tlen, dtstruct, bb->off_dt_strings - bb->off_dt_struct);
+ tlen = tlen + (bb->off_dt_strings - bb->off_dt_struct);
+ memcpy(buf+tlen, propnames, bb->totalsize - bb->off_dt_strings);
+ tlen = tlen + bb->totalsize - bb->off_dt_strings;
+ *sizep = tlen;
+ return 0;
+}
diff -puN kexec/arch/ppc64/kexec-ppc64.h~create_flat_devtree kexec/arch/ppc64/kexec-ppc64.h
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-ppc64.h~create_flat_devtree 2005-09-14 12:56:03.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-ppc64.h 2005-09-14 12:56:33.000000000 +0530
@@ -6,4 +6,15 @@ int elf_ppc64_load(int argc, char **argv
struct kexec_info *info);
void elf_ppc64_usage(void);
-#endif /* KEXEC_PPC_H */
+/* boot block version 2 as defined by the linux kernel */
+struct bootblock {
+ unsigned magic,
+ totalsize,
+ off_dt_struct,
+ off_dt_strings,
+ off_mem_rsvmap,
+ version,
+ last_comp_version,
+ boot_physid;
+};
+#endif /* KEXEC_PPC64_H */
_
More information about the Linuxppc64-dev
mailing list