Signed-off-by: Kumar Gala <[EMAIL PROTECTED]> --- common/cmd_bootm.c | 149 ++++++++++++++++++++++++++++- include/image.h | 20 ++++- lib_ppc/bootm.c | 272 ++++++++++++++++++++++++++++++++++------------------ 3 files changed, 347 insertions(+), 94 deletions(-)
* Added flushing the data cache in multicore cases so images are visible to both cores * Added an arch_lmb_reserve() as a way for arch's to reserve regions of memory that shouldnt get loaded on to (like the stack) * fixed up some comments pointed by Jerry diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 19257bb..5a48111 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -34,6 +34,7 @@ #include <bzlib.h> #include <environment.h> #include <lmb.h> +#include <linux/ctype.h> #include <asm/byteorder.h> #if defined(CONFIG_CMD_USB) @@ -128,6 +129,12 @@ void __board_lmb_reserve(struct lmb *lmb) } void board_lmb_reserve(struct lmb *lmb) __attribute__((weak, alias("__board_lmb_reserve"))); +void __arch_lmb_reserve(struct lmb *lmb) +{ + /* please define platform specific arch_lmb_reserve() */ +} +void arch_lmb_reserve(struct lmb *lmb) __attribute__((weak, alias("__arch_lmb_reserve"))); + #if defined(__ARM__) #define IH_INITRD_ARCH IH_ARCH_ARM #elif defined(__avr32__) @@ -173,6 +180,7 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) lmb_add(&images.lmb, (phys_addr_t)mem_start, mem_size); + arch_lmb_reserve(&images.lmb); board_lmb_reserve(&images.lmb); /* get kernel image header, start address and length */ @@ -273,7 +281,7 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } images.os.start = (ulong)os_hdr; - images.valid = 1; + images.state = BOOTM_STATE_START; return 0; } @@ -376,6 +384,113 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) return 0; } +/* we overload the cmd field with our state machine info instead of a + * function pointer */ +cmd_tbl_t cmd_bootm_sub[] = { + U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""), + U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""), +#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC) + U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""), +#endif +#ifdef CONFIG_OF_LIBFDT + U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""), +#endif + U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""), + U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""), + U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""), + U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""), +}; + +int do_bootm_subcommand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int ret = 0; + int state; + cmd_tbl_t *c; + + c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); + + if (c) { + state = (int)c->cmd; + + /* treat start special since it resets the state machine */ + if (state == BOOTM_STATE_START) { + argc--; + argv++; + return bootm_start(cmdtp, flag, argc, argv); + } + } + /* Unrecognized command */ + else { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (images.state >= state) { + printf ("Trying to execute a command out of order\n"); + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + images.state |= state; + + switch (state) { + ulong load_end; + case BOOTM_STATE_START: + /* should never occur */ + break; + case BOOTM_STATE_LOADOS: + ret = bootm_load_os(images.os, &load_end, 0); + if (ret) + return ret; + + lmb_reserve(&images.lmb, images.os.load, + (load_end - images.os.load)); + break; +#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC) + case BOOTM_STATE_RAMDISK: + { + ulong rd_len = images.rd_end - images.rd_start; + char str[17]; + + ret = boot_ramdisk_high(&images.lmb, images.rd_start, + rd_len, &images.initrd_start, &images.initrd_end); + if (ret) + return ret; + + sprintf(str, "%lx", images.initrd_start); + setenv("initrd_start", str); + sprintf(str, "%lx", images.initrd_end); + setenv("initrd_end", str); + } + break; +#endif +#ifdef CONFIG_OF_LIBFDT + case BOOTM_STATE_FDT: + { + ulong bootmap_base = getenv_bootm_low(); + ret = boot_relocate_fdt(&images.lmb, bootmap_base, + &images.ft_addr, &images.ft_len); + break; + } +#endif + case BOOTM_STATE_OS_CMDLINE: + do_bootm_linux(BOOTM_STATE_OS_CMDLINE, argc, argv, &images); + break; + case BOOTM_STATE_OS_BD_T: + do_bootm_linux(BOOTM_STATE_OS_BD_T, argc, argv, &images); + break; + case BOOTM_STATE_OS_PREP: + do_bootm_linux(BOOTM_STATE_OS_PREP, argc, argv, &images); + break; + case BOOTM_STATE_OS_GO: + disable_interrupts(); + do_bootm_linux(BOOTM_STATE_OS_GO, argc, argv, &images); + break; + } + + return ret; +} + /*******************************************************************/ /* bootm - boot application image from image in memory */ /*******************************************************************/ @@ -386,6 +501,23 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) ulong load_end = 0; int ret; + /* determine if we have a sub command */ + if (argc > 1) { + char *endp; + + simple_strtoul(argv[1], &endp, 16); + /* endp pointing to NULL means that argv[1] was just a + * valid number, pass it along to the normal bootm processing + * + * If endp is ':' or '#' assume a FIT identifier so pass + * along for normal processing. + * + * Right now we assume the first arg should never be '-' + */ + if ((*endp != 0) && (*endp != ':') && (*endp != '#')) + return do_bootm_subcommand(cmdtp, flag, argc, argv); + } + if (bootm_start(cmdtp, flag, argc, argv)) return 1; @@ -782,6 +914,21 @@ U_BOOT_CMD( "\tUse iminfo command to get the list of existing component\n" "\timages and configurations.\n" #endif + "\nSub-commands to do part of the bootm sequence. The sub-commands " + "must be\n" + "issued in the order below (it's ok to not issue all sub-commands):\n" + "\tstart [addr [arg ...]]\n" + "\tloados - load OS image\n" +#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC) + "\tramdisk - relocate initrd, set env initrd_start/initrd_end\n" +#endif +#if defined(CONFIG_OF_LIBFDT) + "\tfdt - relocate flat device tree\n" +#endif + "\tbdt - OS specific bd_t processing\n" + "\tcmdline - OS specific command line processing/setup\n" + "\tprep - OS specific prep before relocation or go\n" + "\tgo - start OS\n" ); /*******************************************************************/ diff --git a/include/image.h b/include/image.h index 82e6345..557e72a 100644 --- a/include/image.h +++ b/include/image.h @@ -228,6 +228,7 @@ typedef struct bootm_headers { #endif #endif +#ifndef USE_HOSTCC image_info_t os; /* os image info */ ulong ep; /* entry point of OS */ @@ -238,8 +239,25 @@ typedef struct bootm_headers { #endif ulong ft_len; /* length of flat device tree */ + ulong initrd_start; + ulong initrd_end; + ulong cmdline_start; + ulong cmdline_end; + bd_t *kbd; +#endif + int verify; /* getenv("verify")[0] != 'n' */ - int valid; /* set to 1 if we've set values in the header */ + +#define BOOTM_STATE_START (0x00000001) +#define BOOTM_STATE_LOADOS (0x00000002) +#define BOOTM_STATE_RAMDISK (0x00000004) +#define BOOTM_STATE_FDT (0x00000008) +#define BOOTM_STATE_OS_CMDLINE (0x00000010) +#define BOOTM_STATE_OS_BD_T (0x00000020) +#define BOOTM_STATE_OS_PREP (0x00000040) +#define BOOTM_STATE_OS_GO (0x00000080) + int state; + #ifndef USE_HOSTCC struct lmb lmb; /* for memory mgmt */ #endif diff --git a/lib_ppc/bootm.c b/lib_ppc/bootm.c index 5af25dd..e07959c 100644 --- a/lib_ppc/bootm.c +++ b/lib_ppc/bootm.c @@ -47,6 +47,7 @@ DECLARE_GLOBAL_DATA_PTR; +extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); extern ulong get_effective_memsize(void); static ulong get_sp (void); static void set_clocks_in_mhz (bd_t *kbd); @@ -55,30 +56,78 @@ static void set_clocks_in_mhz (bd_t *kbd); #define CFG_LINUX_LOWMEM_MAX_SIZE (768*1024*1024) #endif -__attribute__((noinline)) -int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +static void boot_jump_linux(bootm_headers_t *images) { - ulong sp; - - ulong initrd_start, initrd_end; - ulong rd_len; - ulong size; - phys_size_t bootm_size; - - ulong cmd_start, cmd_end, bootmap_base; - bd_t *kbd; void (*kernel)(bd_t *, ulong r4, ulong r5, ulong r6, ulong r7, ulong r8, ulong r9); - int ret; - ulong of_size = images->ft_len; - struct lmb *lmb = &images->lmb; - -#if defined(CONFIG_OF_LIBFDT) - char *of_flat_tree = images->ft_addr; +#ifdef CONFIG_OF_LIBFDT + char *of_flat_tree = images->ft_addr; #endif kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong, ulong, ulong))images->ep; + debug ("## Transferring control to Linux (at address %08lx) ...\n", + (ulong)kernel); + + show_boot_progress (15); + +#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) + unlock_ram_in_cache(); +#endif + +#if defined(CONFIG_OF_LIBFDT) + if (of_flat_tree) { /* device tree; boot new style */ + /* + * Linux Kernel Parameters (passing device tree): + * r3: pointer to the fdt + * r4: 0 + * r5: 0 + * r6: epapr magic + * r7: size of IMA in bytes + * r8: 0 + * r9: 0 + */ +#if defined(CONFIG_85xx) || defined(CONFIG_440) + #define EPAPR_MAGIC (0x45504150) +#else + #define EPAPR_MAGIC (0x65504150) +#endif + + debug (" Booting using OF flat tree...\n"); + (*kernel) ((bd_t *)of_flat_tree, 0, 0, EPAPR_MAGIC, + CFG_BOOTMAPSZ, 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 + * r8: 0 + * r9: 0 + */ + ulong cmd_start = images->cmdline_start; + ulong cmd_end = images->cmdline_end; + ulong initrd_start = images->initrd_start; + ulong initrd_end = images->initrd_end; + bd_t *kbd = images->kbd; + + debug (" Booting using board info...\n"); + (*kernel) (kbd, initrd_start, initrd_end, + cmd_start, cmd_end, 0, 0); + /* does not return */ + } + return ; +} + +void arch_lmb_reserve(struct lmb *lmb) +{ + phys_size_t bootm_size; + ulong size, sp, bootmap_base; bootmap_base = getenv_bootm_low(); bootm_size = getenv_bootm_size(); @@ -116,127 +165,166 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) sp -= 1024; lmb_reserve(lmb, sp, (CFG_SDRAM_BASE + get_effective_memsize() - sp)); + return ; +} + +static void boot_prep_linux(void) +{ +#if (CONFIG_NUM_CPUS > 1) + /* if we are MP make sure to flush the dcache() to any changes are made + * visibile to all other cores */ + flush_dcache(); +#endif + return ; +} + +static int boot_cmdline_linux(bootm_headers_t *images) +{ + ulong bootmap_base = getenv_bootm_low(); + ulong of_size = images->ft_len; + struct lmb *lmb = &images->lmb; + ulong *cmd_start = &images->cmdline_start; + ulong *cmd_end = &images->cmdline_end; + + int ret = 0; + if (!of_size) { /* allocate space and init command line */ - ret = boot_get_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; + return ret; } + } + + return ret; +} + +static int boot_bd_t_linux(bootm_headers_t *images) +{ + ulong bootmap_base = getenv_bootm_low(); + ulong of_size = images->ft_len; + struct lmb *lmb = &images->lmb; + bd_t **kbd = &images->kbd; + + int ret = 0; + if (!of_size) { /* allocate space for kernel copy of board info */ - ret = boot_get_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; + return ret; } - set_clocks_in_mhz(kbd); + set_clocks_in_mhz(*kbd); } + return ret; +} + +static int boot_body_linux(bootm_headers_t *images) +{ + ulong rd_len, bootmap_base = getenv_bootm_low(); + ulong of_size = images->ft_len; + struct lmb *lmb = &images->lmb; + ulong *initrd_start = &images->initrd_start; + ulong *initrd_end = &images->initrd_end; +#if defined(CONFIG_OF_LIBFDT) + char **of_flat_tree = &images->ft_addr; +#endif + + int ret; + + /* allocate space and init command line */ + ret = boot_cmdline_linux(images); + if (ret) + return ret; + + /* allocate space for kernel copy of board info */ + ret = boot_bd_t_linux(images); + if (ret) + return ret; + rd_len = images->rd_end - images->rd_start; + ret = boot_ramdisk_high (lmb, images->rd_start, rd_len, initrd_start, initrd_end); + if (ret) + return ret; #if defined(CONFIG_OF_LIBFDT) - ret = boot_relocate_fdt(lmb, bootmap_base, &of_flat_tree, &of_size); + ret = boot_relocate_fdt(lmb, bootmap_base, of_flat_tree, &of_size); if (ret) - goto error; + return ret; /* * Add the chosen node if it doesn't exist, add the env and bd_t * if the user wants it (the logic is in the subroutines). */ if (of_size) { - if (fdt_chosen(of_flat_tree, 1) < 0) { + if (fdt_chosen(*of_flat_tree, 1) < 0) { puts ("ERROR: "); puts ("/chosen node create failed"); puts (" - must RESET the board to recover.\n"); - goto error; + return -1; } #ifdef CONFIG_OF_BOARD_SETUP /* Call the board-specific fixup routine */ - ft_board_setup(of_flat_tree, gd->bd); + ft_board_setup(*of_flat_tree, gd->bd); #endif - } - /* Fixup the fdt memreserve now that we know how big it is */ - if (of_flat_tree) { /* Delete the old LMB reservation */ - lmb_free(lmb, (phys_addr_t)(u32)of_flat_tree, - (phys_size_t)fdt_totalsize(of_flat_tree)); + lmb_free(lmb, (phys_addr_t)(u32)*of_flat_tree, + (phys_size_t)fdt_totalsize(*of_flat_tree)); - ret = fdt_resize(of_flat_tree); + ret = fdt_resize(*of_flat_tree); if (ret < 0) - goto error; + return ret; of_size = ret; - if ((of_flat_tree) && (initrd_start && initrd_end)) + if (*initrd_start && *initrd_end) of_size += FDT_RAMDISK_OVERHEAD; /* Create a new LMB reservation */ - lmb_reserve(lmb, (ulong)of_flat_tree, of_size); + lmb_reserve(lmb, (ulong)*of_flat_tree, of_size); + + /* fixup the initrd now that we know where it should be */ + if (*initrd_start && *initrd_end) + fdt_initrd(*of_flat_tree, *initrd_start, *initrd_end, 1); } #endif /* CONFIG_OF_LIBFDT */ + return 0; +} - ret = boot_ramdisk_high (lmb, images->rd_start, rd_len, &initrd_start, &initrd_end); - if (ret) - goto error; - -#if defined(CONFIG_OF_LIBFDT) - /* fixup the initrd now that we know where it should be */ - if ((of_flat_tree) && (initrd_start && initrd_end)) - fdt_initrd(of_flat_tree, initrd_start, initrd_end, 1); -#endif - debug ("## Transferring control to Linux (at address %08lx) ...\n", - (ulong)kernel); +__attribute__((noinline)) +int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +{ + int ret; - show_boot_progress (15); + if (flag & BOOTM_STATE_OS_CMDLINE) { + boot_cmdline_linux(images); + return 0; + } -#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) - unlock_ram_in_cache(); -#endif + if (flag & BOOTM_STATE_OS_BD_T) { + boot_bd_t_linux(images); + return 0; + } -#if defined(CONFIG_OF_LIBFDT) - if (of_flat_tree) { /* device tree; boot new style */ - /* - * Linux Kernel Parameters (passing device tree): - * r3: pointer to the fdt - * r4: 0 - * r5: 0 - * r6: epapr magic - * r7: size of IMA in bytes - * r8: 0 - * r9: 0 - */ -#if defined(CONFIG_85xx) || defined(CONFIG_440) - #define EPAPR_MAGIC (0x45504150) -#else - #define EPAPR_MAGIC (0x65504150) -#endif + if (flag & BOOTM_STATE_OS_PREP) { + boot_prep_linux(); + return 0; + } - debug (" Booting using OF flat tree...\n"); - (*kernel) ((bd_t *)of_flat_tree, 0, 0, EPAPR_MAGIC, - CFG_BOOTMAPSZ, 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 - * r8: 0 - * r9: 0 - */ - debug (" Booting using board info...\n"); - (*kernel) (kbd, initrd_start, initrd_end, - cmd_start, cmd_end, 0, 0); - /* does not return */ + if (flag & BOOTM_STATE_OS_GO) { + boot_jump_linux(images); + return 0; } - return 1; -error: - return 1; + boot_prep_linux(); + ret = boot_body_linux(images); + if (ret) + return ret; + boot_jump_linux(images); + + return 0; } static ulong get_sp (void) -- 1.5.5.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot