bootm: Add subcommands

Add the ability to break the steps of the bootm command into several
subcommands: start, loados, ramdisk, fdt, bdt, cmdline, prep, go.

This allows us to do things like manipulate device trees before
they are passed to a booting kernel or setup memory for a secondary
core in multicore situations.

Not all OS types support all subcommands (currently only start, loados,
ramdisk, fdt, and go are supported).

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
This commit is contained in:
Kumar Gala 2008-10-21 17:25:45 -05:00 committed by Wolfgang Denk
parent be08315933
commit 49c3a861d1
13 changed files with 219 additions and 2 deletions

View File

@ -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)
@ -296,7 +297,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;
}
@ -399,6 +400,121 @@ 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 {
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;
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 */
/*******************************************************************/
@ -419,6 +535,23 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
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;
@ -783,6 +916,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"
);
/*******************************************************************/
@ -1022,6 +1170,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");
@ -1102,6 +1253,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");
@ -1120,6 +1274,9 @@ static int do_bootm_rtems (int flag, int argc, char *argv[],
{
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");
@ -1149,6 +1306,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");
@ -1169,6 +1329,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");
@ -1191,6 +1354,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");

View File

@ -230,6 +230,7 @@ typedef struct bootm_headers {
#endif
#endif
#ifndef USE_HOSTCC
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */
@ -240,8 +241,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

View File

@ -67,6 +67,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
char *commandline = getenv ("bootargs");
#endif
if ((flag != 0) || (flag != BOOTM_STATE_OS_GO))
return 1;
theKernel = (void (*)(int, int, uint))images->ep;
s = getenv ("machid");

View File

@ -178,6 +178,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
char *commandline = getenv("bootargs");
int ret;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
theKernel = (void *)images->ep;
show_boot_progress (15);

View File

@ -36,6 +36,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
int (*appl) (char *cmdline);
char *cmdline;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
#ifdef SHARED_RESOURCES
swap_to(FLASH);
#endif

View File

@ -40,6 +40,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
size_t len;
#endif
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
if (images->legacy_hdr_valid) {
hdr = images->legacy_hdr_os;
if (image_check_type (hdr, IH_TYPE_MULTI)) {

View File

@ -76,6 +76,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
void (*kernel) (bd_t *, ulong, ulong, ulong, ulong);
struct lmb *lmb = &images->lmb;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
bootmap_base = getenv_bootm_low();
/* allocate space and init command line */

View File

@ -38,6 +38,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
void (*theKernel) (char *);
char *commandline = getenv ("bootargs");
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
theKernel = (void (*)(char *))images->ep;
show_boot_progress (15);

View File

@ -50,6 +50,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
char env_buf[12];
char *cp;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
/* find kernel entry point */
theKernel = (void (*)(int, char **, char **, int *))images->ep;

View File

@ -29,6 +29,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
void (*kernel)(void) = (void (*)(void))images->ep;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
/* For now we assume the Microtronix linux ... which only
* needs to be called ;-)
*/

View File

@ -117,6 +117,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
char *of_flat_tree = images->ft_addr;
#endif
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
kernel = (void (*)(bd_t *, ulong, ulong, ulong,
ulong, ulong, ulong))images->ep;

View File

@ -56,6 +56,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
unsigned long size = images->ep - (unsigned long)param;
char *bootargs = getenv("bootargs");
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
/* Setup parameters */
memset(param, 0, size); /* Clear zero page */
strcpy(cmdline, bootargs);

View File

@ -102,6 +102,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t * images)
struct lmb *lmb = &images->lmb;
int ret;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
/* Get virtual address of kernel start */
linux_hdr = (void *)images->os.load;