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 +#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) +{ + 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) +{ + 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__); + + if (tree->last_comp_version > 3) + return; /* don't know what to do */ + + 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. + */ + 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