#ifndef USE_HOSTCC
#include <common.h>
#include <bootstage.h>
+#include <cli.h>
+#include <cpu_func.h>
+#include <env.h>
#include <errno.h>
#include <fdt_support.h>
+#include <irq_func.h>
#include <lmb.h>
+#include <log.h>
#include <malloc.h>
#include <mapmem.h>
+#include <net.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
#include <asm/io.h>
+#include <linux/sizes.h>
#if defined(CONFIG_CMD_USB)
#include <usb.h>
#endif
#define CONFIG_SYS_BOOTM_LEN 0x800000
#endif
+#define MAX_CMDLINE_SIZE SZ_4K
+
#define IH_INITRD_ARCH IH_ARCH_DEFAULT
#ifndef USE_HOSTCC
bootm_headers_t images; /* pointers to os/initrd/fdt images */
-static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
- char * const argv[], bootm_headers_t *images,
+static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], bootm_headers_t *images,
ulong *os_data, ulong *os_len);
__weak void board_quiesce_devices(void)
static inline void boot_start_lmb(bootm_headers_t *images) { }
#endif
-static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc,
- char * const argv[])
+static int bootm_start(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
{
memset((void *)&images, 0, sizeof(images));
images.verify = env_get_yesno("verify");
return 0;
}
-static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
- char * const argv[])
+static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
{
const void *os_hdr;
bool ep_found = false;
* @flag: Ignored Argument
* @argc: command argument count
* @argv: command argument list
+ * @start: OS image start address
+ * @size: OS image size
*
* boot_find_images() will attempt to load an available ramdisk,
* flattened device tree, as well as specifically marked
* 0, if all existing images were loaded correctly
* 1, if an image is found but corrupted, or invalid
*/
-int bootm_find_images(int flag, int argc, char * const argv[])
+int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
+ ulong size)
{
int ret;
return 1;
}
+ /* check if ramdisk overlaps OS image */
+ if (images.rd_start && (((ulong)images.rd_start >= start &&
+ (ulong)images.rd_start < start + size) ||
+ ((ulong)images.rd_end > start &&
+ (ulong)images.rd_end <= start + size) ||
+ ((ulong)images.rd_start < start &&
+ (ulong)images.rd_end >= start + size))) {
+ printf("ERROR: RD image overlaps OS image (OS=0x%lx..0x%lx)\n",
+ start, start + size);
+ return 1;
+ }
+
#if IMAGE_ENABLE_OF_LIBFDT
/* find flattened device tree */
ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
puts("Could not find a valid device tree\n");
return 1;
}
+
+ /* check if FDT overlaps OS image */
+ if (images.ft_addr &&
+ (((ulong)images.ft_addr >= start &&
+ (ulong)images.ft_addr <= start + size) ||
+ ((ulong)images.ft_addr + images.ft_len >= start &&
+ (ulong)images.ft_addr + images.ft_len <= start + size))) {
+ printf("ERROR: FDT image overlaps OS image (OS=0x%lx..0x%lx)\n",
+ start, start + size);
+ return 1;
+ }
+
if (CONFIG_IS_ENABLED(CMD_FDT))
set_working_fdt_addr(map_to_sysmem(images.ft_addr));
#endif
return 0;
}
-static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
- char * const argv[])
+static int bootm_find_other(struct cmd_tbl *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 ||
images.os.os == IH_OS_VXWORKS))
- return bootm_find_images(flag, argc, argv);
+ return bootm_find_images(flag, argc, argv, 0, 0);
return 0;
}
bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
return err;
}
+ /* We need the decompressed image size in the next steps */
+ images->os.image_len = load_end - load;
flush_cache(flush_start, ALIGN(load_end, ARCH_DMA_MINALIGN) - flush_start);
return iflag;
}
-#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
+#define CONSOLE_ARG "console="
+#define CONSOLE_ARG_SIZE sizeof(CONSOLE_ARG)
-#define CONSOLE_ARG "console="
-#define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1)
-
-static void fixup_silent_linux(void)
+/**
+ * fixup_silent_linux() - Handle silencing the linux boot if required
+ *
+ * This uses the silent_linux envvar to control whether to add/set a "console="
+ * parameter to the command line
+ *
+ * @buf: Buffer containing the string to process
+ * @maxlen: Maximum length of buffer
+ * @return 0 if OK, -ENOSPC if @maxlen is too small
+ */
+static int fixup_silent_linux(char *buf, int maxlen)
{
- char *buf;
- const char *env_val;
- char *cmdline = env_get("bootargs");
int want_silent;
+ char *cmdline;
+ int size;
+ /*
+ * Move the input string to the end of buffer. The output string will be
+ * built up at the start.
+ */
+ size = strlen(buf) + 1;
+ if (size * 2 > maxlen)
+ return -ENOSPC;
+ cmdline = buf + maxlen - size;
+ memmove(cmdline, buf, size);
/*
* Only fix cmdline when requested. The environment variable can be:
*
*/
want_silent = env_get_yesno("silent_linux");
if (want_silent == 0)
- return;
+ return 0;
else if (want_silent == -1 && !(gd->flags & GD_FLG_SILENT))
- return;
+ return 0;
debug("before silent fix-up: %s\n", cmdline);
- if (cmdline && (cmdline[0] != '\0')) {
+ if (*cmdline) {
char *start = strstr(cmdline, CONSOLE_ARG);
- /* Allocate space for maximum possible new command line */
- buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_LEN + 1);
- if (!buf) {
- debug("%s: out of memory\n", __func__);
- return;
- }
+ /* Check space for maximum possible new command line */
+ if (size + CONSOLE_ARG_SIZE > maxlen)
+ return -ENOSPC;
if (start) {
char *end = strchr(start, ' ');
- int num_start_bytes = start - cmdline + CONSOLE_ARG_LEN;
+ int start_bytes;
- strncpy(buf, cmdline, num_start_bytes);
+ start_bytes = start - cmdline + CONSOLE_ARG_SIZE - 1;
+ strncpy(buf, cmdline, start_bytes);
if (end)
- strcpy(buf + num_start_bytes, end);
+ strcpy(buf + start_bytes, end);
else
- buf[num_start_bytes] = '\0';
+ buf[start_bytes] = '\0';
} else {
sprintf(buf, "%s %s", cmdline, CONSOLE_ARG);
}
- env_val = buf;
+ if (buf + strlen(buf) >= cmdline)
+ return -ENOSPC;
} else {
- buf = NULL;
- env_val = CONSOLE_ARG;
+ if (maxlen < sizeof(CONSOLE_ARG))
+ return -ENOSPC;
+ strcpy(buf, CONSOLE_ARG);
+ }
+ debug("after silent fix-up: %s\n", buf);
+
+ return 0;
+}
+
+/**
+ * process_subst() - Handle substitution of ${...} fields in the environment
+ *
+ * Handle variable substitution in the provided buffer
+ *
+ * @buf: Buffer containing the string to process
+ * @maxlen: Maximum length of buffer
+ * @return 0 if OK, -ENOSPC if @maxlen is too small
+ */
+static int process_subst(char *buf, int maxlen)
+{
+ char *cmdline;
+ int size;
+ int ret;
+
+ /* Move to end of buffer */
+ size = strlen(buf) + 1;
+ cmdline = buf + maxlen - size;
+ if (buf + size > cmdline)
+ return -ENOSPC;
+ memmove(cmdline, buf, size);
+
+ ret = cli_simple_process_macros(cmdline, buf, cmdline - buf);
+
+ return ret;
+}
+
+int bootm_process_cmdline(char *buf, int maxlen, int flags)
+{
+ int ret;
+
+ /* Check config first to enable compiler to eliminate code */
+ if (IS_ENABLED(CONFIG_SILENT_CONSOLE) &&
+ !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) &&
+ (flags & BOOTM_CL_SILENT)) {
+ ret = fixup_silent_linux(buf, maxlen);
+ if (ret)
+ return log_msg_ret("silent", ret);
}
+ if (IS_ENABLED(CONFIG_BOOTARGS_SUBST) && (flags & BOOTM_CL_SUBST)) {
+ ret = process_subst(buf, maxlen);
+ if (ret)
+ return log_msg_ret("silent", ret);
+ }
+
+ return 0;
+}
- env_set("bootargs", env_val);
- debug("after silent fix-up: %s\n", env_val);
+int bootm_process_cmdline_env(int flags)
+{
+ const int maxlen = MAX_CMDLINE_SIZE;
+ bool do_silent;
+ const char *env;
+ char *buf;
+ int ret;
+
+ /* First check if any action is needed */
+ do_silent = IS_ENABLED(CONFIG_SILENT_CONSOLE) &&
+ !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && (flags & BOOTM_CL_SILENT);
+ if (!do_silent && !IS_ENABLED(CONFIG_BOOTARGS_SUBST))
+ return 0;
+
+ env = env_get("bootargs");
+ if (env && strlen(env) >= maxlen)
+ return -E2BIG;
+ buf = malloc(maxlen);
+ if (!buf)
+ return -ENOMEM;
+ if (env)
+ strcpy(buf, env);
+ else
+ *buf = '\0';
+ ret = bootm_process_cmdline(buf, maxlen, flags);
+ if (!ret) {
+ ret = env_set("bootargs", buf);
+
+ /*
+ * If buf is "" and bootargs does not exist, this will produce
+ * an error trying to delete bootargs. Ignore it
+ */
+ if (ret == -ENOENT)
+ ret = 0;
+ }
free(buf);
+ if (ret)
+ return log_msg_ret("env", ret);
+
+ return 0;
}
-#endif /* CONFIG_SILENT_CONSOLE */
/**
* Execute selected states of the bootm command.
* then the intent is to boot an OS, so this function will not return
* unless the image type is standalone.
*/
-int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
- int states, bootm_headers_t *images, int boot_progress)
+int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int states, bootm_headers_t *images,
+ int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
if (!ret && (states & BOOTM_STATE_OS_BD_T))
ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_PREP)) {
-#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
- if (images->os.os == IH_OS_LINUX)
- fixup_silent_linux();
-#endif
+ ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX);
+ if (ret) {
+ printf("Cmdline setup failed (err=%d)\n", ret);
+ ret = CMD_RET_FAILURE;
+ goto err;
+ }
ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
}
* pointer to image header if valid image was found, plus kernel start
* address and length, otherwise NULL
*/
-static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
- char * const argv[], bootm_headers_t *images,
+static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], bootm_headers_t *images,
ulong *os_data, ulong *os_len)
{
#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
#else /* USE_HOSTCC */
#if defined(CONFIG_FIT_SIGNATURE)
-static int bootm_host_load_image(const void *fit, int req_image_type)
+static int bootm_host_load_image(const void *fit, int req_image_type,
+ int cfg_noffset)
{
const char *fit_uname_config = NULL;
ulong data, len;
void *load_buf;
int ret;
+ fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
memset(&images, '\0', sizeof(images));
images.verify = 1;
noffset = fit_image_load(&images, (ulong)fit,
for (i = 0; i < ARRAY_SIZE(image_types); i++) {
int ret;
- ret = bootm_host_load_image(fit, image_types[i]);
+ ret = bootm_host_load_image(fit, image_types[i], cfg_noffset);
if (!err && ret && ret != -ENOENT)
err = ret;
}