On Fri, Sep 21, 2007 at 06:05:06PM -0500, Milton Miller wrote: > kexec-tools still produces a version 2 device tree, while the > libraries in the wrapper only support version 16 and later. > > Add a routine to convert a v2 flat device tree to a v16 one inplace > by inserting OF_DT_NOP and chomping full path. Make space for new > headers by moving and then chomping the OF_DT_NOPs. > > Signed-off-by: Milton Miller <[EMAIL PROTECTED]> > --- > vs 12175 > Rediffed Makefile, ops, kexec.c > > Index: kernel/arch/powerpc/boot/flatdevtree_conv.c > =================================================================== > --- /dev/null 1970-01-01 00:00:00.000000000 +0000 > +++ kernel/arch/powerpc/boot/flatdevtree_conv.c 2007-09-20 > 17:49:04.000000000 -0500 > @@ -0,0 +1,280 @@ > +/* > + * 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. > + * > + * Copyright IBM Corporation 2007 > + * > + * Authors: Milton Miller <[EMAIL PROTECTED]> > + */ > +#include "flatdevtree.h" > +#include "stdio.h" > +#include "ops.h" > + > +#define MIN_VERSION 2 > +#define OUT_VERSION 16
Should output version 17. In any case, don't try to be so general - just convert v123 (all basically the same) to latest (i.e. v17) without all the #if nonsense. > +#define OUT_COMPAT 16 > + > +#ifdef NO_CHECK > +static int check_v123_tree(u32 *start, u32 *limit) > +{ > + return 0; > +} > +#else > +/** > + * check_v123_tree - check integrety of a version 1, 2, or 3 tree > + * @start: the start of the device tree struct > + * @limit: the end of the region for the struct > + * structural checks on device_tree > + */ > +static int check_v123_tree(u32 *start, u32 *limit) What is the point of this check? If the device tree is corrupt, we're stuffed anyway, so why bother? > +{ > + u32 len; > + int depth = 0; > + u32 *dtp = start; > + > + while (dtp < limit) > + switch (*dtp) { > + case OF_DT_END: > + if (depth) > + return -1; > + return ++dtp - start; > + case OF_DT_NOP: > + dtp++; > + break; > + case OF_DT_END_NODE: > + dtp++; > + depth--; > + break; > + case OF_DT_BEGIN_NODE: > + len = strlen((char *)(++dtp)); > + /* check path is suffix to previous? */ > + dtp += 1 + (len / 4); > + depth++; > + break; > + case OF_DT_PROP: > + len = dtp[1]; > + dtp += 3; > + if ((len >= 8) && ((long)dtp & 4)) > + dtp++; > + dtp += (len + 3) / 4; > + break; > + default: > + return -1; > + } > + return -1; /* no OF_DT_END */ > +} > +#endif > + > +/** > + * nop_to_v16 - add %OF_DT_NOP to hide alignment differences > + * @dtp: pointer to the beginning of the struct area to modify > + * insert %OF_DT_NOP into the dt_struct @dtp to make it v16 from v1, 2, or 3. > + */ > +static int nop_to_v16(u32 *dtp) > +{ > + int nops = 0; > + char *p, *s; > + int len; > + u32 *next; > + > + while (*dtp != OF_DT_END) > + switch (*dtp) { > + case OF_DT_BEGIN_NODE: > + /* v2 & v3 names are full path, v16+ is relative */ > + p = (char *)(++dtp); > + len = strlen(p); > + next = dtp + 1 + len / 4; > + > + for (s = p + len; *s != '/'; s--) > + if (s == p) > + fatal("name %s has no '/'", p); > + > + len -= s++ - p; /* not the slash but the nul */ > + memmove(p, s, len); > + while (len % 4) > + p[len++] = '\0'; > + dtp += len / 4; > + while (dtp != next) { > + *dtp++ = OF_DT_NOP; > + nops++; > + } > + break; > + case OF_DT_PROP: > + /* convert from align_8 to align_4 via prefixing nop */ > + len = dtp[1]; > + if ((len >= 8) && !((long)dtp & 4)) { > + memmove(dtp+1, dtp, 12); > + *dtp++ = OF_DT_NOP; > + nops++; > + } > + dtp += 3 + (len + 3)/4; > + break; > + default: > + fatal("%s: unrecognised tag %d at %p\n", __FUNCTION__, > + *dtp, dtp); > + case OF_DT_NOP: > + nops ++; > + /* fall through */ > + case OF_DT_END_NODE: > + dtp ++; > + break; > + } > + return nops; > +} > + > +#if MIN_VERSION < 3 || OUT_VERSION > 16 > +/** > + * move_nops_fwd - move nops in a v16 dt_struct to the beginning > + * @start - device tree starting address > + * @count - number of %OF_DT_NOP cells to move > + */ > +static void move_nops_fwd(u32 *start, int count) What on earth is the point of this. The NOPs are perfectly valid scattered within the tree, why go to all this trouble to shuffle them about. > +{ > + u32 *dtp = start; > + int len; > + while (count) > + switch (*dtp) { > + case OF_DT_NOP: > + memmove(start+1,start,(dtp-start) * 4); > + *start++ = OF_DT_NOP; > + dtp++; > + count--; > + break; > + case OF_DT_END_NODE: > + dtp++; > + break; > + case OF_DT_BEGIN_NODE: > + len = strlen((char *)(++dtp)); > + dtp += 1 + len / 4; > + break; > + case OF_DT_PROP: > + len = dtp[1]; > + dtp += 3 + (len + 3) / 4; > + break; > + case OF_DT_END: > + fatal("Not enough nops -- need %d more\n", count); > + return; > + default: > + fatal("%s: unknown tag %d at %p", __FUNCTION__, *dtp, > dtp) > + } > +} > +#endif > + > +/** > + * conv_flattree_inplace upgrade the version of a boot_param_header > + * @tree: pointer to the device tree header to convert > + * > + * Converts a v1, 2, 3 device tree (of at least MIN_VERSION) > + * in place to OUT_VERSION (16) format, usable by flatdevtree.c > + */ > +void conv_flattree_inplace(struct boot_param_header *tree) > +{ > + u32 *dtp; > + u32 need = 0, nops; > + int slen; > + > + if (tree->magic != OF_DT_HEADER) > + fatal("%s: no magic", __FUNCTION__); More pointless tests... > + if (tree->last_comp_version > 3) > + return; /* don't know what to do */ Rather, don't need to do anything. > + > + if (tree->version < MIN_VERSION) { > + printf("%s: Warning: can't handle version %d tree\n", > + __FUNCTION__, tree->version); > + return; > + } > + > + if (tree->version < 2) > + need++; /* boot_cpu_id */ > + > + if (tree->version < 3) > + need++; /* dt_string_size */ > + > + if (OUT_VERSION > 16) > + need++; /* dt_struct_size */ > + > + dtp = (void *)tree + tree->off_dt_struct; > + > + slen = check_v123_tree(dtp, (void *)tree + tree->totalsize); > + if (slen < 0) > + fatal("device tree check failed\n"); > + > + nops = nop_to_v16(dtp); > + > + if (need & 1) /* keep 8 byte alignment of mem reserve */ > + need++; > + > + if (need > nops) > + fatal("Didn't find enough space to add new header fields\n\r" > + "(needed %d found %d tree %p)", need, nops, tree); > + > + /* ok now compress the dtb struct */ > + move_nops_fwd(dtp, need); > + dtp += need; > + > + /* > + * move mem_rsvmap and dt_strings if they are before dt_struct > + * onto our nops . Adjust start addresses for the 3 sections. > + */ Hrm. Do we really need to worry about this case. You may be producing v2 trees in kexec-tools, but do they actually have the blocks out of order? dtc certainly never produced them that way. > + if ((tree->off_mem_rsvmap < tree->off_dt_struct) || > + (tree->off_dt_strings < tree->off_dt_struct)) { > + int start, end; > + void *ptr; > + > + if (tree->off_mem_rsvmap < tree->off_dt_strings) > + start = tree->off_mem_rsvmap; > + else > + start = tree->off_dt_strings; > + > + end = tree->off_dt_struct; > + ptr = (void *)tree + start; > + > + memmove(ptr + 4 * need, ptr, end - start); > + > + if (tree->off_mem_rsvmap < tree->off_dt_struct) > + tree->off_mem_rsvmap += 4 * need; > + if (tree->off_dt_strings < tree->off_dt_struct) > + tree->off_dt_strings += 4 * need; > + } > + tree->off_dt_struct += 4 * need; > + > + /* ok now we have space to extend the header. */ > + if (tree->version < 2 && MIN_VERSION < 2) { > + tree->boot_cpuid_phys = 0; /* default, caller can fix */ > + } > + > + /* calculate size of dt_strings_size */ > + if (tree->version < 3 && MIN_VERSION < 3) { > + int end = tree->totalsize; > + > + if (tree->off_dt_strings < tree->off_mem_rsvmap) > + end = tree->off_mem_rsvmap; > + > + if ((tree->off_dt_strings < tree->off_dt_struct) && > + (end > tree->off_dt_struct)) > + end = tree->off_dt_struct; > + > + tree->dt_strings_size = end - tree->off_dt_strings; > + } > + > +#if OUT_VERSION > 16 > + tree->dt_struct_size = 4 * slen; > +#endif > + > + tree->version = OUT_VERSION; > + tree->last_comp_version = OUT_COMPAT; > + > + return; > +} > Index: kernel/arch/powerpc/boot/Makefile > =================================================================== > --- kernel.orig/arch/powerpc/boot/Makefile 2007-09-20 17:42:24.000000000 > -0500 > +++ kernel/arch/powerpc/boot/Makefile 2007-09-20 17:49:04.000000000 -0500 > @@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util. > $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix > $(obj)/,$(zlibheader)) > > src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ > - marshal.c memranges.c kexec.c \ > + flatdevtree_conv.c marshal.c memranges.c kexec.c \ > ns16550.c serial.c simple_alloc.c div64.S util.S \ > gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \ > 4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \ > Index: kernel/arch/powerpc/boot/ops.h > =================================================================== > --- kernel.orig/arch/powerpc/boot/ops.h 2007-09-20 17:42:24.000000000 > -0500 > +++ kernel/arch/powerpc/boot/ops.h 2007-09-20 17:49:04.000000000 -0500 > @@ -81,7 +81,10 @@ struct loader_info { > }; > extern struct loader_info loader_info; > > +struct boot_param_header; > + > void start(void); > +void conv_flattree_inplace(struct boot_param_header *tree); > int ft_init(void *dt_blob, unsigned int max_size, unsigned int > max_find_device); > int serial_console_init(void); > int ns16550_console_init(void *devp, struct serial_console_data *scdp); > Index: kernel/arch/powerpc/boot/kexec.c > =================================================================== > --- kernel.orig/arch/powerpc/boot/kexec.c 2007-09-20 17:42:24.000000000 > -0500 > +++ kernel/arch/powerpc/boot/kexec.c 2007-09-20 17:49:04.000000000 -0500 > @@ -99,6 +99,7 @@ void kexec_platform_init(struct boot_par > move_slaves_up(); > > setup_initial_heap(); > + conv_flattree_inplace(dt_blob); > init_flat_tree(dt_blob); > /* > * drivers can malloc and read the tree, but not realloc later > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev > -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev