[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [XenPPC] [hack] dynamic device tree generation
I just got dynamic device tree stuff working. I mean, it's full of hacks, but should be enough to get an initrd (which is why I'm posting it). Patch is below (I'm not even going to check it in to xenppc-unstable.hg it's so bad). With it, I get this console output: xen_start_info at c000000003ffc000 magic xen-3.0-powerpc64HV flags 0 shared_info 3fff000, c000000003fff000 store_mfn 3ffe store_evtchn 1 console_mfn 3ffd console_evtchn 2 Hello World I'm Maple Xen-LPAR! <- xen_init_early firmware_features = 0x40000a Using Xen-Maple machine description ... However, despite many many reinstallations of the tools, my output still ceases after about a pageful. strace on xenconsoled reveals: Process 1149 attached - interrupt to quit *** here I hit "enter" in the "xm console" *** select(20, [16 18 19], [], NULL, NULL) = 1 (in [19]) read(19, "\r", 80) = 1 mlock(0xffcfa7c0, 136) = 0 ioctl(5, SNDCTL_DSP_RESET, 0xffcfa760) = 0 munlock(0xffcfa7c0, 136) = 0 ioctl(18, EVIOCGKEYCODE or EVIOCSKEYCODE, 0xffcfa8b8) = 0 select(20, [16 18 19], [], NULL, NULL) = 1 (in [18]) read(18, "\0\0\0\n", 4) = 4 write(18, "\0\0\0\n", 4) = 4 select(20, [16 18 19], [], NULL, NULL Maybe it's not an event channel problem after all, but rather a console selection problem. Anyways. diff -r da6be38bfdb1 tools/libxc/powerpc64/Makefile --- a/tools/libxc/powerpc64/Makefile Tue Aug 08 20:57:09 2006 -0500 +++ b/tools/libxc/powerpc64/Makefile Tue Aug 08 20:57:24 2006 -0500 @@ -1,1 +1,2 @@ GUEST_SRCS-y += powerpc64/xc_linux_build GUEST_SRCS-y += powerpc64/xc_linux_build.c +GUEST_SRCS-y += powerpc64/ft_build.c diff -r da6be38bfdb1 tools/libxc/powerpc64/xc_linux_build.c --- a/tools/libxc/powerpc64/xc_linux_build.c Tue Aug 08 20:57:09 2006 -0500 +++ b/tools/libxc/powerpc64/xc_linux_build.c Tue Aug 08 23:12:20 2006 -0500 @@ -33,9 +33,10 @@ #include <xg_private.h> #include <xenctrl.h> -/* XXX 64M hack */ -#define MEMSIZE (64UL << 20) +#include "ft_build.h" + #define INITRD_ADDR (24UL << 20) +#define DEVTREE_ADDR (16UL << 20) #define ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1))) @@ -92,8 +93,8 @@ static int init_boot_vcpu( int xc_handle, int domid, struct domain_setup_info *dsi, - unsigned long dtb, - unsigned long kaddr) + unsigned long devtree_addr, + unsigned long kern_addr) { vcpu_guest_context_t ctxt; int rc; @@ -102,8 +103,8 @@ static int init_boot_vcpu( ctxt.user_regs.pc = dsi->v_kernentry; ctxt.user_regs.msr = 0; ctxt.user_regs.gprs[1] = 0; /* Linux uses its own stack */ - ctxt.user_regs.gprs[3] = dtb; - ctxt.user_regs.gprs[4] = kaddr; + ctxt.user_regs.gprs[3] = devtree_addr; + ctxt.user_regs.gprs[4] = kern_addr; ctxt.user_regs.gprs[5] = 0; /* There is a buggy kernel that does not zero the "local_paca", so * we must make sure this register is 0 */ @@ -157,30 +158,85 @@ static int install_image( return rc; } -/* XXX be more flexible about placement in memory */ -static int load_dtb( +static int load_devtree( int xc_handle, int domid, - const char *dtb_path, - unsigned long dtb_addr, - struct domain_setup_info *dsi, - xen_pfn_t *page_array) -{ - uint8_t *img; - unsigned long dtb_size; + xen_pfn_t *page_array, + void *devtree, + unsigned long devtree_addr, + unsigned long initrd_base, + unsigned long initrd_len, + start_info_t *si, + unsigned long si_addr) +{ + uint32_t start_info[4] = {0, si_addr, 0, 0x1000}; + struct boot_param_header *header; + uint64_t *prop; + unsigned int devtree_size; + unsigned int proplen; int rc = 0; - img = load_file(dtb_path, &dtb_size); - if (img == NULL) { - rc = -1; - goto out; - } - - DPRINTF("copying device tree to 0x%lx[0x%lx]\n", dtb_addr, dtb_size); - rc = install_image(xc_handle, domid, page_array, img, dtb_addr, dtb_size); - -out: - free(img); + header = devtree; + devtree_size = header->totalsize; + + DPRINTF("adding initrd props\n"); + prop = ft_get_prop(devtree, "/chosen/linux,initrd-start", &proplen); + if ((prop == NULL) || (proplen != sizeof(*prop))) { + DPRINTF("couldn't set linux,initrd-start property\n"); + return -1; + } + *prop = initrd_base; + + prop = ft_get_prop(devtree, "/chosen/linux,initrd-end", &proplen); + if ((prop == NULL) || (proplen != sizeof(*prop))) { + DPRINTF("couldn't set linux,initrd-end property\n"); + return -1; + } + *prop = initrd_base + initrd_len; + +#if 0 + prop = ft_get_prop(devtree, "/xen/console/frameno", &proplen); + if ((prop == NULL) || (proplen != sizeof(*prop))) { + DPRINTF("couldn't set /xen/console/frameno property\n"); + return -1; + } + *prop = si->console_mfn; + + prop = ft_get_prop(devtree, "/xen/console/interrupts", &proplen); + if ((prop == NULL) || (proplen != sizeof(interrupts))) { + DPRINTF("couldn't set /xen/console/interrupts property\n"); + return -1; + } + interrupts[0] = si->console_evtchn; + memcpy(prop, interrupts, proplen); + + prop = ft_get_prop(devtree, "/xen/store/frameno", &proplen); + if ((prop == NULL) || (proplen != sizeof(*prop))) { + DPRINTF("couldn't set /xen/store/frameno property\n"); + return -1; + } + *prop = si->store_mfn; + + prop = ft_get_prop(devtree, "/xen/store/interrupts", &proplen); + if ((prop == NULL) || (proplen != sizeof(interrupts))) { + DPRINTF("couldn't set /xen/store/interrupts property\n"); + return -1; + } + interrupts[0] = si->store_evtchn; + memcpy(prop, interrupts, proplen); +#endif + + prop = ft_get_prop(devtree, "/xen/start-info", &proplen); + if ((prop == NULL) || (proplen != sizeof(start_info))) { + DPRINTF("couldn't set /xen/start-info property\n"); + return -1; + } + memcpy(prop, start_info, proplen); + + DPRINTF("copying device tree to 0x%lx[0x%x]\n", DEVTREE_ADDR, devtree_size); + rc = install_image(xc_handle, domid, page_array, devtree, DEVTREE_ADDR, + devtree_size); + return rc; } @@ -295,49 +351,53 @@ out: } static unsigned long create_start_info(start_info_t *si, - unsigned int console_evtchn, unsigned int store_evtchn) -{ - unsigned long eomem; + unsigned int console_evtchn, unsigned int store_evtchn, + unsigned long nr_pages) +{ unsigned long si_addr; memset(si, 0, sizeof(*si)); snprintf(si->magic, sizeof(si->magic), "xen-%d.%d-powerpc64HV", 3, 0); - eomem = MEMSIZE; - si->nr_pages = eomem >> PAGE_SHIFT; - si->shared_info = eomem - (PAGE_SIZE * 1); + si->nr_pages = nr_pages; + si->shared_info = (nr_pages - 1) << PAGE_SHIFT; si->store_mfn = si->nr_pages - 2; si->store_evtchn = store_evtchn; si->console_mfn = si->nr_pages - 3; si->console_evtchn = console_evtchn; - si_addr = eomem - (PAGE_SIZE * 4); + si_addr = (nr_pages - 4) << PAGE_SHIFT; return si_addr; } -static int get_page_array(int xc_handle, int domid, xen_pfn_t **page_array) -{ - int nr_pages; +static int get_page_array(int xc_handle, int domid, xen_pfn_t **page_array, + unsigned long *nr_pages) +{ int rc; DPRINTF("xc_get_tot_pages\n"); - nr_pages = xc_get_tot_pages(xc_handle, domid); - DPRINTF(" 0x%x\n", nr_pages); - - *page_array = malloc(nr_pages * sizeof(xen_pfn_t)); + *nr_pages = xc_get_tot_pages(xc_handle, domid); + DPRINTF(" 0x%lx\n", *nr_pages); + + *page_array = malloc(*nr_pages * sizeof(xen_pfn_t)); if (*page_array == NULL) { perror("malloc"); return -1; } DPRINTF("xc_get_pfn_list\n"); - rc = xc_get_pfn_list(xc_handle, domid, *page_array, nr_pages); - if (rc != nr_pages) { + rc = xc_get_pfn_list(xc_handle, domid, *page_array, *nr_pages); + if (rc != *nr_pages) { perror("Could not get the page frame list"); return -1; } return 0; +} + +static void free_page_array(xen_pfn_t *page_array) +{ + free(page_array); } @@ -352,57 +412,69 @@ int xc_linux_build(int xc_handle, unsigned int store_evtchn, unsigned long *store_mfn, unsigned int console_evtchn, - unsigned long *console_mfn) -{ + unsigned long *console_mfn, + void *devtree) +{ + start_info_t si; struct domain_setup_info dsi; xen_pfn_t *page_array = NULL; + unsigned long nr_pages; + unsigned long devtree_addr = 0; unsigned long kern_addr; - unsigned long dtb_addr; - unsigned long si_addr; unsigned long initrd_base = 0; unsigned long initrd_len = 0; - start_info_t si; + unsigned long si_addr; int rc = 0; - if (get_page_array(xc_handle, domid, &page_array)) { - rc = -1; - goto out; - } - + DPRINTF("%s\n", __func__); + + if (get_page_array(xc_handle, domid, &page_array, &nr_pages)) { + rc = -1; + goto out; + } + + DPRINTF("loading image '%s'\n", image_name); if (load_kernel(xc_handle, domid, image_name, &dsi, page_array)) { rc = -1; goto out; } kern_addr = 0; - if (initrd_name && initrd_name[0] != '\0' && - load_initrd(xc_handle, domid, page_array, initrd_name, &initrd_base, - &initrd_len)) { - rc = -1; - goto out; - } - /* XXX install initrd addr/len into device tree */ - - dtb_addr = (16 << 20); - if (load_dtb(xc_handle, domid, "/root/DomU.dtb", dtb_addr, &dsi, page_array)) { - dtb_addr = 0; - } - - si_addr = create_start_info(&si, console_evtchn, store_evtchn); + if (initrd_name && initrd_name[0] != '\0') { + DPRINTF("loading initrd '%s'\n", initrd_name); + if (load_initrd(xc_handle, domid, page_array, initrd_name, + &initrd_base, &initrd_len)) { + rc = -1; + goto out; + } + } + + /* start_info stuff: about to be removed */ + si_addr = create_start_info(&si, console_evtchn, store_evtchn, nr_pages); *console_mfn = page_array[si.console_mfn]; *store_mfn = page_array[si.store_mfn]; - if (install_image(xc_handle, domid, page_array, &si, si_addr, sizeof(start_info_t))) { rc = -1; goto out; } - if (init_boot_vcpu(xc_handle, domid, &dsi, dtb_addr, kern_addr)) { + if (devtree) { + DPRINTF("loading flattened device tree\n"); + devtree_addr = DEVTREE_ADDR; + if (load_devtree(xc_handle, domid, page_array, devtree, devtree_addr, + initrd_base, initrd_len, &si, si_addr)) { + DPRINTF("couldn't load flattened device tree.\n"); + devtree_addr = 0; + } + } + + if (init_boot_vcpu(xc_handle, domid, &dsi, devtree_addr, kern_addr)) { rc = -1; goto out; } out: - return rc; -} + free_page_array(page_array); + return rc; +} diff -r da6be38bfdb1 tools/python/xen/lowlevel/xc/xc.c --- a/tools/python/xen/lowlevel/xc/xc.c Tue Aug 08 20:57:09 2006 -0500 +++ b/tools/python/xen/lowlevel/xc/xc.c Tue Aug 08 22:35:01 2006 -0500 @@ -332,6 +332,7 @@ static PyObject *pyxc_linux_build(XcObje unsigned long store_mfn = 0; unsigned long console_mfn = 0; void *arch_args = NULL; + int unused; static char *kwd_list[] = { "dom", "store_evtchn", "console_evtchn", "image", @@ -339,18 +340,19 @@ static PyObject *pyxc_linux_build(XcObje "ramdisk", "cmdline", "flags", "features", "arch_args", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssiss", kwd_list, + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssiss#", kwd_list, &dom, &store_evtchn, &console_evtchn, &image, /* optional */ &ramdisk, &cmdline, &flags, - &features, &arch_args) ) + &features, &arch_args, &unused) ) return NULL; if ( xc_linux_build(self->xc_handle, dom, image, ramdisk, cmdline, features, flags, store_evtchn, &store_mfn, - console_evtchn, &console_mfn, arch_args) != 0 ) { + console_evtchn, &console_mfn, + arch_args) != 0 ) { if (!errno) errno = EINVAL; return PyErr_SetFromErrno(xc_error); diff -r da6be38bfdb1 tools/python/xen/xend/image.py --- a/tools/python/xen/xend/image.py Tue Aug 08 20:57:09 2006 -0500 +++ b/tools/python/xen/xend/image.py Tue Aug 08 23:01:29 2006 -0500 @@ -96,6 +96,70 @@ class ImageHandler: ("image/cmdline", self.cmdline), ("image/ramdisk", self.ramdisk)) + # XXX + import xen.xend.dtc as dtc + root = dtc.Tree() + root.reserve(0x3ffc000, 0x4000) + + root.addprop('device_type', 'chrp-but-not-really\0') + root.addprop('#size-cells', 2) + root.addprop('#address-cells', 2) + root.addprop('model', 'Momentum,Maple-D\0') + root.addprop('compatible', 'Momentum,Maple\0') + + xen = root.addnode('xen') + xen.addprop('start-info', 0, 0, 0, 0) + xen.addprop('version', 'Xen-3.0-unstable\0') + xen.addprop('reg', 0, self.vm.getDomid(), 0, 0) + xen.addprop('domain-name', 'User Domain\0') + xencons = xen.addnode('console') + xencons.addprop('interrupts', 0, 0) + + mem = root.addnode('memory') + mem.addprop('reg', 0, 0, 0, 0x4000000) + mem.addprop('device_type', 'memory\0') + + cpus = root.addnode('cpus') + cpus.addprop('smp-enabled') + cpus.addprop('#size-cells', 0) + cpus.addprop('#address-cells', 1) + + cpu0 = cpus.addnode('PowerPC,970@0') + cpu0.addprop('ibm,pft-size', 0, 0x14) + cpu0.addprop('reg', 0) + cpu0.addprop('cpu#', 0) + cpu0.addprop('device_type', 'cpu\0') + cpu0.addprop('d-cache-size', 0x8000) + cpu0.addprop('d-cache-line-size', 0x80) + cpu0.addprop('d-cache-sets', 0x80) + cpu0.addprop('i-cache-size', 0x10000) + cpu0.addprop('i-cache-line-size', 0x80) + cpu0.addprop('i-cache-sets', 0x200) + cpu0.addprop('clock-frequency', 'SrN\0') + cpu0.addprop('timebase-frequency', 0xa6e49c0) + cpu0.addprop('timebases-in-sync') + + l2 = cpu0.addnode('l2-cache') + l2.addprop('name', 'l2-cache\0') + l2.addprop('device_type', 'cache\0') + l2.addprop('i-cache-size', 0x80000) + l2.addprop('d-cache-size', 0x80000) + l2.addprop('i-cache-sets', 0x200) + l2.addprop('d-cache-sets', 0x200) + l2.addprop('cache-unified') + + chosen = root.addnode('chosen') + chosen.addprop('linux,platform', 0x501) + chosen.addprop('linux,stdout-path', '/xen/console\0') + chosen.addprop('interrupt-controller', xen.get_phandle()) + chosen.addprop('bootargs', '\0') + chosen.addprop('linux,initrd-start', 0, 0) + chosen.addprop('linux,initrd-end', 0, 0) + + self.tree = root.to_bin() + dtc.writebuf("/tmp/domU.dtb", self.tree); + # XXX + def cleanupBootloading(self): self.unlink(self.kernel) @@ -182,6 +246,8 @@ class LinuxImageHandler(ImageHandler): log.debug("ramdisk = %s", self.ramdisk) log.debug("vcpus = %d", self.vm.getVCpuCount()) log.debug("features = %s", self.vm.getFeatures()) + # XXX + log.debug("tree len = %s", len(self.tree)) return xc.linux_build(dom = self.vm.getDomid(), image = self.kernel, @@ -189,7 +255,8 @@ class LinuxImageHandler(ImageHandler): console_evtchn = console_evtchn, cmdline = self.cmdline, ramdisk = self.ramdisk, - features = self.vm.getFeatures()) + features = self.vm.getFeatures(), + arch_args = self.tree) class HVMImageHandler(ImageHandler): diff -r da6be38bfdb1 tools/libxc/powerpc64/ft_build.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/powerpc64/ft_build.c Tue Aug 08 11:22:58 2006 -0500 @@ -0,0 +1,651 @@ +/* + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stddef.h> +#include <string.h> +#include <stdio.h> +#include <asm/errno.h> + +#include "ft_build.h" + +#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) + +static void ft_put_word(struct ft_cxt *cxt, u32 v) +{ + if (cxt->overflow) /* do nothing */ + return; + + /* check for overflow */ + if (cxt->p + 4 > cxt->pstr) { + cxt->overflow = 1; + return; + } + + *(u32 *) cxt->p = cpu_to_be32(v); + cxt->p += 4; +} + +static inline void ft_put_bin(struct ft_cxt *cxt, const void *data, int sz) +{ + char *p; + + if (cxt->overflow) /* do nothing */ + return; + + /* next pointer pos */ + p = (char *) _ALIGN((unsigned long)cxt->p + sz, 4); + + /* check for overflow */ + if (p > cxt->pstr) { + cxt->overflow = 1; + return; + } + + memcpy(cxt->p, data, sz); + if ((sz & 3) != 0) + memset(cxt->p + sz, 0, 4 - (sz & 3)); + cxt->p = p; +} + +void ft_begin_node(struct ft_cxt *cxt, const char *name) +{ + ft_put_word(cxt, OF_DT_BEGIN_NODE); + ft_put_bin(cxt, name, strlen(name) + 1); +} + +void ft_end_node(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_END_NODE); +} + +void ft_nop(struct ft_cxt *cxt) +{ + ft_put_word(cxt, OF_DT_NOP); +} + +static int lookup_string(struct ft_cxt *cxt, const char *name) +{ + char *p; + + p = cxt->pstr; + while (p < cxt->pstr_begin) { + if (strcmp(p, (char *)name) == 0) + return p - cxt->p_begin; + p += strlen(p) + 1; + } + + return -1; +} + +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz) +{ + int len, off; + + if (cxt->overflow) + return; + + len = strlen(name) + 1; + + off = lookup_string(cxt, name); + if (off == -1) { + /* check if we have space */ + if (cxt->p + 12 + sz + len > cxt->pstr) { + cxt->overflow = 1; + return; + } + + cxt->pstr -= len; + memcpy(cxt->pstr, name, len); + off = cxt->pstr - cxt->p_begin; + } + + /* now put offset from beginning of *STRUCTURE* */ + /* will be fixed up at the end */ + ft_put_word(cxt, OF_DT_PROP); + ft_put_word(cxt, sz); + ft_put_word(cxt, off); + ft_put_bin(cxt, data, sz); +} + +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str) +{ + ft_prop(cxt, name, str, strlen(str) + 1); +} + +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val) +{ + u32 v = cpu_to_be32((u32) val); + + ft_prop(cxt, name, &v, 4); +} + +/* start construction of the flat OF tree */ +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size) +{ + struct boot_param_header *bph = blob; + u32 off; + + /* clear the cxt */ + memset(cxt, 0, sizeof(*cxt)); + + cxt->bph = bph; + cxt->max_size = max_size; + + /* zero everything in the header area */ + memset(bph, 0, sizeof(*bph)); + + bph->magic = cpu_to_be32(OF_DT_HEADER); + bph->version = cpu_to_be32(0x10); + bph->last_comp_version = cpu_to_be32(0x10); + + /* start pointers */ + cxt->pres_begin = (char *) _ALIGN((unsigned long)(bph + 1), 8); + cxt->pres = cxt->pres_begin; + + off = (unsigned long)cxt->pres_begin - (unsigned long)bph; + bph->off_mem_rsvmap = cpu_to_be32(off); + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +/* add a reserver physical area to the rsvmap */ +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) +{ + ((u64 *) cxt->pres)[0] = cpu_to_be64(physaddr); /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = cpu_to_be64(size); + + cxt->pres += 18; /* advance */ + + ((u64 *) cxt->pres)[0] = 0; /* phys = 0, size = 0, terminate */ + ((u64 *) cxt->pres)[1] = 0; + + /* keep track of size */ + cxt->res_size = cxt->pres + 16 - cxt->pres_begin; + + cxt->p_anchor = cxt->pres + 16; /* over the terminator */ +} + +void ft_begin_tree(struct ft_cxt *cxt) +{ + cxt->p_begin = cxt->p_anchor; + cxt->pstr_begin = (char *)cxt->bph + cxt->max_size; /* point at the end */ + + cxt->p = cxt->p_begin; + cxt->pstr = cxt->pstr_begin; +} + +int ft_end_tree(struct ft_cxt *cxt) +{ + struct boot_param_header *bph = cxt->bph; + int off, sz, sz1; + u32 tag, v; + char *p; + + ft_put_word(cxt, OF_DT_END); + + if (cxt->overflow) + return -ENOMEM; + + /* size of the areas */ + cxt->struct_size = cxt->p - cxt->p_begin; + cxt->strings_size = cxt->pstr_begin - cxt->pstr; + + /* the offset we must move */ + off = (cxt->pstr_begin - cxt->p_begin) - cxt->strings_size; + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + + /* move the whole string area */ + memmove(cxt->pstr_begin, cxt->pstr, cxt->strings_size); + + /* now perform the fixup of the strings */ + p = cxt->p_begin; + while ((tag = be32_to_cpu(*(u32 *) p)) != OF_DT_END) { + p += 4; + + if (tag == OF_DT_BEGIN_NODE) { + p = (char *) _ALIGN((unsigned long)p + strlen(p) + 1, 4); + continue; + } + + if (tag == OF_DT_END_NODE || tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + return -EINVAL; + + sz = be32_to_cpu(*(u32 *) p); + p += 4; + + v = be32_to_cpu(*(u32 *) p); + v -= off; + *(u32 *) p = cpu_to_be32(v); /* move down */ + p += 4; + + p = (char *) _ALIGN((unsigned long)p + sz, 4); + } + + /* fix sizes */ + p = (char *)cxt->bph; + sz = (cxt->pstr_begin + cxt->strings_size) - p; + sz1 = _ALIGN(sz, 16); /* align at 16 bytes */ + if (sz != sz1) + memset(p + sz, 0, sz1 - sz); + bph->totalsize = cpu_to_be32(sz1); + bph->off_dt_struct = cpu_to_be32(cxt->p_begin - p); + bph->off_dt_strings = cpu_to_be32(cxt->pstr_begin - p); + + /* the new strings start */ + cxt->pstr_begin = cxt->p_begin + cxt->struct_size; + cxt->pstr = cxt->pstr_begin + cxt->strings_size; + + return 0; +} + +/**********************************************************************/ + +static inline int isprint(int c) +{ + return c >= 0x20 && c <= 0x7e; +} + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + ss = s; + while (*s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || (s + 1 - ss) < len) + return 0; + + return 1; +} + +static void print_data(const void *data, int len) +{ + int i; + const char *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (is_printable_string(data, len)) { + printf(" = \"%s\"", (char *)data); + return; + } + + switch (len) { + case 1: /* byte */ + printf(" = <0x%02x>", (*(char *) data) & 0xff); + break; + case 2: /* half-word */ + printf(" = <0x%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); + break; + case 4: /* word */ + printf(" = <0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); + break; + case 8: /* double-word */ + printf(" = <0x%16llx>", be64_to_cpu(*(u64 *) data)); + break; + default: /* anything else... hexdump */ + printf(" = ["); + for (i = 0, s = data; i < len; i++) + printf("%02x%s", s[i], i < len - 1 ? " " : ""); + printf("]"); + + break; + } +} + +void ft_dump_blob(const void *bphp) +{ + const struct boot_param_header *bph = bphp; + const u64 *p_rsvmap = (const u64 *) + ((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap)); + const u32 *p_struct = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_struct)); + const u32 *p_strings = (const u32 *) + ((const char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag; + const u32 *p; + const char *s, *t; + int depth, sz, shift; + int i; + u64 addr, size; + + if (be32_to_cpu(bph->magic) != OF_DT_HEADER) { + /* not valid tree */ + return; + } + + depth = 0; + shift = 4; + + for (i = 0;; i++) { + addr = be64_to_cpu(p_rsvmap[i * 2]); + size = be64_to_cpu(p_rsvmap[i * 2 + 1]); + if (addr == 0 && size == 0) + break; + + printf("/memreserve/ 0x%llx 0x%llx;\n", addr, size); + } + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (const char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == OF_DT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == OF_DT_NOP) { + printf("%*s[NOP]\n", depth * shift, ""); + continue; + } + + if (tag != OF_DT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", + depth * shift, "", tag); + break; + } + sz = be32_to_cpu(*p++); + s = (const char *)p_strings + be32_to_cpu(*p++); + t = (const char *)p; + p = (const u32 *)_ALIGN((unsigned long)p + sz, 4); + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + +void ft_backtrack_node(struct ft_cxt *cxt) +{ + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; +} + +/* note that the root node of the blob is "peeled" off */ +void ft_merge_blob(struct ft_cxt *cxt, void *blob) +{ + struct boot_param_header *bph = (struct boot_param_header *)blob; + u32 *p_struct = (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + u32 *p_strings = + (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 tag, *p; + char *s, *t; + int depth, sz; + + if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) + return; /* XXX only for node */ + + cxt->p -= 4; + + depth = 0; + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + /* printf("tag: 0x%08x (%d) - %d\n", tag, p - p_struct, depth); */ + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); + + if (depth++ > 0) + ft_begin_node(cxt, s); + + continue; + } + + if (tag == OF_DT_END_NODE) { + ft_end_node(cxt); + if (--depth == 0) + break; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + t = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + sz, 4); + + ft_prop(cxt, s, t, sz); + } +} + +void *ft_get_prop(void *bphp, const char *propname, int *szp) +{ + struct boot_param_header *bph = bphp; + u32 *p_struct = + (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); + u32 *p_strings = + (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); + u32 version = be32_to_cpu(bph->version); + u32 tag; + u32 *p; + char *s, *t; + char *ss; + int sz; + static char path[256], prop[256]; + + path[0] = '\0'; + + p = p_struct; + while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { + + if (tag == OF_DT_BEGIN_NODE) { + s = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + + 1, 4); + strcat(path, s); + strcat(path, "/"); + continue; + } + + if (tag == OF_DT_END_NODE) { + path[strlen(path) - 1] = '\0'; + ss = strrchr(path, '/'); + if (ss != NULL) + ss[1] = '\0'; + continue; + } + + if (tag == OF_DT_NOP) + continue; + + if (tag != OF_DT_PROP) + break; + + sz = be32_to_cpu(*p++); + s = (char *)p_strings + be32_to_cpu(*p++); + if (version < 0x10 && sz >= 8) + p = (u32 *) _ALIGN((unsigned long)p, 8); + t = (char *)p; + p = (u32 *) _ALIGN((unsigned long)p + sz, 4); + + strcpy(prop, path); + strcat(prop, s); + + if (strcmp(prop, propname) == 0) { + *szp = sz; + return t; + } + } + + return NULL; +} + +/********************************************************************/ + +#if 0 +extern unsigned char oftree_dtb[]; +extern unsigned int oftree_dtb_len; + +void ft_setup(void *blob, int size, bd_t * bd) +{ + DECLARE_GLOBAL_DATA_PTR; + char *end; + u32 *p; + int len; + struct ft_cxt cxt; + int i, k, nxt; + static char tmpenv[256]; + char *s, *lval, *rval; + ulong clock; + u32 v; + + /* disable OF tree; booting old kernel */ + if (getenv("disable_of") != NULL) { + memcpy(blob, bd, sizeof(*bd)); + return; + } + + ft_begin(&cxt, blob, size); + + /* fs_add_rsvmap not used */ + + ft_begin_tree(&cxt); + + ft_begin_node(&cxt, ""); + + ft_end_node(&cxt); + + /* copy RO tree */ + ft_merge_blob(&cxt, oftree_dtb); + + /* back into root */ + ft_backtrack_node(&cxt); + + ft_begin_node(&cxt, "u-boot-env"); + + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) ; + s = tmpenv; + for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) + *s++ = env_get_char(k); + *s++ = '\0'; + lval = tmpenv; + s = strchr(tmpenv, '='); + if (s != NULL) { + *s++ = '\0'; + rval = s; + } else + continue; + ft_prop_str(&cxt, lval, rval); + } + + ft_end_node(&cxt); + + ft_begin_node(&cxt, "chosen"); + + ft_prop_str(&cxt, "name", "chosen"); + ft_prop_str(&cxt, "bootargs", getenv("bootargs")); + ft_prop_int(&cxt, "linux,platform", 0x600); /* what is this? */ + + ft_end_node(&cxt); + + ft_end_node(&cxt); /* end root */ + + ft_end_tree(&cxt); + + /* + printf("merged OF-tree\n"); + ft_dump_blob(blob); + */ + + /* paste the bd_t at the end of the flat tree */ + end = (char *)blob + + be32_to_cpu(((struct boot_param_header *)blob)->totalsize); + memcpy(end, bd, sizeof(*bd)); + +#ifdef CONFIG_PPC + + for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { + sprintf(tmpenv, "/bd_t/%s", bd_map[i].name); + v = *(u32 *)((char *)bd + bd_map[i].offset); + + p = ft_get_prop(blob, tmpenv, &len); + if (p != NULL) + *p = cpu_to_be32(v); + } + + p = ft_get_prop(blob, "/bd_t/enetaddr", &len); + if (p != NULL) + memcpy(p, bd->bi_enetaddr, 6); + + p = ft_get_prop(blob, "/bd_t/ethspeed", &len); + if (p != NULL) + *p = cpu_to_be32((u32) bd->bi_ethspeed); + + clock = bd->bi_intfreq; + p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(clock); + +#ifdef OF_TBCLK + clock = OF_TBCLK; + p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len); + if (p != NULL) + *p = cpu_to_be32(OF_TBCLK); +#endif + +#endif /* __powerpc__ */ + + /* + printf("final OF-tree\n"); + ft_dump_blob(blob); + */ + +} +#endif diff -r da6be38bfdb1 tools/libxc/powerpc64/ft_build.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/powerpc64/ft_build.h Tue Aug 08 11:22:58 2006 -0500 @@ -0,0 +1,120 @@ +/* + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FT_BUILD_H +#define FT_BUILD_H + +#include <endian.h> + +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +static inline u16 swab16(u16 x) +{ + return (((u16)(x) & (u16)0x00ffU) << 8) | + (((u16)(x) & (u16)0xff00U) >> 8); +} + +static inline u32 swab32(u32 x) +{ + return (((u32)(x) & (u32)0x000000ffUL) << 24) | + (((u32)(x) & (u32)0x0000ff00UL) << 8) | + (((u32)(x) & (u32)0x00ff0000UL) >> 8) | + (((u32)(x) & (u32)0xff000000UL) >> 24); +} + +static inline u64 swab64(u64 x) +{ + return (u64)(((u64)(x) & (u64)0x00000000000000ffULL) << 56) | + (u64)(((u64)(x) & (u64)0x000000000000ff00ULL) << 40) | + (u64)(((u64)(x) & (u64)0x0000000000ff0000ULL) << 24) | + (u64)(((u64)(x) & (u64)0x00000000ff000000ULL) << 8) | + (u64)(((u64)(x) & (u64)0x000000ff00000000ULL) >> 8) | + (u64)(((u64)(x) & (u64)0x0000ff0000000000ULL) >> 24) | + (u64)(((u64)(x) & (u64)0x00ff000000000000ULL) >> 40) | + (u64)(((u64)(x) & (u64)0xff00000000000000ULL) >> 56); +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_be16(x) swab16(x) +#define be16_to_cpu(x) swab16(x) +#define cpu_to_be32(x) swab32(x) +#define be32_to_cpu(x) swab32(x) +#define cpu_to_be64(x) swab64(x) +#define be64_to_cpu(x) swab64(x) +#else +#define cpu_to_be16(x) (x) +#define be16_to_cpu(x) (x) +#define cpu_to_be32(x) (x) +#define be32_to_cpu(x) (x) +#define cpu_to_be64(x) (x) +#define be64_to_cpu(x) (x) +#endif + +/* Definitions used by the flattened device tree */ +#define OF_DT_HEADER 0xd00dfeed /* marker */ +#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, content */ +#define OF_DT_NOP 0x4 /* nop */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 0x10 + +struct boot_param_header { + u32 magic; /* magic word OF_DT_HEADER */ + u32 totalsize; /* total size of DT block */ + u32 off_dt_struct; /* offset to structure */ + u32 off_dt_strings; /* offset to strings */ + u32 off_mem_rsvmap; /* offset to memory reserve map */ + u32 version; /* format version */ + u32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ + /* version 3 fields below */ + u32 dt_strings_size; /* size of the DT strings block */ +}; + +struct ft_cxt { + struct boot_param_header *bph; + int max_size; /* maximum size of tree */ + int overflow; /* set when this happens */ + char *p, *pstr, *pres; /* running pointers */ + char *p_begin, *pstr_begin, *pres_begin; /* starting pointers */ + char *p_anchor; /* start of constructed area */ + int struct_size, strings_size, res_size; +}; + +void ft_begin_node(struct ft_cxt *cxt, const char *name); +void ft_end_node(struct ft_cxt *cxt); + +void ft_begin_tree(struct ft_cxt *cxt); +int ft_end_tree(struct ft_cxt *cxt); + +void ft_nop(struct ft_cxt *cxt); +void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz); +void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str); +void ft_prop_int(struct ft_cxt *cxt, const char *name, int val); +void ft_begin(struct ft_cxt *cxt, void *blob, int max_size); +void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); + +void ft_dump_blob(const void *bphp); +void ft_merge_blob(struct ft_cxt *cxt, void *blob); +void *ft_get_prop(void *bphp, const char *propname, int *szp); +void ft_set_prop(void *bphp, const char *propname, void *val, int len); + +#endif -- Hollis Blanchard IBM Linux Technology Center _______________________________________________ Xen-ppc-devel mailing list Xen-ppc-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-ppc-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |