This version:
* cleans ups issues pointed out by Jerry
* adds a state machine to the command processing
* adds bd_t and cmdline process on linux for ppc
If this looks good I'll go ahead and clean it up for the other arches and OSes.
- k
Posting this again for discussion. The two features I'm interested in
enabling are:
* Having the ability to modify the device tree before its passed to
the kernel but after 'fdt boardsetup'
* Ability to do all setup but not actually jumping to the kernel.
(This is useful as a way to setup the memory image [kernel, ramdisk,
fdt, etc] for a different cpu than the boot one)
Having bootm sub-commands allows both of these as we can break up
the sequeunce of steps that are part of the bootm process.
---
common/cmd_bootm.c | 150 +-
include/image.h| 20 -
lib_ppc/bootm.c| 262 ++--
3 files changed, 338 insertions(+), 94 deletions(-)
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 19257bb..1de11c2 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#if defined(CONFIG_CMD_USB)
@@ -273,7 +274,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 +377,121 @@ static int bootm_load_os(image_info_t os, ulong
*load_end, int boot_progress)
return 0;
}
+int do_bootm_subcommand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int ret = 0;
+ int state;
+
+ /* start */
+ if (argv[1][0] == 's') {
+ argc--;
+ argv++;
+ return bootm_start(cmdtp, flag, argc, argv);
+ }
+ /* loados */
+ else if (argv[1][0] == 'l') {
+ state = BOOTM_STATE_LOADOS;
+ }
+ /* ramdisk relocate */
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
+ else if (argv[1][0] == 'r') {
+ state = BOOTM_STATE_RAMDISK;
+ }
+#endif
+#ifdef CONFIG_OF_LIBFDT
+ /* fdt relocate */
+ else if (argv[1][0] == 'f') {
+ state = BOOTM_STATE_FDT;
+ }
+#endif
+ /* bd_t setup */
+ else if (argv[1][0] == 'b') {
+ state = BOOTM_STATE_OS_BD_T;
+ }
+ /* cmdline setup */
+ else if (argv[1][0] == 'c') {
+ state = BOOTM_STATE_OS_CMDLINE;
+ }
+ /* prep os */
+ else if (argv[1][0] == 'p') {
+ state = BOOTM_STATE_OS_PREP;
+ }
+ /* go */
+ else if (argv[1][0] == 'g') {
+ state = BOOTM_STATE_OS_GO;
+ }
+ /* 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;