diff options
author | Tom Rini <trini@konsulko.com> | 2020-12-07 17:16:23 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-12-07 17:16:23 -0500 |
commit | cd833de0593fa2346dddab21eff6ccf2411380d3 (patch) | |
tree | f87835b392c62414199e5fb926d0f4f63d92ec9e /common | |
parent | 5157ea526142ace7b0b19939b0d31ace4276cda7 (diff) | |
parent | 51bb33846ad2b045799d2c43ca773fafa36e6ec8 (diff) | |
download | u-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.boot | 17 | ||||
-rw-r--r-- | common/bootm.c | 172 | ||||
-rw-r--r-- | common/cli_simple.c | 17 | ||||
-rw-r--r-- | common/spl/Kconfig | 9 | ||||
-rw-r--r-- | common/spl/spl_atf.c | 129 |
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) |