summaryrefslogtreecommitdiff
path: root/common/cmd_bootm.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/cmd_bootm.c')
-rw-r--r--common/cmd_bootm.c303
1 files changed, 246 insertions, 57 deletions
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 19257bbd4..6fdeef49a 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -34,13 +34,14 @@
#include <bzlib.h>
#include <environment.h>
#include <lmb.h>
+#include <linux/ctype.h>
#include <asm/byteorder.h>
#if defined(CONFIG_CMD_USB)
#include <usb.h>
#endif
-#ifdef CFG_HUSH_PARSER
+#ifdef CONFIG_SYS_HUSH_PARSER
#include <hush.h>
#endif
@@ -60,8 +61,8 @@
DECLARE_GLOBAL_DATA_PTR;
extern int gunzip (void *dst, int dstlen, unsigned char *src, unsigned long *lenp);
-#ifndef CFG_BOOTM_LEN
-#define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */
+#ifndef CONFIG_SYS_BOOTM_LEN
+#define CONFIG_SYS_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */
#endif
#ifdef CONFIG_BZIP2
@@ -102,13 +103,23 @@ extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
typedef int boot_os_fn (int flag, int argc, char *argv[],
bootm_headers_t *images); /* pointers to os/initrd/fdt */
+#define CONFIG_BOOTM_LINUX 1
+#define CONFIG_BOOTM_NETBSD 1
+#define CONFIG_BOOTM_RTEMS 1
+
+#ifdef CONFIG_BOOTM_LINUX
extern boot_os_fn do_bootm_linux;
+#endif
+#ifdef CONFIG_BOOTM_NETBSD
static boot_os_fn do_bootm_netbsd;
+#endif
#if defined(CONFIG_LYNXKDI)
static boot_os_fn do_bootm_lynxkdi;
extern void lynxkdi_boot (image_header_t *);
#endif
+#ifdef CONFIG_BOOTM_RTEMS
static boot_os_fn do_bootm_rtems;
+#endif
#if defined(CONFIG_CMD_ELF)
static boot_os_fn do_bootm_vxworks;
static boot_os_fn do_bootm_qnxelf;
@@ -119,7 +130,29 @@ int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
static boot_os_fn do_bootm_integrity;
#endif
-ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */
+boot_os_fn * boot_os[] = {
+#ifdef CONFIG_BOOTM_LINUX
+ [IH_OS_LINUX] = do_bootm_linux,
+#endif
+#ifdef CONFIG_BOOTM_NETBSD
+ [IH_OS_NETBSD] = do_bootm_netbsd,
+#endif
+#ifdef CONFIG_LYNXKDI
+ [IH_OS_LYNXOS] = do_bootm_lynxkdi,
+#endif
+#ifdef CONFIG_BOOTM_RTEMS
+ [IH_OS_RTEMS] = do_bootm_rtems,
+#endif
+#if defined(CONFIG_CMD_ELF)
+ [IH_OS_VXWORKS] = do_bootm_vxworks,
+ [IH_OS_QNX] = do_bootm_qnxelf,
+#endif
+#ifdef CONFIG_INTEGRITY
+ [IH_OS_INTEGRITY] = do_bootm_integrity,
+#endif
+};
+
+ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */
static bootm_headers_t images; /* pointers to os/initrd/fdt images */
void __board_lmb_reserve(struct lmb *lmb)
@@ -128,6 +161,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 +212,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 +313,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;
}
@@ -289,7 +329,7 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
ulong blob_end = os.end;
ulong image_start = os.image_start;
ulong image_len = os.image_len;
- uint unc_len = CFG_BOOTM_LEN;
+ uint unc_len = CONFIG_SYS_BOOTM_LEN;
const char *type_name = genimg_get_type_name (os.type);
@@ -300,8 +340,10 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
} else {
printf (" Loading %s ... ", type_name);
- memmove_wd ((void *)load,
- (void *)image_start, image_len, CHUNKSZ);
+ if (load != image_start) {
+ memmove_wd ((void *)load,
+ (void *)image_start, image_len, CHUNKSZ);
+ }
}
*load_end = load + image_len;
puts("OK\n");
@@ -310,7 +352,7 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
printf (" Uncompressing %s ... ", type_name);
if (gunzip ((void *)load, unc_len,
(uchar *)image_start, &image_len) != 0) {
- puts ("GUNZIP: uncompress or overwrite error "
+ puts ("GUNZIP: uncompress, out-of-mem or overwrite error "
"- must RESET board to recover\n");
if (boot_progress)
show_boot_progress (-6);
@@ -329,7 +371,7 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
*/
int i = BZ2_bzBuffToBuffDecompress ((char*)load,
&unc_len, (char *)image_start, image_len,
- CFG_MALLOC_LEN < (4096 * 1024), 0);
+ CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
if (i != BZ_OK) {
printf ("BUNZIP2: uncompress or overwrite error %d "
"- must RESET board to recover\n", i);
@@ -347,7 +389,7 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
int ret = lzmaBuffToBuffDecompress(
(unsigned char *)load, &unc_len,
- (unsigned char *)image_start, image_start);
+ (unsigned char *)image_start, image_len);
if (ret != LZMA_RESULT_OK) {
printf ("LZMA: uncompress or overwrite error %d "
"- must RESET board to recover\n", ret);
@@ -376,15 +418,157 @@ 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;
+ boot_os_fn *boot_fn;
+
+ 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 {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ if (images.state >= state) {
+ printf ("Trying to execute a command out of order\n");
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ images.state |= state;
+ boot_fn = boot_os[images.os.os];
+
+ 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:
+ ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images);
+ if (ret)
+ printf ("cmdline subcommand not supported\n");
+ break;
+ case BOOTM_STATE_OS_BD_T:
+ ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images);
+ if (ret)
+ printf ("bdt subcommand not supported\n");
+ break;
+ case BOOTM_STATE_OS_PREP:
+ ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images);
+ if (ret)
+ printf ("prep subcommand not supported\n");
+ break;
+ case BOOTM_STATE_OS_GO:
+ disable_interrupts();
+ boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
+ break;
+ }
+
+ return ret;
+}
+
/*******************************************************************/
/* bootm - boot application image from image in memory */
/*******************************************************************/
+static int relocated = 0;
+
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
-
ulong iflag;
ulong load_end = 0;
int ret;
+ boot_os_fn *boot_fn;
+
+ /* relocate boot function table */
+ if (!relocated) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(boot_os); i++)
+ boot_os[i] += gd->reloc_off;
+ relocated = 1;
+ }
+
+ /* 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;
@@ -447,45 +631,13 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
show_boot_progress (8);
- switch (images.os.os) {
- default: /* handled by (original) Linux case */
- case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
- fixup_silent_linux();
+ if (images.os.os == IH_OS_LINUX)
+ fixup_silent_linux();
#endif
- do_bootm_linux (0, argc, argv, &images);
- break;
-
- case IH_OS_NETBSD:
- do_bootm_netbsd (0, argc, argv, &images);
- break;
-#ifdef CONFIG_LYNXKDI
- case IH_OS_LYNXOS:
- do_bootm_lynxkdi (0, argc, argv, &images);
- break;
-#endif
-
- case IH_OS_RTEMS:
- do_bootm_rtems (0, argc, argv, &images);
- break;
-
-#if defined(CONFIG_CMD_ELF)
- case IH_OS_VXWORKS:
- do_bootm_vxworks (0, argc, argv, &images);
- break;
-
- case IH_OS_QNX:
- do_bootm_qnxelf (0, argc, argv, &images);
- break;
-#endif
-
-#ifdef CONFIG_INTEGRITY
- case IH_OS_INTEGRITY:
- do_bootm_integrity (0, argc, argv, &images);
- break;
-#endif
- }
+ boot_fn = boot_os[images.os.os];
+ boot_fn(0, argc, argv, &images);
show_boot_progress (-9);
#ifdef DEBUG
@@ -762,8 +914,8 @@ static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]
}
U_BOOT_CMD(
- bootm, CFG_MAXARGS, 1, do_bootm,
- "bootm - boot application image from memory\n",
+ bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
+ "boot application image from memory",
"[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
@@ -782,6 +934,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"
);
/*******************************************************************/
@@ -792,7 +959,7 @@ int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int rcode = 0;
-#ifndef CFG_HUSH_PARSER
+#ifndef CONFIG_SYS_HUSH_PARSER
if (run_command (getenv ("bootcmd"), flag) < 0)
rcode = 1;
#else
@@ -805,14 +972,14 @@ int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
U_BOOT_CMD(
boot, 1, 1, do_bootd,
- "boot - boot default, i.e., run 'bootcmd'\n",
+ "boot default, i.e., run 'bootcmd'",
NULL
);
/* keep old command name "bootd" for backward compatibility */
U_BOOT_CMD(
bootd, 1, 1, do_bootd,
- "bootd - boot default, i.e., run 'bootcmd'\n",
+ "boot default, i.e., run 'bootcmd'",
NULL
);
@@ -896,8 +1063,8 @@ static int image_info (ulong addr)
}
U_BOOT_CMD(
- iminfo, CFG_MAXARGS, 1, do_iminfo,
- "iminfo - print header information for application image\n",
+ iminfo, CONFIG_SYS_MAXARGS, 1, do_iminfo,
+ "print header information for application image",
"addr [addr ...]\n"
" - print header information for application image starting at\n"
" address 'addr' in memory; this includes verification of the\n"
@@ -917,7 +1084,7 @@ int do_imls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
void *hdr;
for (i = 0, info = &flash_info[0];
- i < CFG_MAX_FLASH_BANKS; ++i, ++info) {
+ i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
if (info->flash_id == FLASH_UNKNOWN)
goto next_bank;
@@ -965,7 +1132,7 @@ next_bank: ;
U_BOOT_CMD(
imls, 1, 1, do_imls,
- "imls - list all images found in flash\n",
+ "list all images found in flash",
"\n"
" - Prints information about all images found at sector\n"
" boundaries in flash.\n"
@@ -1012,6 +1179,7 @@ static void fixup_silent_linux ()
/* OS booting routines */
/*******************************************************************/
+#ifdef CONFIG_BOOTM_NETBSD
static int do_bootm_netbsd (int flag, int argc, char *argv[],
bootm_headers_t *images)
{
@@ -1021,6 +1189,9 @@ static int do_bootm_netbsd (int flag, int argc, char *argv[],
char *consdev;
char *cmdline;
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
#if defined(CONFIG_FIT)
if (!images->legacy_hdr_valid) {
fit_unsupported_reset ("NetBSD");
@@ -1094,6 +1265,7 @@ static int do_bootm_netbsd (int flag, int argc, char *argv[],
return 1;
}
+#endif /* CONFIG_BOOTM_NETBSD*/
#ifdef CONFIG_LYNXKDI
static int do_bootm_lynxkdi (int flag, int argc, char *argv[],
@@ -1101,6 +1273,9 @@ static int do_bootm_lynxkdi (int flag, int argc, char *argv[],
{
image_header_t *hdr = &images->legacy_hdr_os_copy;
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
#if defined(CONFIG_FIT)
if (!images->legacy_hdr_valid) {
fit_unsupported_reset ("Lynx");
@@ -1114,11 +1289,15 @@ static int do_bootm_lynxkdi (int flag, int argc, char *argv[],
}
#endif /* CONFIG_LYNXKDI */
+#ifdef CONFIG_BOOTM_RTEMS
static int do_bootm_rtems (int flag, int argc, char *argv[],
bootm_headers_t *images)
{
void (*entry_point)(bd_t *);
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
#if defined(CONFIG_FIT)
if (!images->legacy_hdr_valid) {
fit_unsupported_reset ("RTEMS");
@@ -1141,6 +1320,7 @@ static int do_bootm_rtems (int flag, int argc, char *argv[],
return 1;
}
+#endif /* CONFIG_BOOTM_RTEMS */
#if defined(CONFIG_CMD_ELF)
static int do_bootm_vxworks (int flag, int argc, char *argv[],
@@ -1148,6 +1328,9 @@ static int do_bootm_vxworks (int flag, int argc, char *argv[],
{
char str[80];
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
#if defined(CONFIG_FIT)
if (!images->legacy_hdr_valid) {
fit_unsupported_reset ("VxWorks");
@@ -1168,6 +1351,9 @@ static int do_bootm_qnxelf(int flag, int argc, char *argv[],
char *local_args[2];
char str[16];
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
#if defined(CONFIG_FIT)
if (!images->legacy_hdr_valid) {
fit_unsupported_reset ("QNX");
@@ -1190,6 +1376,9 @@ static int do_bootm_integrity (int flag, int argc, char *argv[],
{
void (*entry_point)(void);
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
#if defined(CONFIG_FIT)
if (!images->legacy_hdr_valid) {
fit_unsupported_reset ("INTEGRITY");