* (C) Copyright 2000-2009
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
return 0;
}
-static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
- char * const argv[])
+static int bootm_find_ramdisk(int flag, int argc, char * const argv[])
+{
+ int ret;
+
+ /* find ramdisk */
+ ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
+ &images.rd_start, &images.rd_end);
+ if (ret) {
+ puts("Ramdisk image is corrupt or invalid\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+static int bootm_find_fdt(int flag, int argc, char * const argv[])
{
int ret;
+ /* find flattened device tree */
+ ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
+ &images.ft_addr, &images.ft_len);
+ if (ret) {
+ puts("Could not find a valid device tree\n");
+ return 1;
+ }
+
+ set_working_fdt_addr(images.ft_addr);
+
+ return 0;
+}
+#endif
+
+static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
if (((images.os.type == IH_TYPE_KERNEL) ||
(images.os.type == IH_TYPE_KERNEL_NOLOAD) ||
(images.os.type == IH_TYPE_MULTI)) &&
(images.os.os == IH_OS_LINUX)) {
- /* find ramdisk */
- ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
- &images.rd_start, &images.rd_end);
- if (ret) {
- puts("Ramdisk image is corrupt or invalid\n");
+ if (bootm_find_ramdisk(flag, argc, argv))
return 1;
- }
#if defined(CONFIG_OF_LIBFDT)
- /* find flattened device tree */
- ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
- &images.ft_addr, &images.ft_len);
- if (ret) {
- puts("Could not find a valid device tree\n");
+ if (bootm_find_fdt(flag, argc, argv))
return 1;
- }
-
- set_working_fdt_addr(images.ft_addr);
#endif
}
#define BOOTM_ERR_RESET -1
#define BOOTM_ERR_OVERLAP -2
#define BOOTM_ERR_UNIMPLEMENTED -3
-static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
+static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end,
+ int boot_progress)
{
+ image_info_t os = images->os;
uint8_t comp = os.comp;
ulong load = os.load;
ulong blob_start = os.start;
const char *type_name = genimg_get_type_name(os.type);
- load_buf = map_sysmem(load, image_len);
+ load_buf = map_sysmem(load, unc_len);
image_buf = map_sysmem(image_start, image_len);
switch (comp) {
case IH_COMP_NONE:
memmove_wd(load_buf, image_buf, image_len, CHUNKSZ);
}
*load_end = load + image_len;
- puts("OK\n");
break;
#ifdef CONFIG_GZIP
case IH_COMP_GZIP:
}
#endif /* CONFIG_LZMA */
#ifdef CONFIG_LZO
- case IH_COMP_LZO:
+ case IH_COMP_LZO: {
+ size_t size;
+
printf(" Uncompressing %s ... ", type_name);
- ret = lzop_decompress(image_buf, image_len, load_buf,
- &unc_len);
+ ret = lzop_decompress(image_buf, image_len, load_buf, &size);
if (ret != LZO_E_OK) {
printf("LZO: uncompress or overwrite error %d "
"- must RESET board to recover\n", ret);
return BOOTM_ERR_RESET;
}
- *load_end = load + unc_len;
+ *load_end = load + size;
break;
+ }
#endif /* CONFIG_LZO */
default:
printf("Unimplemented compression type %d\n", comp);
debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load,
*load_end);
- return BOOTM_ERR_OVERLAP;
+ /* Check what type of image this is. */
+ if (images->legacy_hdr_valid) {
+ if (image_get_type(&images->legacy_hdr_os_copy)
+ == IH_TYPE_MULTI)
+ puts("WARNING: legacy format multi component image overwritten\n");
+ return BOOTM_ERR_OVERLAP;
+ } else {
+ puts("ERROR: new format image overwritten - must RESET the board to recover\n");
+ bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
+ return BOOTM_ERR_RESET;
+ }
}
return 0;
};
static int boot_selected_os(int argc, char * const argv[], int state,
- bootm_headers_t *images, boot_os_fn *boot_fn, ulong *iflag)
+ bootm_headers_t *images, boot_os_fn *boot_fn)
{
if (images->os.type == IH_TYPE_STANDALONE) {
/* This may return when 'autostart' is 'no' */
bootm_start_standalone(argc, argv);
return 0;
}
+ arch_preboot_os();
+ boot_fn(state, argc, argv, images);
+ if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
+ return 0;
+ bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
+#ifdef DEBUG
+ puts("\n## Control returned to monitor - resetting...\n");
+#endif
+ return BOOTM_ERR_RESET;
+}
+
+/**
+ * bootm_disable_interrupts() - Disable interrupts in preparation for load/boot
+ *
+ * @return interrupt flag (0 if interrupts were disabled, non-zero if they were
+ * enabled)
+ */
+static ulong bootm_disable_interrupts(void)
+{
+ ulong iflag;
+
/*
* We have reached the point of no return: we are going to
* overwrite all exception vector code, so we cannot easily
* recover from any failures any more...
*/
- *iflag = disable_interrupts();
+ iflag = disable_interrupts();
#ifdef CONFIG_NETCONSOLE
/* Stop the ethernet stack if NetConsole could have left it up */
eth_halt();
*/
usb_stop();
#endif
-#ifdef CONFIG_SILENT_CONSOLE
- if (images->os.os == IH_OS_LINUX)
- fixup_silent_linux();
-#endif
- arch_preboot_os();
- boot_fn(state, argc, argv, images);
- if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
- return 0;
- bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
-#ifdef DEBUG
- puts("\n## Control returned to monitor - resetting...\n");
-#endif
- return BOOTM_ERR_RESET;
+ return iflag;
}
/**
* Note that if states contains more than one flag it MUST contain
* BOOTM_STATE_START, since this handles and consumes the command line args.
*
+ * Also note that aside from boot_os_fn functions and bootm_load_os no other
+ * functions we store the return value of in 'ret' may use a negative return
+ * value, without special handling.
+ *
* @param cmdtp Pointer to bootm command table entry
* @param flag Command flags (CMD_FLAG_...)
* @param argc Number of subcommand arguments (0 = no arguments)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
- int ret = 0;
+ int ret = 0, need_boot_fn;
images->state |= states;
if (!ret && (states & BOOTM_STATE_LOADOS)) {
ulong load_end;
- ret = bootm_load_os(images->os, &load_end, 0);
- if (!ret) {
+ iflag = bootm_disable_interrupts();
+ ret = bootm_load_os(images, &load_end, 0);
+ if (ret == 0)
lmb_reserve(&images->lmb, images->os.load,
(load_end - images->os.load));
- }
+ else if (ret && ret != BOOTM_ERR_OVERLAP)
+ goto err;
+ else if (ret == BOOTM_ERR_OVERLAP)
+ ret = 0;
+#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
+ if (images->os.os == IH_OS_LINUX)
+ fixup_silent_linux();
+#endif
}
/* Relocate the ramdisk */
if (ret)
return ret;
boot_fn = boot_os[images->os.os];
- if (boot_fn == NULL) {
+ need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
+ BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
+ BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
+ if (boot_fn == NULL && need_boot_fn) {
if (iflag)
enable_interrupts();
printf("ERROR: booting os '%s' (%d) is not supported\n",
char *cmd_list = getenv("fakegocmd");
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
- images, boot_fn, &iflag);
+ images, boot_fn);
if (!ret && cmd_list)
ret = run_command_list(cmd_list, -1, flag);
}
#endif
+
+ /* Check for unsupported subcommand. */
+ if (ret) {
+ puts("subcommand not supported\n");
+ return ret;
+ }
+
/* Now run the OS! We hope this doesn't return */
if (!ret && (states & BOOTM_STATE_OS_GO))
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
- images, boot_fn, &iflag);
+ images, boot_fn);
/* Deal with any fallout */
- if (ret < 0) {
- if (ret == BOOTM_ERR_UNIMPLEMENTED) {
- if (iflag)
- enable_interrupts();
- bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
- return 1;
- } else if (ret == BOOTM_ERR_OVERLAP) {
- if (images->legacy_hdr_valid) {
- if (image_get_type(&images->legacy_hdr_os_copy)
- == IH_TYPE_MULTI)
- puts("WARNING: legacy format multi component image overwritten\n");
- } else {
- puts("ERROR: new format image overwritten - must RESET the board to recover\n");
- bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
- ret = BOOTM_ERR_RESET;
- }
- }
- if (ret == BOOTM_ERR_RESET)
- do_reset(cmdtp, flag, argc, argv);
- }
+err:
if (iflag)
enable_interrupts();
- if (ret)
- puts("subcommand not supported\n");
+
+ if (ret == BOOTM_ERR_UNIMPLEMENTED)
+ bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
+ else if (ret == BOOTM_ERR_RESET)
+ do_reset(cmdtp, flag, argc, argv);
return ret;
}
case IMAGE_FORMAT_FIT:
os_noffset = fit_image_load(images, FIT_KERNEL_PROP,
img_addr,
- &fit_uname_kernel, fit_uname_config,
+ &fit_uname_kernel, &fit_uname_config,
IH_ARCH_DEFAULT, IH_TYPE_KERNEL,
BOOTSTAGE_ID_FIT_KERNEL_START,
FIT_LOAD_IGNORED, os_data, os_len);
images->fit_hdr_os = map_sysmem(img_addr, 0);
images->fit_uname_os = fit_uname_kernel;
+ images->fit_uname_cfg = fit_uname_config;
images->fit_noffset_os = os_noffset;
break;
#endif
char *buf;
const char *env_val;
char *cmdline = getenv("bootargs");
+ int want_silent;
- /* Only fix cmdline when requested */
- if (!(gd->flags & GD_FLG_SILENT))
+ /*
+ * Only fix cmdline when requested. The environment variable can be:
+ *
+ * no - we never fixup
+ * yes - we always fixup
+ * unset - we rely on the console silent flag
+ */
+ want_silent = getenv_yesno("silent_linux");
+ if (want_silent == 0)
+ return;
+ else if (want_silent == -1 && !(gd->flags & GD_FLG_SILENT))
return;
debug("before silent fix-up: %s\n", cmdline);
}
#endif /* CONFIG_SILENT_CONSOLE */
+#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9)
+static void copy_args(char *dest, int argc, char * const argv[], char delim)
+{
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (i > 0)
+ *dest++ = delim;
+ strcpy(dest, argv[i]);
+ dest += strlen(argv[i]);
+ }
+}
+#endif
/*******************************************************************/
/* OS booting routines */
char *consdev;
char *cmdline;
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
for (i = 0, len = 0; i < argc; i += 1)
len += strlen(argv[i]) + 1;
cmdline = malloc(len);
-
- for (i = 0, len = 0; i < argc; i += 1) {
- if (i > 0)
- cmdline[len++] = ' ';
- strcpy(&cmdline[len], argv[i]);
- len += strlen(argv[i]);
- }
+ copy_args(cmdline, argc, argv, ' ');
} else if ((cmdline = getenv("bootargs")) == NULL) {
cmdline = "";
}
{
image_header_t *hdr = &images->legacy_hdr_os_copy;
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
{
void (*entry_point)(bd_t *);
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
{
void (*entry_point)(void);
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
bootm_headers_t *images)
{
void (*entry_point)(void);
+ char *s;
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
}
#endif
+ /* See README.plan9 */
+ s = getenv("confaddr");
+ if (s != NULL) {
+ char *confaddr = (char *)simple_strtoul(s, NULL, 16);
+
+ if (argc > 0) {
+ copy_args(confaddr, argc, argv, '\n');
+ } else {
+ s = getenv("bootargs");
+ if (s != NULL)
+ strcpy(confaddr, s);
+ }
+ }
+
entry_point = (void (*)(void))images->ep;
printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
{
char str[80];
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
char *local_args[2];
char str[16];
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
{
void (*entry_point)(void);
+ if (flag & BOOTM_STATE_OS_PREP)
+ return 0;
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
#ifdef CONFIG_CMD_BOOTZ
-static int __bootz_setup(void *image, void **start, void **end)
+int __weak bootz_setup(ulong image, ulong *start, ulong *end)
{
/* Please define bootz_setup() for your platform */
puts("Your platform's zImage format isn't supported yet!\n");
return -1;
}
-int bootz_setup(void *image, void **start, void **end)
- __attribute__((weak, alias("__bootz_setup")));
/*
* zImage booting support
char * const argv[], bootm_headers_t *images)
{
int ret;
- void *zi_start, *zi_end;
+ ulong zi_start, zi_end;
ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
images, 1);
/* Setup Linux kernel zImage entry point */
- if (argc < 2) {
+ if (!argc) {
images->ep = load_addr;
debug("* kernel: default image load address = 0x%08lx\n",
load_addr);
} else {
- images->ep = simple_strtoul(argv[1], NULL, 16);
+ images->ep = simple_strtoul(argv[0], NULL, 16);
debug("* kernel: cmdline image address = 0x%08lx\n",
images->ep);
}
- ret = bootz_setup((void *)images->ep, &zi_start, &zi_end);
+ ret = bootz_setup(images->ep, &zi_start, &zi_end);
if (ret != 0)
return 1;
lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);
- ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_FINDOTHER,
- images, 1);
+ /*
+ * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
+ * have a header that provide this informaiton.
+ */
+ if (bootm_find_ramdisk(flag, argc, argv))
+ return 1;
- return ret;
+#if defined(CONFIG_OF_LIBFDT)
+ if (bootm_find_fdt(flag, argc, argv))
+ return 1;
+#endif
+
+ return 0;
}
int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- bootm_headers_t images;
int ret;
+ /* Consume 'bootz' */
+ argc--; argv++;
+
if (bootz_start(cmdtp, flag, argc, argv, &images))
return 1;
+ /*
+ * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
+ * disable interrupts ourselves
+ */
+ bootm_disable_interrupts();
+
+ images.os.os = IH_OS_LINUX;
ret = do_bootm_states(cmdtp, flag, argc, argv,
- BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO,
+ BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
+ BOOTM_STATE_OS_GO,
&images, 1);
return ret;