* MA 02111-1307 USA
*/
-#define DEBUG
#include <common.h>
#include <watchdog.h>
#include <fdt_support.h>
static void fdt_error (const char *msg);
-static int get_fdt (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
+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 int fdt_relocate (struct lmb *lmb, ulong bootmap_base,
+static int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
char **of_flat_tree, ulong *of_size);
#endif
static ulong get_sp (void);
static void set_clocks_in_mhz (bd_t *kbd);
+#ifndef CFG_LINUX_LOWMEM_MAX_SIZE
+#define CFG_LINUX_LOWMEM_MAX_SIZE (768*1024*1024)
+#endif
+
void __attribute__((noinline))
do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
bootm_headers_t *images)
ulong initrd_start, initrd_end;
ulong rd_data_start, rd_data_end, rd_len;
+ ulong size;
ulong cmd_start, cmd_end, bootmap_base;
bd_t *kbd;
char *of_flat_tree = NULL;
#endif
- bootmap_base = 0;
+ bootmap_base = getenv_bootm_low();
+ size = getenv_bootm_size();
+
+#ifdef DEBUG
+ if (((u64)bootmap_base + size) > (CFG_SDRAM_BASE + (u64)gd->ram_size))
+ puts("WARNING: bootm_low + bootm_size exceed total memory\n");
+ if ((bootmap_base + size) > get_effective_memsize())
+ puts("WARNING: bootm_low + bootm_size exceed eff. memory\n");
+#endif
+
+ size = min(size, get_effective_memsize());
+ size = min(size, CFG_LINUX_LOWMEM_MAX_SIZE);
+
+ if (size < getenv_bootm_size()) {
+ ulong base = bootmap_base + size;
+ printf("WARNING: adjusting available memory to %x\n", size);
+ lmb_reserve(lmb, base, getenv_bootm_size() - size);
+ }
/*
* Booting a (Linux) kernel image
* pointer.
*/
sp = get_sp();
- debug ("## Current stack ends at 0x%08lx ", sp);
+ debug ("## Current stack ends at 0x%08lx\n", sp);
/* adjust sp by 1K to be safe */
sp -= 1024;
#if defined(CONFIG_OF_LIBFDT)
/* find flattened device tree */
- ret = get_fdt (cmdtp, flag, argc, argv, images, &of_flat_tree, &of_size);
+ ret = boot_get_fdt (cmdtp, flag, argc, argv, images, &of_flat_tree, &of_size);
if (ret)
goto error;
if (!of_size) {
/* allocate space and init command line */
- ret = get_boot_cmdline (lmb, &cmd_start, &cmd_end, bootmap_base);
+ ret = boot_get_cmdline (lmb, &cmd_start, &cmd_end, bootmap_base);
if (ret) {
puts("ERROR with allocation of cmdline\n");
goto error;
}
/* allocate space for kernel copy of board info */
- ret = get_boot_kbd (lmb, &kbd, bootmap_base);
+ ret = boot_get_kbd (lmb, &kbd, bootmap_base);
if (ret) {
puts("ERROR with allocation of kernel bd\n");
goto error;
ep = image_get_ep (images->legacy_hdr_os);
#if defined(CONFIG_FIT)
} else if (images->fit_uname_os) {
- fit_unsupported_reset ("PPC linux bootm");
- goto error;
+ ret = fit_image_get_entry (images->fit_hdr_os,
+ images->fit_noffset_os, &ep);
+ if (ret) {
+ puts ("Can't get entry point property!\n");
+ goto error;
+ }
#endif
} else {
puts ("Could not find kernel entry point!\n");
kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))ep;
/* find ramdisk */
- ret = get_ramdisk (cmdtp, flag, argc, argv, images,
- IH_ARCH_PPC, &rd_data_start, &rd_data_end);
-
+ ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_PPC,
+ &rd_data_start, &rd_data_end);
if (ret)
goto error;
rd_len = rd_data_end - rd_data_start;
#if defined(CONFIG_OF_LIBFDT)
- ret = fdt_relocate (lmb, bootmap_base,
+ ret = boot_relocate_fdt (lmb, bootmap_base,
cmdtp, flag, argc, argv, &of_flat_tree, &of_size);
/*
}
#endif /* CONFIG_OF_LIBFDT */
- ret = ramdisk_high (lmb, rd_data_start, rd_len, &initrd_start, &initrd_end);
+ ret = boot_ramdisk_high (lmb, rd_data_start, rd_len, &initrd_start, &initrd_end);
if (ret)
goto error;
#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500)
unlock_ram_in_cache();
#endif
+ if (!images->autostart)
+ return ;
#if defined(CONFIG_OF_LIBFDT)
if (of_flat_tree) { /* device tree; boot new style */
* r6: NULL
* r7: NULL
*/
+ debug (" Booting using OF flat tree...\n");
(*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0);
/* does not return */
- }
+ } else
#endif
- /*
- * Linux Kernel Parameters (passing board info data):
- * r3: ptr to board info data
- * r4: initrd_start or 0 if no initrd
- * r5: initrd_end - unused if r4 is 0
- * r6: Start of command line string
- * r7: End of command line string
- */
- (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
- /* does not return */
+ {
+ /*
+ * Linux Kernel Parameters (passing board info data):
+ * r3: ptr to board info data
+ * r4: initrd_start or 0 if no initrd
+ * r5: initrd_end - unused if r4 is 0
+ * r6: Start of command line string
+ * r7: End of command line string
+ */
+ debug (" Booting using board info...\n");
+ (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
+ /* does not return */
+ }
return ;
error:
- do_reset (cmdtp, flag, argc, argv);
+ if (images->autostart)
+ do_reset (cmdtp, flag, argc, argv);
return ;
}
return fdt_hdr;
}
-static int get_fdt (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
+/**
+ * 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
+ */
+#if defined(CONFIG_FIT)
+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;
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
- if (argc > 3) {
+ *of_flat_tree = NULL;
+ *of_size = 0;
+
+ if (argc > 3 || genimg_has_config (images)) {
#if defined(CONFIG_FIT)
- /*
- * 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
+ 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);
+ {
+ 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",
+ debug ("## Checking for 'FDT'/'FDT Image' at %08lx\n",
fdt_addr);
/* copy from dataflash if needed */
- fdt_addr = gen_get_image (fdt_addr);
+ 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 (gen_image_get_format ((void *)fdt_addr)) {
+ switch (genimg_get_format ((void *)fdt_addr)) {
case IMAGE_FORMAT_LEGACY:
- debug ("* fdt: legacy format image\n");
-
/* verify fdt_addr points to a valid image header */
- printf ("## Flattened Device Tree Legacy Image at %08lx\n",
+ printf ("## Flattened Device Tree from Legacy Image at %08lx\n",
fdt_addr);
fdt_hdr = image_get_fdt (fdt_addr);
if (!fdt_hdr)
fdt_error ("fdt overwritten");
goto error;
}
- memmove ((void *)image_get_load (fdt_hdr),
+
+ 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 *)image_get_load (fdt_hdr);
+ fdt_blob = (char *)load_start;
break;
case IMAGE_FORMAT_FIT:
/*
*/
#if defined(CONFIG_FIT)
/* check FDT blob vs FIT blob */
- if (0) { /* FIXME: call FIT format verification */
+ if (fit_check_format ((const void *)fdt_addr)) {
/*
* FIT image
*/
fit_hdr = (void *)fdt_addr;
- debug ("* fdt: FIT format image\n");
- fit_unsupported_reset ("PPC fdt");
- goto error;
+ 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;
+ }
+
+ /* verift that image data is a proper FDT blob */
+ if (fdt_check_header ((char *)data) != 0) {
+ fdt_error ("Subimage data is not a FTD");
+ 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
{
}
} else {
debug ("## No Flattened Device Tree\n");
- *of_flat_tree = NULL;
- *of_size = 0;
return 0;
}
return 1;
}
-static int fdt_relocate (struct lmb *lmb, ulong bootmap_base,
+static int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
char **of_flat_tree, ulong *of_size)
{
if (fdt_blob >= (char *)CFG_BOOTMAPSZ)
relocate = 1;
- of_len = be32_to_cpu (fdt_totalsize (fdt));
+ of_len = be32_to_cpu (fdt_totalsize (fdt_blob));
/* move flattend device tree if needed */
if (relocate) {