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.
This commit is contained in:
Tom Rini
2020-12-07 17:16:23 -05:00
31 changed files with 914 additions and 99 deletions

View File

@@ -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"

View File

@@ -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)
{
/*

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 {
};

View File

@@ -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;

View File

@@ -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.
*/

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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,18 +469,34 @@ 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_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:
*
@@ -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;
}
/**
* 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);
}
env_set("bootargs", env_val);
debug("after silent fix-up: %s\n", env_val);
free(buf);
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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
/* 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;
};
__weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
uintptr_t bl33_entry,
uintptr_t fdt_addr)
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)

View File

@@ -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__ */

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -526,25 +526,79 @@ 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
*

View File

@@ -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,

View File

@@ -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]);

View File

@@ -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

247
test/bootm.c Normal file
View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;