aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-12-07 17:16:23 -0500
committerTom Rini <trini@konsulko.com>2020-12-07 17:16:23 -0500
commitcd833de0593fa2346dddab21eff6ccf2411380d3 (patch)
treef87835b392c62414199e5fb926d0f4f63d92ec9e /common
parent5157ea526142ace7b0b19939b0d31ace4276cda7 (diff)
parent51bb33846ad2b045799d2c43ca773fafa36e6ec8 (diff)
downloadu-boot-cd833de0593fa2346dddab21eff6ccf2411380d3.zip
u-boot-cd833de0593fa2346dddab21eff6ccf2411380d3.tar.gz
u-boot-cd833de0593fa2346dddab21eff6ccf2411380d3.tar.bz2
Merge branch '2020-12-07-bootm-and-spl-atf-improvements' into next
- Series to improve "bootm" by allowing variable evaluation within the cmdline we would be passing. This will help with Chrome OS but can be useful elsewhere. - Improve ATF (TF-A) support within SPL.
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig.boot17
-rw-r--r--common/bootm.c172
-rw-r--r--common/cli_simple.c17
-rw-r--r--common/spl/Kconfig9
-rw-r--r--common/spl/spl_atf.c129
5 files changed, 298 insertions, 46 deletions
diff --git a/common/Kconfig.boot b/common/Kconfig.boot
index 3f6d9c1..58e9854 100644
--- a/common/Kconfig.boot
+++ b/common/Kconfig.boot
@@ -865,6 +865,23 @@ config BOOTARGS
CONFIG_BOOTARGS goes into the environment value "bootargs". Note that
this value will also override the "chosen" node in FDT blob.
+config BOOTARGS_SUBST
+ bool "Support substituting strings in boot arguments"
+ help
+ This allows substituting string values in the boot arguments. These
+ are applied after the commandline has been built.
+
+ One use for this is to insert the root-disk UUID into the command
+ line where bootargs contains "root=${uuid}"
+
+ setenv bootargs "console= root=${uuid}"
+ # Set the 'uuid' environment variable
+ part uuid mmc 2:2 uuid
+
+ # Command-line substitution will put the real uuid into the
+ # kernel command line
+ bootm
+
config USE_BOOTCOMMAND
bool "Enable a default value for bootcmd"
help
diff --git a/common/bootm.c b/common/bootm.c
index 167eea4..8298693 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -7,6 +7,7 @@
#ifndef USE_HOSTCC
#include <common.h>
#include <bootstage.h>
+#include <cli.h>
#include <cpu_func.h>
#include <env.h>
#include <errno.h>
@@ -19,6 +20,7 @@
#include <net.h>
#include <asm/cache.h>
#include <asm/io.h>
+#include <linux/sizes.h>
#if defined(CONFIG_CMD_USB)
#include <usb.h>
#endif
@@ -35,6 +37,8 @@
#define CONFIG_SYS_BOOTM_LEN 0x800000
#endif
+#define MAX_CMDLINE_SIZE SZ_4K
+
#define IH_INITRD_ARCH IH_ARCH_DEFAULT
#ifndef USE_HOSTCC
@@ -465,19 +469,35 @@ ulong bootm_disable_interrupts(void)
return iflag;
}
-#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
-
-#define CONSOLE_ARG "console="
-#define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1)
+#define CONSOLE_ARG "console="
+#define CONSOLE_ARG_SIZE sizeof(CONSOLE_ARG)
-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:
*
* no - we never fixup
@@ -486,44 +506,132 @@ static void fixup_silent_linux(void)
*/
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;
+}
- env_set("bootargs", env_val);
- debug("after silent fix-up: %s\n", env_val);
+/**
+ * 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;
+}
+
+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.
@@ -627,10 +735,12 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
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);
}
diff --git a/common/cli_simple.c b/common/cli_simple.c
index 7d91316..e80ba48 100644
--- a/common/cli_simple.c
+++ b/common/cli_simple.c
@@ -60,13 +60,14 @@ int cli_simple_parse_line(char *line, char *argv[])
return nargs;
}
-void cli_simple_process_macros(const char *input, char *output)
+int cli_simple_process_macros(const char *input, char *output, int max_size)
{
char c, prev;
const char *varname_start = NULL;
int inputcnt = strlen(input);
- int outputcnt = CONFIG_SYS_CBSIZE;
+ int outputcnt = max_size;
int state = 0; /* 0 = waiting for '$' */
+ int ret;
/* 1 = waiting for '(' or '{' */
/* 2 = waiting for ')' or '}' */
@@ -157,13 +158,18 @@ void cli_simple_process_macros(const char *input, char *output)
prev = c;
}
- if (outputcnt)
+ ret = inputcnt ? -ENOSPC : 0;
+ if (outputcnt) {
*output = 0;
- else
+ } else {
*(output - 1) = 0;
+ ret = -ENOSPC;
+ }
debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
strlen(output_start), output_start);
+
+ return ret;
}
/*
@@ -239,7 +245,8 @@ int cli_simple_run_command(const char *cmd, int flag)
debug_parser("token: \"%s\"\n", token);
/* find macros in this token and replace them */
- cli_simple_process_macros(token, finaltoken);
+ cli_simple_process_macros(token, finaltoken,
+ sizeof(finaltoken));
/* Extract arguments */
argc = cli_simple_parse_line(finaltoken, argv);
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index d8086bd..6d980be 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1276,6 +1276,15 @@ config SPL_ATF
is loaded by SPL (which is considered as BL2 in ATF terminology).
More detail at: https://github.com/ARM-software/arm-trusted-firmware
+config SPL_ATF_LOAD_IMAGE_V2
+ bool "Use the new LOAD_IMAGE_V2 parameter passing"
+ depends on SPL_ATF
+ help
+ Some platforms use the newer LOAD_IMAGE_V2 parameter passing.
+
+ If you want to load a bl31 image from the SPL and need the new
+ method, say Y.
+
config SPL_ATF_NO_PLATFORM_PARAM
bool "Pass no platform parameter"
depends on SPL_ATF
diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c
index 9bd25f6..e1b68dd 100644
--- a/common/spl/spl_atf.c
+++ b/common/spl/spl_atf.c
@@ -18,13 +18,36 @@
#include <spl.h>
#include <asm/cache.h>
-static struct bl2_to_bl31_params_mem bl31_params_mem;
-static struct bl31_params *bl2_to_bl31_params;
-
-__weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
- uintptr_t bl33_entry,
- uintptr_t fdt_addr)
+/* Holds all the structures we need for bl31 parameter passing */
+struct bl2_to_bl31_params_mem {
+ struct bl31_params bl31_params;
+ struct atf_image_info bl31_image_info;
+ struct atf_image_info bl32_image_info;
+ struct atf_image_info bl33_image_info;
+ struct entry_point_info bl33_ep_info;
+ struct entry_point_info bl32_ep_info;
+ struct entry_point_info bl31_ep_info;
+};
+
+struct bl2_to_bl31_params_mem_v2 {
+ struct bl_params bl_params;
+ struct bl_params_node bl31_params_node;
+ struct bl_params_node bl32_params_node;
+ struct bl_params_node bl33_params_node;
+ struct atf_image_info bl31_image_info;
+ struct atf_image_info bl32_image_info;
+ struct atf_image_info bl33_image_info;
+ struct entry_point_info bl33_ep_info;
+ struct entry_point_info bl32_ep_info;
+ struct entry_point_info bl31_ep_info;
+};
+
+struct bl31_params *bl2_plat_get_bl31_params_default(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
{
+ static struct bl2_to_bl31_params_mem bl31_params_mem;
+ struct bl31_params *bl2_to_bl31_params;
struct entry_point_info *bl32_ep_info;
struct entry_point_info *bl33_ep_info;
@@ -78,6 +101,87 @@ __weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
return bl2_to_bl31_params;
}
+__weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ return bl2_plat_get_bl31_params_default(bl32_entry, bl33_entry,
+ fdt_addr);
+}
+
+struct bl_params *bl2_plat_get_bl31_params_v2_default(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ static struct bl2_to_bl31_params_mem_v2 bl31_params_mem;
+ struct bl_params *bl_params;
+ struct bl_params_node *bl_params_node;
+
+ /*
+ * Initialise the memory for all the arguments that needs to
+ * be passed to BL31
+ */
+ memset(&bl31_params_mem, 0, sizeof(bl31_params_mem));
+
+ /* Assign memory for TF related information */
+ bl_params = &bl31_params_mem.bl_params;
+ SET_PARAM_HEAD(bl_params, ATF_PARAM_BL_PARAMS, ATF_VERSION_2, 0);
+ bl_params->head = &bl31_params_mem.bl31_params_node;
+
+ /* Fill BL31 related information */
+ bl_params_node = &bl31_params_mem.bl31_params_node;
+ bl_params_node->image_id = ATF_BL31_IMAGE_ID;
+ bl_params_node->image_info = &bl31_params_mem.bl31_image_info;
+ bl_params_node->ep_info = &bl31_params_mem.bl31_ep_info;
+ bl_params_node->next_params_info = &bl31_params_mem.bl32_params_node;
+ SET_PARAM_HEAD(bl_params_node->image_info, ATF_PARAM_IMAGE_BINARY,
+ ATF_VERSION_2, 0);
+
+ /* Fill BL32 related information */
+ bl_params_node = &bl31_params_mem.bl32_params_node;
+ bl_params_node->image_id = ATF_BL32_IMAGE_ID;
+ bl_params_node->image_info = &bl31_params_mem.bl32_image_info;
+ bl_params_node->ep_info = &bl31_params_mem.bl32_ep_info;
+ bl_params_node->next_params_info = &bl31_params_mem.bl33_params_node;
+ SET_PARAM_HEAD(bl_params_node->ep_info, ATF_PARAM_EP,
+ ATF_VERSION_2, ATF_EP_SECURE);
+
+ /* secure payload is optional, so set pc to 0 if absent */
+ bl_params_node->ep_info->args.arg3 = fdt_addr;
+ bl_params_node->ep_info->pc = bl32_entry ? bl32_entry : 0;
+ bl_params_node->ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXECPTIONS);
+ SET_PARAM_HEAD(bl_params_node->image_info, ATF_PARAM_IMAGE_BINARY,
+ ATF_VERSION_2, 0);
+
+ /* Fill BL33 related information */
+ bl_params_node = &bl31_params_mem.bl33_params_node;
+ bl_params_node->image_id = ATF_BL33_IMAGE_ID;
+ bl_params_node->image_info = &bl31_params_mem.bl33_image_info;
+ bl_params_node->ep_info = &bl31_params_mem.bl33_ep_info;
+ bl_params_node->next_params_info = NULL;
+ SET_PARAM_HEAD(bl_params_node->ep_info, ATF_PARAM_EP,
+ ATF_VERSION_2, ATF_EP_NON_SECURE);
+
+ /* BL33 expects to receive the primary CPU MPID (through x0) */
+ bl_params_node->ep_info->args.arg0 = 0xffff & read_mpidr();
+ bl_params_node->ep_info->pc = bl33_entry;
+ bl_params_node->ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXECPTIONS);
+ SET_PARAM_HEAD(bl_params_node->image_info, ATF_PARAM_IMAGE_BINARY,
+ ATF_VERSION_2, 0);
+
+ return bl_params;
+}
+
+__weak struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ return bl2_plat_get_bl31_params_v2_default(bl32_entry, bl33_entry,
+ fdt_addr);
+}
+
static inline void raw_write_daif(unsigned int daif)
{
__asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
@@ -88,16 +192,21 @@ typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params);
static void bl31_entry(uintptr_t bl31_entry, uintptr_t bl32_entry,
uintptr_t bl33_entry, uintptr_t fdt_addr)
{
- struct bl31_params *bl31_params;
atf_entry_t atf_entry = (atf_entry_t)bl31_entry;
+ void *bl31_params;
- bl31_params = bl2_plat_get_bl31_params(bl32_entry, bl33_entry,
- fdt_addr);
+ if (CONFIG_IS_ENABLED(ATF_LOAD_IMAGE_V2))
+ bl31_params = bl2_plat_get_bl31_params_v2(bl32_entry,
+ bl33_entry,
+ fdt_addr);
+ else
+ bl31_params = bl2_plat_get_bl31_params(bl32_entry, bl33_entry,
+ fdt_addr);
raw_write_daif(SPSR_EXCEPTION_MASK);
dcache_disable();
- atf_entry((void *)bl31_params, (void *)fdt_addr);
+ atf_entry(bl31_params, (void *)fdt_addr);
}
static int spl_fit_images_find(void *blob, int os)