diff options
author | Tom Rini <trini@konsulko.com> | 2020-12-08 01:16:23 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-12-08 01:16:23 +0300 |
commit | cd833de0593fa2346dddab21eff6ccf2411380d3 (patch) | |
tree | f87835b392c62414199e5fb926d0f4f63d92ec9e | |
parent | 5157ea526142ace7b0b19939b0d31ace4276cda7 (diff) | |
parent | 51bb33846ad2b045799d2c43ca773fafa36e6ec8 (diff) | |
download | u-boot-cd833de0593fa2346dddab21eff6ccf2411380d3.tar.xz |
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.
31 files changed, 914 insertions, 99 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 3aa99e08fc..356193f9ec 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -146,6 +146,8 @@ config SANDBOX imply ACPI_PMC_SANDBOX imply CMD_PMC imply CMD_CLONE + imply SILENT_CONSOLE + imply BOOTARGS_SUBST config SH bool "SuperH architecture" diff --git a/arch/arm/cpu/armv8/cpu-dt.c b/arch/arm/cpu/armv8/cpu-dt.c index 97d4473a68..61c38b17cb 100644 --- a/arch/arm/cpu/armv8/cpu-dt.c +++ b/arch/arm/cpu/armv8/cpu-dt.c @@ -9,7 +9,7 @@ #include <asm/system.h> #include <asm/armv8/sec_firmware.h> -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) int psci_update_dt(void *fdt) { /* diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index 6d3391db3b..598ee2ffa2 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -26,7 +26,7 @@ #endif #include <fsl_sec.h> #include <asm/arch-fsl-layerscape/soc.h> -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #include <asm/armv8/sec_firmware.h> #endif #include <asm/arch/speed.h> @@ -81,7 +81,7 @@ void ft_fixup_cpu(void *blob) "device_type", "cpu", 4); } -#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && \ +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) && \ defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) int node; u32 psci_ver; @@ -383,7 +383,7 @@ static void fdt_fixup_msi(void *blob) } #endif -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) /* Remove JR node used by SEC firmware */ void fdt_fixup_remove_jr(void *blob) { @@ -488,7 +488,7 @@ void ft_cpu_setup(void *blob, struct bd_info *bd) else { ccsr_sec_t __iomem *sec; -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) fdt_fixup_remove_jr(blob); fdt_fixup_kaslr(blob); #endif diff --git a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S index a519f6ed67..d8803738f1 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S +++ b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S @@ -192,6 +192,7 @@ ENTRY(lowlevel_init) #endif /* Initialize GIC Secure Bank Status */ +#if !defined(CONFIG_SPL_BUILD) #if defined(CONFIG_GICV2) || defined(CONFIG_GICV3) branch_if_slave x0, 1f bl get_gic_offset @@ -205,6 +206,7 @@ ENTRY(lowlevel_init) bl gic_init_secure_percpu #endif #endif +#endif 100: branch_if_master x0, x1, 2f diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ppa.c b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c index 1ddb267093..2285296ea0 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/ppa.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c @@ -16,7 +16,7 @@ #elif defined(CONFIG_FSL_LSCH2) #include <asm/arch/immap_lsch2.h> #endif -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #include <asm/armv8/sec_firmware.h> #endif #ifdef CONFIG_CHAIN_OF_TRUST diff --git a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi index 2375549c6e..65d5684973 100644 --- a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi +++ b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi @@ -16,7 +16,7 @@ ethernet3 = &enetc6; }; - binman { + binman: binman { filename = "u-boot.rom"; pad-byte = <0xff>; @@ -80,21 +80,18 @@ conf-1 { description = "fsl-ls1028a-kontron-sl28"; firmware = "uboot"; - loadables = "uboot"; fdt = "fdt-1"; }; conf-2 { description = "fsl-ls1028a-kontron-sl28-var3"; firmware = "uboot"; - loadables = "uboot"; fdt = "fdt-2"; }; conf-3 { description = "fsl-ls1028a-kontron-sl28-var4"; firmware = "uboot"; - loadables = "uboot"; fdt = "fdt-3"; }; }; @@ -102,6 +99,81 @@ }; }; +#ifdef CONFIG_SL28_SPL_LOADS_ATF_BL31 +&binman { + fit { + images { + bl31 { + description = "ARM Trusted Firmware (bl31)"; + type = "firmware"; + arch = "arm"; + os = "arm-trusted-firmware"; + compression = "none"; + load = <CONFIG_SL28_BL31_ENTRY_ADDR>; + entry = <CONFIG_SL28_BL31_ENTRY_ADDR>; + + blob-ext { + filename = "bl31.bin"; + }; + }; + }; + + configurations { + conf-1 { + firmware = "bl31"; + loadables = "uboot"; + }; + + conf-2 { + firmware = "bl31"; + loadables = "uboot"; + }; + + conf-3 { + firmware = "bl31"; + loadables = "uboot"; + }; + }; + }; +}; +#endif + +#ifdef CONFIG_SL28_SPL_LOADS_OPTEE_BL32 +&binman { + fit { + images { + bl32 { + description = "OP-TEE Trusted OS (bl32)"; + type = "firmware"; + arch = "arm"; + os = "tee"; + compression = "none"; + load = <CONFIG_SL28_BL32_ENTRY_ADDR>; + entry = <CONFIG_SL28_BL32_ENTRY_ADDR>; + + blob-ext { + filename = "tee.bin"; + }; + }; + }; + + configurations { + conf-1 { + loadables = "uboot", "bl32"; + }; + + conf-2 { + loadables = "uboot", "bl32"; + }; + + conf-3 { + loadables = "uboot", "bl32"; + }; + }; + }; +}; +#endif + &i2c0 { rtc: rtc@32 { }; diff --git a/arch/arm/lib/bootm-fdt.c b/arch/arm/lib/bootm-fdt.c index 02a49a8e10..fe46a7d7c9 100644 --- a/arch/arm/lib/bootm-fdt.c +++ b/arch/arm/lib/bootm-fdt.c @@ -63,7 +63,7 @@ int arch_fixup_fdt(void *blob) #endif #if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV8_PSCI) || \ - defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) + CONFIG_IS_ENABLED(SEC_FIRMWARE_ARMV8_PSCI) ret = psci_update_dt(blob); if (ret) return ret; diff --git a/arch/arm/lib/psci-dt.c b/arch/arm/lib/psci-dt.c index 0ed29a43f1..903b335704 100644 --- a/arch/arm/lib/psci-dt.c +++ b/arch/arm/lib/psci-dt.c @@ -10,7 +10,7 @@ #include <linux/sizes.h> #include <linux/kernel.h> #include <asm/psci.h> -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #include <asm/armv8/sec_firmware.h> #endif @@ -64,7 +64,7 @@ int fdt_psci(void *fdt) return nodeoff; init_psci_node: -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) psci_ver = sec_firmware_support_psci_version(); #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI) psci_ver = ARM_PSCI_VER_1_0; @@ -85,7 +85,7 @@ init_psci_node: return tmp; } -#ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if !CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) /* * The Secure firmware framework isn't able to support PSCI version 0.1. */ diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 50fb16d2da..f154827ec7 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -15,6 +15,7 @@ #define LOG_CATEGORY LOGC_BOOT #include <common.h> +#include <bootm.h> #include <command.h> #include <env.h> #include <irq_func.h> @@ -330,7 +331,12 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, } if (cmd_line) { + int max_size = 0xff; + int ret; + log_debug("Setup cmdline\n"); + if (bootproto >= 0x0206) + max_size = hdr->cmdline_size; if (bootproto >= 0x0202) { hdr->cmd_line_ptr = (uintptr_t)cmd_line; } else if (bootproto >= 0x0200) { @@ -346,6 +352,14 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, strcpy(cmd_line, (char *)cmdline_force); else build_command_line(cmd_line, auto_boot); + ret = bootm_process_cmdline(cmd_line, max_size, BOOTM_CL_ALL); + if (ret) { + printf("Cmdline setup failed (err=%d)\n", ret); + return ret; + } + printf("Kernel command line: \""); + puts(cmd_line); + printf("\"\n"); } if (IS_ENABLED(CONFIG_INTEL_MID) && bootproto >= 0x0207) diff --git a/board/kontron/sl28/Kconfig b/board/kontron/sl28/Kconfig index cdec39be01..4078ef186b 100644 --- a/board/kontron/sl28/Kconfig +++ b/board/kontron/sl28/Kconfig @@ -15,4 +15,37 @@ config SYS_CONFIG_NAME config SYS_TEXT_BASE default 0x96000000 +config SL28_SPL_LOADS_ATF_BL31 + bool "SPL loads BL31 of the ARM Trusted Firmware" + select SPL_ATF + select SPL_ATF_LOAD_IMAGE_V2 + select ARMV8_SEC_FIRMWARE_SUPPORT + select SEC_FIRMWARE_ARMV8_PSCI + help + Enable this to load a BL31 image by the SPL. You have to + provde a bl31.bin in u-boot's root directory. + +if SL28_SPL_LOADS_ATF_BL31 + +config SL28_BL31_ENTRY_ADDR + hex "Entry point of the BL31 image" + default 0xfbe00000 + +endif + +config SL28_SPL_LOADS_OPTEE_BL32 + bool "SPL loads OP-TEE Trusted OS as BL32" + depends on SL28_SPL_LOADS_ATF_BL31 + help + Enable this to load a BL32 image by the SPL. You have to + provde a tee.bin in u-boot's root directory. + +if SL28_SPL_LOADS_OPTEE_BL32 + +config SL28_BL32_ENTRY_ADDR + hex "Entry point of the BL32 image" + default 0xfc000000 + +endif + endif diff --git a/board/kontron/sl28/Makefile b/board/kontron/sl28/Makefile index 74d8012f0f..5d220f0744 100644 --- a/board/kontron/sl28/Makefile +++ b/board/kontron/sl28/Makefile @@ -5,4 +5,8 @@ obj-y += sl28.o cmds.o endif obj-y += common.o ddr.o -obj-$(CONFIG_SPL_BUILD) += spl.o + +ifdef CONFIG_SPL_BUILD +obj-y += spl.o +obj-$(CONFIG_SPL_ATF) += spl_atf.o +endif diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c index b18127c4d1..34f17b486b 100644 --- a/board/kontron/sl28/sl28.c +++ b/board/kontron/sl28/sl28.c @@ -50,6 +50,7 @@ int ft_board_setup(void *blob, struct bd_info *bd) u64 base[CONFIG_NR_DRAM_BANKS]; u64 size[CONFIG_NR_DRAM_BANKS]; int nbanks = CONFIG_NR_DRAM_BANKS; + int node; int i; ft_cpu_setup(blob, bd); @@ -64,5 +65,11 @@ int ft_board_setup(void *blob, struct bd_info *bd) fdt_fixup_icid(blob); + if (CONFIG_IS_ENABLED(SL28_SPL_LOADS_OPTEE_BL32)) { + node = fdt_node_offset_by_compatible(blob, -1, "linaro,optee-tz"); + if (node) + fdt_set_node_status(blob, node, FDT_STATUS_OKAY, 0); + } + return 0; } diff --git a/board/kontron/sl28/spl_atf.c b/board/kontron/sl28/spl_atf.c new file mode 100644 index 0000000000..5438b5239c --- /dev/null +++ b/board/kontron/sl28/spl_atf.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LS1028A TF-A calling support + * + * Copyright (c) 2020 Michael Walle <michael@walle.cc> + */ + +#include <common.h> +#include <asm/io.h> +#include <atf_common.h> +#include <spl.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct region_info { + u64 addr; + u64 size; +}; + +struct dram_regions_info { + u64 num_dram_regions; + u64 total_dram_size; + struct region_info region[CONFIG_NR_DRAM_BANKS]; +}; + +struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry, + uintptr_t bl33_entry, + uintptr_t fdt_addr) +{ + static struct dram_regions_info dram_regions_info = { 0 }; + struct bl_params *bl_params; + struct bl_params_node *node; + void *dcfg_ccsr = (void *)DCFG_BASE; + int i; + + dram_regions_info.num_dram_regions = CONFIG_NR_DRAM_BANKS; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + dram_regions_info.region[i].addr = gd->bd->bi_dram[i].start; + dram_regions_info.region[i].size = gd->bd->bi_dram[i].size; + dram_regions_info.total_dram_size += gd->bd->bi_dram[i].size; + } + + bl_params = bl2_plat_get_bl31_params_v2_default(bl32_entry, bl33_entry, + fdt_addr); + + for_each_bl_params_node(bl_params, node) { + if (node->image_id == ATF_BL31_IMAGE_ID) { + node->ep_info->args.arg3 = (uintptr_t)&dram_regions_info; + node->ep_info->args.arg4 = in_le32(dcfg_ccsr + DCFG_PORSR1); + } + } + + return bl_params; +} diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 7fce723800..d0d2eca904 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -266,7 +266,9 @@ static int _do_env_set(int flag, int argc, char *const argv[], int env_flag) /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { int rc = hdelete_r(name, &env_htab, env_flag); - return !rc; + + /* If the variable didn't exist, don't report an error */ + return rc && rc != -ENOENT ? 1 : 0; } /* @@ -895,7 +897,7 @@ static int do_env_delete(struct cmd_tbl *cmdtp, int flag, while (--argc > 0) { char *name = *++argv; - if (!hdelete_r(name, &env_htab, env_flag)) + if (hdelete_r(name, &env_htab, env_flag)) ret = 1; } diff --git a/cmd/pxe_utils.c b/cmd/pxe_utils.c index 235522f4bb..b9d9a5786c 100644 --- a/cmd/pxe_utils.c +++ b/cmd/pxe_utils.c @@ -322,7 +322,8 @@ static int label_localboot(struct pxe_label *label) if (label->append) { char bootargs[CONFIG_SYS_CBSIZE]; - cli_simple_process_macros(label->append, bootargs); + cli_simple_process_macros(label->append, bootargs, + sizeof(bootargs)); env_set("bootargs", bootargs); } @@ -430,7 +431,8 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label) strcat(bootargs, ip_str); strcat(bootargs, mac_str); - cli_simple_process_macros(bootargs, finalbootargs); + cli_simple_process_macros(bootargs, finalbootargs, + sizeof(finalbootargs)); env_set("bootargs", finalbootargs); printf("append: %s\n", finalbootargs); } diff --git a/common/Kconfig.boot b/common/Kconfig.boot index 3f6d9c1a25..58e98548de 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 167eea4a1e..8298693900 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 7d91316a0f..e80ba488a5 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 d8086bd9e8..6d980be0b7 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 9bd25f6b32..e1b68dd561 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) diff --git a/include/atf_common.h b/include/atf_common.h index fd5454c55b..d69892fac6 100644 --- a/include/atf_common.h +++ b/include/atf_common.h @@ -14,8 +14,14 @@ #define ATF_PARAM_EP 0x01 #define ATF_PARAM_IMAGE_BINARY 0x02 #define ATF_PARAM_BL31 0x03 +#define ATF_PARAM_BL_PARAMS 0x05 #define ATF_VERSION_1 0x01 +#define ATF_VERSION_2 0x02 + +#define ATF_BL31_IMAGE_ID 0x03 +#define ATF_BL32_IMAGE_ID 0x04 +#define ATF_BL33_IMAGE_ID 0x05 #define ATF_EP_SECURE 0x0 #define ATF_EP_NON_SECURE 0x1 @@ -121,6 +127,9 @@ struct atf_image_info { struct param_header h; uintptr_t image_base; /* physical address of base of image */ uint32_t image_size; /* bytes read from image file */ +#if CONFIG_IS_ENABLED(ATF_LOAD_IMAGE_V2) + uint32_t image_max_size; +#endif }; /***************************************************************************** @@ -162,21 +171,28 @@ struct bl31_params { struct atf_image_info *bl33_image_info; }; -/******************************************************************************* - * This structure represents the superset of information that is passed to - * BL31, e.g. while passing control to it from BL2, bl31_params - * and other platform specific params - ******************************************************************************/ -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; +/* BL image node in the BL image execution sequence */ +struct bl_params_node { + unsigned int image_id; + struct atf_image_info *image_info; + struct entry_point_info *ep_info; + struct bl_params_node *next_params_info; +}; + +/* + * BL image head node in the BL image execution sequence + * It is also used to pass information to next BL image. + */ +struct bl_params { + struct param_header h; + struct bl_params_node *head; }; +#define for_each_bl_params_node(bl_params, node) \ + for ((node) = (bl_params)->head; \ + (node); \ + (node) = (node)->next_params_info) + #endif /*__ASSEMBLY__ */ #endif /* __BL_COMMON_H__ */ diff --git a/include/bootm.h b/include/bootm.h index a812a6bf24..7f88ec718b 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -75,6 +75,14 @@ void board_quiesce_devices(void); */ void switch_to_non_secure_mode(void); +/* Flags to control bootm_process_cmdline() */ +enum bootm_cmdline_t { + BOOTM_CL_SILENT = 1 << 0, /* Do silent console processing */ + BOOTM_CL_SUBST = 1 << 1, /* Do substitution */ + + BOOTM_CL_ALL = 3, /* All substitutions */ +}; + /** * arch_preboot_os() - arch specific configuration before booting */ @@ -85,4 +93,36 @@ void arch_preboot_os(void); */ void board_preboot_os(void); +/* + * bootm_process_cmdline() - Process fix-ups for the command line + * + * This handles: + * + * - making Linux boot silently if requested ('silent_linux' envvar) + * - performing substitutions in the command line ('bootargs_subst' envvar) + * + * @maxlen must provide enough space for the string being processed plus the + * resulting string + * + * @buf: buffer holding commandline string to adjust + * @maxlen: Maximum length of buffer at @buf (including \0) + * @flags: Flags to control what happens (see bootm_cmdline_t) + * @return 0 if OK, -ENOMEM if out of memory, -ENOSPC if the commandline is too + * long + */ +int bootm_process_cmdline(char *buf, int maxlen, int flags); + +/** + * bootm_process_cmdline_env() - Process fix-ups for the command line + * + * Updates the 'bootargs' envvar as required. This handles: + * + * - making Linux boot silently if requested ('silent_linux' envvar) + * - performing substitutions in the command line ('bootargs_subst' envvar) + * + * @flags: Flags to control what happens (see bootm_cmdline_t) + * @return 0 if OK, -ENOMEM if out of memory + */ +int bootm_process_cmdline_env(int flags); + #endif diff --git a/include/cli.h b/include/cli.h index 39b913743b..3449fa6ae7 100644 --- a/include/cli.h +++ b/include/cli.h @@ -34,8 +34,10 @@ int cli_simple_run_command(const char *cmd, int flag); * * @param input Input string possible containing $() / ${} vars * @param output Output string with $() / ${} vars expanded + * @param max_size Maximum size of @output (including terminator) + * @return 0 if OK, -ENOSPC if we ran out of space in @output */ -void cli_simple_process_macros(const char *input, char *output); +int cli_simple_process_macros(const char *input, char *output, int max_size); /** * cli_simple_run_command_list() - Execute a list of command diff --git a/include/search.h b/include/search.h index e56843c26f..d0bb44388e 100644 --- a/include/search.h +++ b/include/search.h @@ -80,7 +80,16 @@ int hsearch_r(struct env_entry item, enum env_action action, int hmatch_r(const char *match, int last_idx, struct env_entry **retval, struct hsearch_data *htab); -/* Search and delete entry matching "key" in internal hash table. */ +/** + * hdelete_r() - Search and delete entry in internal hash table + * + * @key: Name of entry to delete + * @htab: Hash table + * @flag: Flags to use (H_...) + * @return 0 on success, -ENOENT if not found, -EPERM if the hash table callback + * rejected changing the variable, -EINVAL if the hash table refused to + * delete the variable + */ int hdelete_r(const char *key, struct hsearch_data *htab, int flag); ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, diff --git a/include/spl.h b/include/spl.h index b72dfc7e3d..374a295fa3 100644 --- a/include/spl.h +++ b/include/spl.h @@ -526,26 +526,80 @@ int spl_ymodem_load_image(struct spl_image_info *spl_image, void spl_invoke_atf(struct spl_image_info *spl_image); /** - * bl2_plat_get_bl31_params() - prepare params for bl31. - * @bl32_entry address of BL32 executable (secure) - * @bl33_entry address of BL33 executable (non secure) - * @fdt_addr address of Flat Device Tree + * bl2_plat_get_bl31_params() - return params for bl31. + * @bl32_entry: address of BL32 executable (secure) + * @bl33_entry: address of BL33 executable (non secure) + * @fdt_addr: address of Flat Device Tree * - * This function assigns a pointer to the memory that the platform has kept - * aside to pass platform specific and trusted firmware related information - * to BL31. This memory is allocated by allocating memory to - * bl2_to_bl31_params_mem structure which is a superset of all the - * structure whose information is passed to BL31 - * NOTE: This function should be called only once and should be done - * before generating params to BL31 + * This is a weak function which might be overridden by the board code. By + * default it will just call bl2_plat_get_bl31_params_default(). * - * @return bl31 params structure pointer + * If you just want to manipulate or add some parameters, you can override + * this function, call bl2_plat_get_bl31_params_default and operate on the + * returned bl31 params. + * + * Return: bl31 params structure pointer */ struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry, uintptr_t bl33_entry, uintptr_t fdt_addr); /** + * bl2_plat_get_bl31_params_default() - prepare params for bl31. + * @bl32_entry: address of BL32 executable (secure) + * @bl33_entry: address of BL33 executable (non secure) + * @fdt_addr: address of Flat Device Tree + * + * This is the default implementation of bl2_plat_get_bl31_params(). It assigns + * a pointer to the memory that the platform has kept aside to pass platform + * specific and trusted firmware related information to BL31. This memory is + * allocated by allocating memory to bl2_to_bl31_params_mem structure which is + * a superset of all the structure whose information is passed to BL31 + * + * NOTE: The memory is statically allocated, thus this function should be + * called only once. All subsequent calls will overwrite any changes. + * + * Return: bl31 params structure pointer + */ +struct bl31_params *bl2_plat_get_bl31_params_default(uintptr_t bl32_entry, + uintptr_t bl33_entry, + uintptr_t fdt_addr); + +/** + * bl2_plat_get_bl31_params_v2() - return params for bl31 + * @bl32_entry: address of BL32 executable (secure) + * @bl33_entry: address of BL33 executable (non secure) + * @fdt_addr: address of Flat Device Tree + * + * This function does the same as bl2_plat_get_bl31_params() except that is is + * used for the new LOAD_IMAGE_V2 option, which uses a slightly different + * method to pass the parameters. + * + * Return: bl31 params structure pointer + */ +struct bl_params *bl2_plat_get_bl31_params_v2(uintptr_t bl32_entry, + uintptr_t bl33_entry, + uintptr_t fdt_addr); + +/** + * bl2_plat_get_bl31_params_v2_default() - prepare params for bl31. + * @bl32_entry: address of BL32 executable (secure) + * @bl33_entry: address of BL33 executable (non secure) + * @fdt_addr: address of Flat Device Tree + * + * This is the default implementation of bl2_plat_get_bl31_params_v2(). It + * prepares the linked list of the bl31 params, populates the image types and + * set the entry points for bl32 and bl33 (if available). + * + * NOTE: The memory is statically allocated, thus this function should be + * called only once. All subsequent calls will overwrite any changes. + * + * Return: bl31 params structure pointer + */ +struct bl_params *bl2_plat_get_bl31_params_v2_default(uintptr_t bl32_entry, + uintptr_t bl33_entry, + uintptr_t fdt_addr); +/** * spl_optee_entry - entry function for optee * * args defind in op-tee project diff --git a/include/test/suites.h b/include/test/suites.h index 5c97846e7f..52e8fc8155 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -26,6 +26,7 @@ int cmd_ut_category(const char *name, const char *prefix, struct unit_test *tests, int n_ents, int argc, char *const argv[]); +int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc, diff --git a/lib/hashtable.c b/lib/hashtable.c index 7c08f5c805..ff5ff72639 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -472,7 +472,7 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) idx = hsearch_r(e, ENV_FIND, &ep, htab, 0); if (idx == 0) { __set_errno(ESRCH); - return 0; /* not found */ + return -ENOENT; /* not found */ } /* Check for permission */ @@ -481,7 +481,7 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) debug("change_ok() rejected deleting variable " "%s, skipping it!\n", key); __set_errno(EPERM); - return 0; + return -EPERM; } /* If there is a callback, call it */ @@ -490,12 +490,12 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) debug("callback() rejected deleting variable " "%s, skipping it!\n", key); __set_errno(EINVAL); - return 0; + return -EINVAL; } _hdelete(key, htab, ep, idx); - return 1; + return 0; } #if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV)) @@ -917,7 +917,7 @@ int himport_r(struct hsearch_data *htab, if (!drop_var_from_set(name, nvars, localvars)) continue; - if (hdelete_r(name, htab, flag) == 0) + if (hdelete_r(name, htab, flag)) debug("DELETE ERROR ##############################\n"); continue; @@ -979,7 +979,7 @@ int himport_r(struct hsearch_data *htab, * b) if the variable was not present in current env, we notify * it might be a typo */ - if (hdelete_r(localvars[i], htab, flag) == 0) + if (hdelete_r(localvars[i], htab, flag)) printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]); else printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]); diff --git a/test/Makefile b/test/Makefile index 8296734eb3..d4323f9963 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,6 +5,7 @@ ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o endif +obj-$(CONFIG_$(SPL_)CMDLINE) += bootm.o obj-$(CONFIG_$(SPL_)CMDLINE) += cmd/ obj-$(CONFIG_$(SPL_)CMDLINE) += cmd_ut.o obj-$(CONFIG_$(SPL_)CMDLINE) += command_ut.o diff --git a/test/bootm.c b/test/bootm.c new file mode 100644 index 0000000000..92dc2b6e17 --- /dev/null +++ b/test/bootm.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for bootm routines + * + * Copyright 2020 Google LLC + */ + +#include <common.h> +#include <bootm.h> +#include <test/suites.h> +#include <test/test.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define BOOTM_TEST(_name, _flags) UNIT_TEST(_name, _flags, bootm_test) + +enum { + BUF_SIZE = 1024, +}; + +#define CONSOLE_STR "console=/dev/ttyS0" + +/* Test cmdline processing where nothing happens */ +static int bootm_test_nop(struct unit_test_state *uts) +{ + char buf[BUF_SIZE]; + + *buf = '\0'; + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, true)); + ut_asserteq_str("", buf); + + strcpy(buf, "test"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, true)); + ut_asserteq_str("test", buf); + + return 0; +} +BOOTM_TEST(bootm_test_nop, 0); + +/* Test cmdline processing when out of space */ +static int bootm_test_nospace(struct unit_test_state *uts) +{ + char buf[BUF_SIZE]; + + /* Zero buffer size */ + *buf = '\0'; + ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 0, true)); + + /* Buffer string not terminated */ + memset(buf, 'a', BUF_SIZE); + ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, BUF_SIZE, true)); + + /* Not enough space to copy string */ + memset(buf, '\0', BUF_SIZE); + memset(buf, 'a', BUF_SIZE / 2); + ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, BUF_SIZE, true)); + + /* Just enough space */ + memset(buf, '\0', BUF_SIZE); + memset(buf, 'a', BUF_SIZE / 2 - 1); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, true)); + + return 0; +} +BOOTM_TEST(bootm_test_nospace, 0); + +/* Test silent processing */ +static int bootm_test_silent(struct unit_test_state *uts) +{ + char buf[BUF_SIZE]; + + /* 'silent_linux' not set should do nothing */ + env_set("silent_linux", NULL); + strcpy(buf, CONSOLE_STR); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); + ut_asserteq_str(CONSOLE_STR, buf); + + ut_assertok(env_set("silent_linux", "no")); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); + ut_asserteq_str(CONSOLE_STR, buf); + + ut_assertok(env_set("silent_linux", "yes")); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); + ut_asserteq_str("console=", buf); + + /* Empty buffer should still add the string */ + *buf = '\0'; + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); + ut_asserteq_str("console=", buf); + + /* Check nothing happens when do_silent is false */ + *buf = '\0'; + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, 0)); + ut_asserteq_str("", buf); + + /* Not enough space */ + *buf = '\0'; + ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 8, BOOTM_CL_SILENT)); + + /* Just enough space */ + *buf = '\0'; + ut_assertok(bootm_process_cmdline(buf, 9, BOOTM_CL_SILENT)); + + /* add at end */ + strcpy(buf, "something"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); + ut_asserteq_str("something console=", buf); + + /* change at start */ + strcpy(buf, CONSOLE_STR " something"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT)); + ut_asserteq_str("console= something", buf); + + return 0; +} +BOOTM_TEST(bootm_test_silent, 0); + +/* Test substitution processing */ +static int bootm_test_subst(struct unit_test_state *uts) +{ + char buf[BUF_SIZE]; + + /* try with an unset variable */ + ut_assertok(env_set("var", NULL)); + strcpy(buf, "some${var}thing"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("something", buf); + + /* Replace with shorter string */ + ut_assertok(env_set("var", "bb")); + strcpy(buf, "some${var}thing"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("somebbthing", buf); + + /* Replace with same-length string */ + ut_assertok(env_set("var", "abc")); + strcpy(buf, "some${var}thing"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("someabcthing", buf); + + /* Replace with longer string */ + ut_assertok(env_set("var", "abcde")); + strcpy(buf, "some${var}thing"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("someabcdething", buf); + + /* Check it is case sensitive */ + ut_assertok(env_set("VAR", NULL)); + strcpy(buf, "some${VAR}thing"); + ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("something", buf); + + /* Check too long - need 12 bytes for each string */ + strcpy(buf, "some${var}thing"); + ut_asserteq(-ENOSPC, + bootm_process_cmdline(buf, 12 * 2 - 1, BOOTM_CL_SUBST)); + + /* Check just enough space */ + strcpy(buf, "some${var}thing"); + ut_assertok(bootm_process_cmdline(buf, 16 * 2, BOOTM_CL_SUBST)); + ut_asserteq_str("someabcdething", buf); + + /* + * Check the substition string being too long. This results in a string + * of 12 (13 bytes). We need enough space for that plus the original + * "a${var}c" string of 9 bytes. So 12 + 9 = 21 bytes. + */ + ut_assertok(env_set("var", "1234567890")); + strcpy(buf, "a${var}c"); + ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 21, BOOTM_CL_SUBST)); + + strcpy(buf, "a${var}c"); + ut_asserteq(0, bootm_process_cmdline(buf, 22, BOOTM_CL_SUBST)); + + /* Check multiple substitutions */ + ut_assertok(env_set("var", "abc")); + strcpy(buf, "some${var}thing${bvar}else"); + ut_asserteq(0, bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("someabcthingelse", buf); + + /* Check multiple substitutions */ + ut_assertok(env_set("bvar", "123")); + strcpy(buf, "some${var}thing${bvar}else"); + ut_asserteq(0, bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST)); + ut_asserteq_str("someabcthing123else", buf); + + return 0; +} +BOOTM_TEST(bootm_test_subst, 0); + +/* Test silent processing in the bootargs variable */ +static int bootm_test_silent_var(struct unit_test_state *uts) +{ + env_set("bootargs", NULL); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SUBST)); + ut_assertnull(env_get("bootargs")); + + ut_assertok(env_set("bootargs", "some${var}thing")); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SUBST)); + ut_asserteq_str("something", env_get("bootargs")); + + return 0; +} +BOOTM_TEST(bootm_test_silent_var, 0); + +/* Test substitution processing in the bootargs variable */ +static int bootm_test_subst_var(struct unit_test_state *uts) +{ + env_set("bootargs", NULL); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); + ut_asserteq_str("console=", env_get("bootargs")); + + ut_assertok(env_set("var", "abc")); + ut_assertok(env_set("bootargs", "some${var}thing")); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); + ut_asserteq_str("some${var}thing console=", env_get("bootargs")); + + return 0; +} +BOOTM_TEST(bootm_test_subst_var, 0); + +/* Test substitution and silent console processing in the bootargs variable */ +static int bootm_test_subst_both(struct unit_test_state *uts) +{ + ut_assertok(env_set("silent_linux", "yes")); + env_set("bootargs", NULL); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL)); + ut_asserteq_str("console=", env_get("bootargs")); + + ut_assertok(env_set("bootargs", "some${var}thing " CONSOLE_STR)); + ut_assertok(env_set("var", "1234567890")); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL)); + ut_asserteq_str("some1234567890thing console=", env_get("bootargs")); + + return 0; +} +BOOTM_TEST(bootm_test_subst_both, 0); + +int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct unit_test *tests = ll_entry_start(struct unit_test, bootm_test); + const int n_ents = ll_entry_count(struct unit_test, bootm_test); + + return cmd_ut_category("bootm", "bootm_test_", tests, n_ents, + argc, argv); +} diff --git a/test/cmd_ut.c b/test/cmd_ut.c index f79109e6f8..fad1c899a4 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -88,6 +88,7 @@ static struct cmd_tbl cmd_ut_sub[] = { "", ""), U_BOOT_CMD_MKENT(bloblist, CONFIG_SYS_MAXARGS, 1, do_ut_bloblist, "", ""), + U_BOOT_CMD_MKENT(bootm, CONFIG_SYS_MAXARGS, 1, do_ut_bootm, "", ""), U_BOOT_CMD_MKENT(str, CONFIG_SYS_MAXARGS, 1, do_ut_str, "", ""), #endif diff --git a/test/env/hashtable.c b/test/env/hashtable.c index 339cc19ba1..70102f9121 100644 --- a/test/env/hashtable.c +++ b/test/env/hashtable.c @@ -80,7 +80,7 @@ static int htab_create_delete(struct unit_test_state *uts, ut_asserteq_str(key, ritem->key); ut_asserteq_str(key, ritem->data); - ut_asserteq(1, hdelete_r(key, htab, 0)); + ut_asserteq(0, hdelete_r(key, htab, 0)); } return 0; |