
From: Michal Simek monstr@monstr.eu
Signed-off-by: Michal Simek monstr@monstr.eu --- lib_microblaze/bootm.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 430 insertions(+), 14 deletions(-)
diff --git a/lib_microblaze/bootm.c b/lib_microblaze/bootm.c index 30a03ef..c8fcf21 100644 --- a/lib_microblaze/bootm.c +++ b/lib_microblaze/bootm.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2007 Michal Simek + * (C) Copyright 2007-2008 Michal Simek * (C) Copyright 2004 Atmark Techno, Inc. * * Michal SIMEK monstr@monstr.eu @@ -15,7 +15,7 @@ * * 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 + * 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 @@ -30,24 +30,46 @@ #include <zlib.h> #include <asm/byteorder.h>
+#if defined(CONFIG_OF_LIBFDT) +#include <fdt.h> +#include <libfdt.h> +#include <fdt_support.h> + +static int boot_get_fdt (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + bootm_headers_t *images, char **of_flat_tree, ulong *of_size); +static image_header_t *image_get_fdt (ulong fdt_addr); +#endif + DECLARE_GLOBAL_DATA_PTR;
extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
void do_bootm_linux (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[], - bootm_headers_t *images) + bootm_headers_t *images) { - /* First parameter is mapped to $r5 for kernel boot args */ - void (*theKernel) (char *); + void (*theKernel) (char *, ulong, ulong); char *commandline = getenv ("bootargs"); + ulong rd_data_start, rd_data_end; ulong ep = 0; + int ret; + +#if defined(CONFIG_OF_LIBFDT) + char *of_flat_tree = NULL; + ulong of_size = 0; +#endif + + /* find flattened device tree */ + ret = boot_get_fdt (cmdtp, flag, argc, argv, images, + &of_flat_tree, &of_size); + if (ret) + goto error;
/* find kernel entry point */ if (images->legacy_hdr_valid) { - ep = image_get_ep (&images->legacy_hdr_os_copy); + ep = image_get_ep (images->legacy_hdr_os); #if defined(CONFIG_FIT) } else if (images->fit_uname_os) { - int ret = fit_image_get_entry (images->fit_hdr_os, + ret = fit_image_get_entry (images->fit_hdr_os, images->fit_noffset_os, &ep); if (ret) { puts ("Can't get entry point property!\n"); @@ -58,19 +80,33 @@ void do_bootm_linux (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[], puts ("Could not find kernel entry point!\n"); goto error; } - theKernel = (void (*)(char *))ep; + theKernel = (void (*)(char *, ulong, ulong))ep; + + /* find ramdisk */ + ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_MICROBLAZE, + &rd_data_start, &rd_data_end); + if (ret) + goto error;
show_boot_progress (15);
+ if (!(ulong) of_flat_tree) + of_flat_tree = simple_strtoul (argv[3], NULL, 16); + + /* + * Linux Kernel Parameters (passing device tree): + * r5: pointer to command line + * r6: pointer to ramdisk + * r7: pointer to the fdt, followed by the board info data + */ + #ifdef DEBUG - printf ("## Transferring control to Linux (at address %08lx) ...\n", - (ulong) theKernel); + printf ("## Transferring control to Linux (at address %08lx) " \ + "ramdisk 0x%08x, FDT 0x%08x...\n", + (ulong) theKernel, rd_data_start, (ulong) of_flat_tree); #endif + theKernel (commandline, rd_data_start, (ulong) of_flat_tree);
- if (!images->autostart) - return ; - - theKernel (commandline); /* does not return */ return;
@@ -79,3 +115,383 @@ error: do_reset (cmdtp, flag, argc, argv); return; } + +#if defined(CONFIG_FIT) +static void fdt_error (const char *msg) +{ + puts ("ERROR: "); + puts (msg); + puts (" - must RESET the board to recover.\n"); +} + +/** + * fit_check_fdt - verify FIT format FDT subimage + * @fit_hdr: pointer to the FIT header + * fdt_noffset: FDT subimage node offset within FIT image + * @verify: data CRC verification flag + * + * fit_check_fdt() verifies integrity of the FDT subimage and from + * specified FIT image. + * + * returns: + * 1, on success + * 0, on failure + */ +static int fit_check_fdt (const void *fit, int fdt_noffset, int verify) +{ + fit_image_print (fit, fdt_noffset, " "); + + if (verify) { + puts (" Verifying Hash Integrity ... "); + if (!fit_image_check_hashes (fit, fdt_noffset)) { + fdt_error ("Bad Data Hash"); + return 0; + } + puts ("OK\n"); + } + + if (!fit_image_check_type (fit, fdt_noffset, IH_TYPE_FLATDT)) { + fdt_error ("Not a FDT image"); + return 0; + } + + if (!fit_image_check_comp (fit, fdt_noffset, IH_COMP_NONE)) { + fdt_error ("FDT image is compressed"); + return 0; + } + + return 1; +} +#endif /* CONFIG_FIT */ + +static int boot_get_fdt (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + bootm_headers_t *images, char **of_flat_tree, ulong *of_size) +{ + ulong fdt_addr; + image_header_t *fdt_hdr; + char *fdt_blob = NULL; + ulong image_start, image_end; + ulong load_start, load_end; +#if defined(CONFIG_FIT) + void *fit_hdr; + const char *fit_uname_config = NULL; + const char *fit_uname_fdt = NULL; + ulong default_addr; + int cfg_noffset; + int fdt_noffset; + const void *data; + size_t size; +#endif + + *of_flat_tree = NULL; + *of_size = 0; + + if (argc > 3 || genimg_has_config (images)) { +#if defined(CONFIG_FIT) + if (argc > 3) { + /* + * If the FDT blob comes from the FIT image and the + * FIT image address is omitted in the command line + * argument, try to use ramdisk or os FIT image + * address or default load address. + */ + if (images->fit_uname_rd) + default_addr = (ulong)images->fit_hdr_rd; + else if (images->fit_uname_os) + default_addr = (ulong)images->fit_hdr_os; + else + default_addr = load_addr; + + if (fit_parse_conf (argv[3], default_addr, + &fdt_addr, &fit_uname_config)) { + debug ("* fdt: config '%s' from image at 0x%08lx\n", + fit_uname_config, fdt_addr); + } else if (fit_parse_subimage (argv[3], default_addr, + &fdt_addr, &fit_uname_fdt)) { + debug ("* fdt: subimage '%s' from image at 0x%08lx\n", + fit_uname_fdt, fdt_addr); + } else +#endif + { + fdt_addr = simple_strtoul(argv[3], NULL, 16); + debug ("* fdt: cmdline image address = 0x%08lx\n", + fdt_addr); + } +#if defined(CONFIG_FIT) + } else { + /* use FIT configuration provided in first bootm + * command argument + */ + fdt_addr = (ulong)images->fit_hdr_os; + fit_uname_config = images->fit_uname_cfg; + debug ("* fdt: using config '%s' from image at 0x%08lx\n", + fit_uname_config, fdt_addr); + + /* + * Check whether configuration has FDT blob defined, + * if not quit silently. + */ + fit_hdr = (void *)fdt_addr; + cfg_noffset = fit_conf_get_node (fit_hdr, + fit_uname_config); + if (cfg_noffset < 0) { + debug ("* fdt: no such config\n"); + return 0; + } + + fdt_noffset = fit_conf_get_fdt_node (fit_hdr, + cfg_noffset); + if (fdt_noffset < 0) { + debug ("* fdt: no fdt in config\n"); + return 0; + } + } +#endif + + debug ("## Checking for 'FDT'/'FDT Image' at %08lx\n", + fdt_addr); + + /* copy from dataflash if needed */ + fdt_addr = genimg_get_image (fdt_addr); + + /* + * Check if there is an FDT image at the + * address provided in the second bootm argument + * check image type, for FIT images get a FIT node. + */ + switch (genimg_get_format ((void *)fdt_addr)) { + case IMAGE_FORMAT_LEGACY: + /* verify fdt_addr points to a valid image header */ + printf ("## Flattened Device Tree from Legacy Image at %08lx\n", + fdt_addr); + fdt_hdr = image_get_fdt (fdt_addr); + if (!fdt_hdr) + goto error; + + /* + * move image data to the load address, + * make sure we don't overwrite initial image + */ + image_start = (ulong)fdt_hdr; + image_end = image_get_image_end (fdt_hdr); + + load_start = image_get_load (fdt_hdr); + load_end = load_start + image_get_data_size (fdt_hdr); + + if ((load_start < image_end) && (load_end > image_start)) { + fdt_error ("fdt overwritten"); + goto error; + } + + debug (" Loading FDT from 0x%08lx to 0x%08lx\n", + image_get_data (fdt_hdr), load_start); + + memmove ((void *)load_start, + (void *)image_get_data (fdt_hdr), + image_get_data_size (fdt_hdr)); + + fdt_blob = (char *)load_start; + break; + case IMAGE_FORMAT_FIT: + /* + * This case will catch both: new uImage format + * (libfdt based) and raw FDT blob (also libfdt + * based). + */ +#if defined(CONFIG_FIT) + /* check FDT blob vs FIT blob */ + if (fit_check_format ((const void *)fdt_addr)) { + /* + * FIT image + */ + fit_hdr = (void *)fdt_addr; + printf ("## Flattened Device Tree from FIT Image at %08lx\n", + fdt_addr); + + if (!fit_uname_fdt) { + /* + * no FDT blob image node unit name, + * try to get config node first. If + * config unit node name is NULL + * fit_conf_get_node() will try to + * find default config node + */ + cfg_noffset = fit_conf_get_node (fit_hdr, + fit_uname_config); + + if (cfg_noffset < 0) { + fdt_error ("Could not find configuration node\n"); + goto error; + } + + fit_uname_config = fdt_get_name (fit_hdr, + cfg_noffset, NULL); + printf (" Using '%s' configuration\n", + fit_uname_config); + + fdt_noffset = fit_conf_get_fdt_node (fit_hdr, + cfg_noffset); + fit_uname_fdt = fit_get_name (fit_hdr, + fdt_noffset, NULL); + } else { + /* get FDT component image node offset */ + fdt_noffset = fit_image_get_node (fit_hdr, + fit_uname_fdt); + } + if (fdt_noffset < 0) { + fdt_error ("Could not find subimage node\n"); + goto error; + } + + printf (" Trying '%s' FDT blob subimage\n", + fit_uname_fdt); + + if (!fit_check_fdt (fit_hdr, fdt_noffset, + images->verify)) + goto error; + + /* get ramdisk image data address and length */ + if (fit_image_get_data (fit_hdr, fdt_noffset, + &data, &size)) { + fdt_error ("Could not find FDT subimage data"); + goto error; + } + + /* verify that image data is a proper FDT blob */ + if (fdt_check_header ((char *)data) != 0) { + fdt_error ("Subimage data is not a FDT"); + goto error; + } + + /* + * move image data to the load address, + * make sure we don't overwrite initial image + */ + image_start = (ulong)fit_hdr; + image_end = fit_get_end (fit_hdr); + + if (fit_image_get_load (fit_hdr, fdt_noffset, + &load_start) == 0) { + load_end = load_start + size; + + if ((load_start < image_end) && + (load_end > image_start)) { + fdt_error ("FDT overwritten"); + goto error; + } + + printf (" Loading FDT from 0x%08lx to 0x%08lx\n", + (ulong)data, load_start); + + memmove ((void *)load_start, + (void *)data, size); + + fdt_blob = (char *)load_start; + } else { + fdt_blob = (char *)data; + } + + images->fit_hdr_fdt = fit_hdr; + images->fit_uname_fdt = fit_uname_fdt; + images->fit_noffset_fdt = fdt_noffset; + break; + } else +#endif + { + /* + * FDT blob + */ + fdt_blob = (char *)fdt_addr; + debug ("* fdt: raw FDT blob\n"); + printf ("## Flattened Device Tree blob at %08lx\n", fdt_blob); + } + break; + default: + fdt_error ("Did not find a cmdline Flattened Device Tree"); + goto error; + } + + printf (" Booting using the fdt blob at 0x%x\n", fdt_blob); + + } else if (images->legacy_hdr_valid && + image_check_type (&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) { + + ulong fdt_data, fdt_len; + + /* + * Now check if we have a legacy multi-component image, + * get second entry data start address and len. + */ + printf ("## Flattened Device Tree from multi " + "component Image at %08lX\n", + (ulong)images->legacy_hdr_os); + + image_multi_getimg (images->legacy_hdr_os, 2, &fdt_data, &fdt_len); + if (fdt_len) { + + fdt_blob = (char *)fdt_data; + printf (" Booting using the fdt at 0x%x\n", fdt_blob); + + if (fdt_check_header (fdt_blob) != 0) { + fdt_error ("image is not a fdt"); + goto error; + } + + if (be32_to_cpu (fdt_totalsize (fdt_blob)) != fdt_len) { + fdt_error ("fdt size != image size"); + goto error; + } + } else { + fdt_error ("Did not find a Flattened Device Tree " + "in a legacy multi-component image"); + goto error; + } + } else { + debug ("## No Flattened Device Tree\n"); + return 0; + } + + *of_flat_tree = fdt_blob; + *of_size = be32_to_cpu (fdt_totalsize (fdt_blob)); + debug (" of_flat_tree at 0x%08lx size 0x%08lx\n", + *of_flat_tree, *of_size); + + return 0; + +error: + do_reset (cmdtp, flag, argc, argv); + return 1; +} + +static image_header_t *image_get_fdt (ulong fdt_addr) +{ + image_header_t *fdt_hdr = (image_header_t *)fdt_addr; + + image_print_contents (fdt_hdr); + + puts (" Verifying Checksum ... "); + if (!image_check_hcrc (fdt_hdr)) { + fdt_error ("fdt header checksum invalid"); + return NULL; + } + + if (!image_check_dcrc (fdt_hdr)) { + fdt_error ("fdt checksum invalid"); + return NULL; + } + puts ("OK\n"); + + if (!image_check_type (fdt_hdr, IH_TYPE_FLATDT)) { + fdt_error ("uImage is not a fdt"); + return NULL; + } + if (image_get_comp (fdt_hdr) != IH_COMP_NONE) { + fdt_error ("uImage is compressed"); + return NULL; + } + if (fdt_check_header ((char *)image_get_data (fdt_hdr)) != 0) { + fdt_error ("uImage data is not a fdt"); + return NULL; + } + return fdt_hdr; +}