From 59b07a257ccee6e8a624ba33f4074b12c2453cf9 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:45:54 +0100 Subject: [PATCH 01/21] treewide: use CONFIG_IS_ENABLED() for ARMV8_SEC_FIRMWARE_SUPPORT There is SPL_ARMV8_SEC_FIRMWARE_SUPPORT and ARMV8_SEC_FIRMWARE_SUPPORT. Thus use CONFIG_IS_ENABLED() instead of the simple #ifdef. Signed-off-by: Michael Walle Acked-by: Michal Simek --- arch/arm/cpu/armv8/cpu-dt.c | 2 +- arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 8 ++++---- arch/arm/cpu/armv8/fsl-layerscape/ppa.c | 2 +- arch/arm/lib/bootm-fdt.c | 2 +- arch/arm/lib/psci-dt.c | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) 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 #include -#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 #include -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #include #endif #include @@ -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/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 #endif -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #include #endif #ifdef CONFIG_CHAIN_OF_TRUST 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 #include #include -#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT +#if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT) #include #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. */ From 37c218a06e50727ee5b13640f0cfeee396dc1c10 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:45:55 +0100 Subject: [PATCH 02/21] spl: atf: move storage for bl31_params into function There is no need to have the storage available globally. This is also a preparation for LOAD_IMAGE_V2 support. That will introduce a similar generator function which also has its own storage. Signed-off-by: Michael Walle Acked-by: Michal Simek --- common/spl/spl_atf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c index 9bd25f6b32..df0a198d55 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -18,13 +18,12 @@ #include #include -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) { + 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; From d2cb0c8f759ddc9cbc063816454d5f0d18d7fcb1 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:45:56 +0100 Subject: [PATCH 03/21] spl: atf: provide a bl2_plat_get_bl31_params_default() Move the actual implementation of the bl2_plat_get_bl31_params() to its own function. The weak function will just call the default implementation. This has the advantage that board code can still call the original implementation if it just want to modify minor things. Signed-off-by: Michael Walle --- common/spl/spl_atf.c | 14 +++++++++++--- include/spl.h | 43 +++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c index df0a198d55..63af6a6207 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -18,9 +18,9 @@ #include #include -__weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry, - uintptr_t bl33_entry, - uintptr_t fdt_addr) +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; @@ -77,6 +77,14 @@ __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); +} + static inline void raw_write_daif(unsigned int daif) { __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory"); diff --git a/include/spl.h b/include/spl.h index b72dfc7e3d..fd928377f0 100644 --- a/include/spl.h +++ b/include/spl.h @@ -526,25 +526,44 @@ 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); /** * spl_optee_entry - entry function for optee * From 553825c1090c9f6968e81a0d40d0a3f42202fc6b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:45:57 +0100 Subject: [PATCH 04/21] spl: atf: remove helper structure from common header bl2_to_bl31_params_mem is just an implementation detail of the SPL ATF support and is not needed anywhere else. Move it from the header to the actual module. Signed-off-by: Michael Walle Acked-by: Michal Simek --- common/spl/spl_atf.c | 11 +++++++++++ include/atf_common.h | 14 -------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c index 63af6a6207..51b45d5dc6 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -18,6 +18,17 @@ #include #include +/* 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 bl31_params *bl2_plat_get_bl31_params_default(uintptr_t bl32_entry, uintptr_t bl33_entry, uintptr_t fdt_addr) diff --git a/include/atf_common.h b/include/atf_common.h index fd5454c55b..e173a10ca9 100644 --- a/include/atf_common.h +++ b/include/atf_common.h @@ -162,20 +162,6 @@ 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; -}; #endif /*__ASSEMBLY__ */ From 7b866825cd354a358eff8f62207701771e0511bd Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:45:58 +0100 Subject: [PATCH 05/21] spl: atf: add support for LOAD_IMAGE_V2 Newer platforms use the LOAD_IMAGE_V2 parameter passing method. Add support for it. Signed-off-by: Michael Walle --- common/spl/Kconfig | 9 ++++ common/spl/spl_atf.c | 99 ++++++++++++++++++++++++++++++++++++++++++-- include/atf_common.h | 30 ++++++++++++++ include/spl.h | 35 ++++++++++++++++ 4 files changed, 169 insertions(+), 4 deletions(-) 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 51b45d5dc6..e1b68dd561 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -29,6 +29,19 @@ struct bl2_to_bl31_params_mem { 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) @@ -96,6 +109,79 @@ __weak struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_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"); @@ -106,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 e173a10ca9..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,6 +171,27 @@ struct bl31_params { struct atf_image_info *bl33_image_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__ */ diff --git a/include/spl.h b/include/spl.h index fd928377f0..374a295fa3 100644 --- a/include/spl.h +++ b/include/spl.h @@ -564,6 +564,41 @@ struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry, 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 * From 8084e918bca8fa2ecf226a5eac5ea064d669b301 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:45:59 +0100 Subject: [PATCH 06/21] armv8: layerscape: don't initialize GIC in SPL The BL31 expects the GIC to be uninitialized. Thus, if we are loading the BL31 by the SPL we must not initialize it. If u-boot is loaded by the SPL directly, it will initialize the GIC again (in the same lowlevel_init()). This was tested on a custom board with SPL loading the BL31 and jumping to u-boot as BL33 as well as loading u-boot directly by the SPL. In case the ATF BL1/BL2 is used, this patch won't change anything, because no SPL is used at all. Signed-off-by: Michael Walle --- arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S | 2 ++ 1 file changed, 2 insertions(+) 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 From ea22783f4010ed1599b96f5b7183222bfcc48537 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:46:00 +0100 Subject: [PATCH 07/21] board: sl28: remove u-boot from loadable DT node It is not needed. Remove it. Signed-off-by: Michael Walle --- arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi | 3 --- 1 file changed, 3 deletions(-) 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..87e14d6ae6 100644 --- a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi +++ b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi @@ -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"; }; }; From e057760f38465f77ff9b557570f56845011729fe Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:46:01 +0100 Subject: [PATCH 08/21] board: sl28: add ATF support (bl31) Add support to load the bl31 part of the ARM Trusted Firmware by the SPL. Signed-off-by: Michael Walle --- .../dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi | 41 +++++++++++++- board/kontron/sl28/Kconfig | 10 ++++ board/kontron/sl28/Makefile | 6 ++- board/kontron/sl28/spl_atf.c | 54 +++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 board/kontron/sl28/spl_atf.c 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 87e14d6ae6..54ef0b4258 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>; @@ -99,6 +99,45 @@ }; }; +#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 = ; + entry = ; + + 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 + &i2c0 { rtc: rtc@32 { }; diff --git a/board/kontron/sl28/Kconfig b/board/kontron/sl28/Kconfig index cdec39be01..aba49fc115 100644 --- a/board/kontron/sl28/Kconfig +++ b/board/kontron/sl28/Kconfig @@ -15,4 +15,14 @@ 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. + 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/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 + */ + +#include +#include +#include +#include + +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; +} From 4c450daf7d5d48ef075980e11052bf6bb28db4f6 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 18 Nov 2020 17:46:02 +0100 Subject: [PATCH 09/21] board: sl28: add OP-TEE Trusted OS support (bl32) Add support to load the OP-TEE Trusted OS by the SPL. Signed-off-by: Michael Walle --- .../dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi | 36 +++++++++++++++++++ board/kontron/sl28/Kconfig | 23 ++++++++++++ board/kontron/sl28/sl28.c | 7 ++++ 3 files changed, 66 insertions(+) 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 54ef0b4258..65d5684973 100644 --- a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi +++ b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi @@ -138,6 +138,42 @@ }; #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 = ; + entry = ; + + 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/board/kontron/sl28/Kconfig b/board/kontron/sl28/Kconfig index aba49fc115..4078ef186b 100644 --- a/board/kontron/sl28/Kconfig +++ b/board/kontron/sl28/Kconfig @@ -25,4 +25,27 @@ config SL28_SPL_LOADS_ATF_BL31 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/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; } From 96434a76fd254248ded19e95dc967d28e65a5edf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:37 -0700 Subject: [PATCH 10/21] env: Allow returning errors from hdelete_r() At present this function returns 1 on success and 0 on failure. But in the latter case it provides no indication of what went wrong. If an attempt is made to delete a non-existent variable, the caller may want to ignore this error. This happens when setting a non-existent variable to "", for example. Update the function to return 0 on success and a useful error code on failure. Add a function comment too. Make sure that env_set() does not return an error if it is deleting a variable that doesn't exist. We could update env_set() to return useful error numbers also, but that is beyond the scope of this change. Signed-off-by: Simon Glass wip --- cmd/nvedit.c | 6 ++++-- include/search.h | 11 ++++++++++- lib/hashtable.c | 12 ++++++------ test/env/hashtable.c | 2 +- 4 files changed, 21 insertions(+), 10 deletions(-) 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/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/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/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; From f158ba15ee0f9f756193b60420adfdc0a9c1eb96 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:38 -0700 Subject: [PATCH 11/21] bootm: Add tests for fixup_silent_linux() This function currently has no tests. Export it so that we can implement a simple test on sandbox. Use IS_ENABLED() to remove the unused code, instead #ifdef. Signed-off-by: Simon Glass --- arch/Kconfig | 1 + common/bootm.c | 14 +++++----- include/bootm.h | 3 +++ include/test/suites.h | 1 + test/Makefile | 1 + test/bootm.c | 59 +++++++++++++++++++++++++++++++++++++++++++ test/cmd_ut.c | 1 + 7 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 test/bootm.c diff --git a/arch/Kconfig b/arch/Kconfig index 3aa99e08fc..accd4df5b0 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -146,6 +146,7 @@ config SANDBOX imply ACPI_PMC_SANDBOX imply CMD_PMC imply CMD_CLONE + imply SILENT_CONSOLE config SH bool "SuperH architecture" diff --git a/common/bootm.c b/common/bootm.c index 167eea4a1e..0d36c57210 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -465,18 +465,21 @@ 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) -static void fixup_silent_linux(void) +void fixup_silent_linux(void) { char *buf; const char *env_val; - char *cmdline = env_get("bootargs"); + char *cmdline; int want_silent; + if (!IS_ENABLED(CONFIG_SILENT_CONSOLE) && + !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY)) + return; + cmdline = env_get("bootargs"); + /* * Only fix cmdline when requested. The environment variable can be: * @@ -523,7 +526,6 @@ static void fixup_silent_linux(void) debug("after silent fix-up: %s\n", env_val); free(buf); } -#endif /* CONFIG_SILENT_CONSOLE */ /** * Execute selected states of the bootm command. @@ -627,10 +629,8 @@ 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 = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); } diff --git a/include/bootm.h b/include/bootm.h index a812a6bf24..6d675e6455 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -85,4 +85,7 @@ void arch_preboot_os(void); */ void board_preboot_os(void); +/* Adjust the 'bootargs' to ensure that Linux boots silently, if required */ +void fixup_silent_linux(void); + #endif 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/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..59d16cb3df --- /dev/null +++ b/test/bootm.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for bootm routines + * + * Copyright 2020 Google LLC + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define BOOTM_TEST(_name, _flags) UNIT_TEST(_name, _flags, bootm_test) + +#define CONSOLE_STR "console=/dev/ttyS0" + +/* Test silent processing in the bootargs variable */ +static int bootm_test_silent_var(struct unit_test_state *uts) +{ + /* 'silent_linux' not set should do nothing */ + env_set("silent_linux", NULL); + env_set("bootargs", CONSOLE_STR); + fixup_silent_linux(); + ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); + + env_set("bootargs", NULL); + fixup_silent_linux(); + ut_assertnull(env_get("bootargs")); + + ut_assertok(env_set("silent_linux", "no")); + env_set("bootargs", CONSOLE_STR); + fixup_silent_linux(); + ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); + + ut_assertok(env_set("silent_linux", "yes")); + env_set("bootargs", CONSOLE_STR); + fixup_silent_linux(); + ut_asserteq_str("console=", env_get("bootargs")); + + /* Empty buffer should still add the string */ + env_set("bootargs", NULL); + fixup_silent_linux(); + ut_asserteq_str("console=", env_get("bootargs")); + + return 0; +} +BOOTM_TEST(bootm_test_silent_var, 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 From 4ae42643d0d71dbb5af45d19fa05b7a6807150c0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:39 -0700 Subject: [PATCH 12/21] bootm: Update fixup_silent_linux() to return an error At present this function fails silently on error. Update it to produce an error code. Report this error to the user and abort the boot, since it likely will prevent a successful start. No tests are added at this stage, since additional refactoring is taking place in subsequent patches. Signed-off-by: Simon Glass --- common/bootm.c | 22 +++++++++++++++------- include/bootm.h | 11 +++++++++-- test/bootm.c | 10 +++++----- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 0d36c57210..950ff7cff6 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -468,7 +468,7 @@ ulong bootm_disable_interrupts(void) #define CONSOLE_ARG "console=" #define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1) -void fixup_silent_linux(void) +int fixup_silent_linux(void) { char *buf; const char *env_val; @@ -477,7 +477,7 @@ void fixup_silent_linux(void) if (!IS_ENABLED(CONFIG_SILENT_CONSOLE) && !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY)) - return; + return 0; cmdline = env_get("bootargs"); /* @@ -489,9 +489,9 @@ 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')) { @@ -501,7 +501,7 @@ void fixup_silent_linux(void) buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_LEN + 1); if (!buf) { debug("%s: out of memory\n", __func__); - return; + return -ENOSPC; } if (start) { @@ -525,6 +525,8 @@ void fixup_silent_linux(void) env_set("bootargs", env_val); debug("after silent fix-up: %s\n", env_val); free(buf); + + return 0; } /** @@ -629,8 +631,14 @@ 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 (images->os.os == IH_OS_LINUX) - fixup_silent_linux(); + if (images->os.os == IH_OS_LINUX) { + ret = fixup_silent_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/include/bootm.h b/include/bootm.h index 6d675e6455..438829af0f 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -85,7 +85,14 @@ void arch_preboot_os(void); */ void board_preboot_os(void); -/* Adjust the 'bootargs' to ensure that Linux boots silently, if required */ -void fixup_silent_linux(void); +/* + * fixup_silent_linux() - Process fix-ups for the command line + * + * Updates the 'bootargs' envvar as required. This handles making Linux boot + * silently if requested ('silent_linux' envvar) + * + * @return 0 if OK, -ENOMEM if out of memory + */ +int fixup_silent_linux(void); #endif diff --git a/test/bootm.c b/test/bootm.c index 59d16cb3df..ab1711609b 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -23,26 +23,26 @@ static int bootm_test_silent_var(struct unit_test_state *uts) /* 'silent_linux' not set should do nothing */ env_set("silent_linux", NULL); env_set("bootargs", CONSOLE_STR); - fixup_silent_linux(); + ut_assertok(fixup_silent_linux()); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); env_set("bootargs", NULL); - fixup_silent_linux(); + ut_assertok(fixup_silent_linux()); ut_assertnull(env_get("bootargs")); ut_assertok(env_set("silent_linux", "no")); env_set("bootargs", CONSOLE_STR); - fixup_silent_linux(); + ut_assertok(fixup_silent_linux()); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); ut_assertok(env_set("silent_linux", "yes")); env_set("bootargs", CONSOLE_STR); - fixup_silent_linux(); + ut_assertok(fixup_silent_linux()); ut_asserteq_str("console=", env_get("bootargs")); /* Empty buffer should still add the string */ env_set("bootargs", NULL); - fixup_silent_linux(); + ut_assertok(fixup_silent_linux()); ut_asserteq_str("console=", env_get("bootargs")); return 0; From 4dcb81545ab09b6cb4ee1f3c870fb3131984cf6f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:40 -0700 Subject: [PATCH 13/21] bootm: Rename fixup_silent_linux() We want to add more processing to this function. Before doing so, rename it to bootm_process_cmdline_env(), which is more generic. Signed-off-by: Simon Glass --- common/bootm.c | 4 ++-- include/bootm.h | 4 ++-- test/bootm.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 950ff7cff6..54f64128f8 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -468,7 +468,7 @@ ulong bootm_disable_interrupts(void) #define CONSOLE_ARG "console=" #define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1) -int fixup_silent_linux(void) +int bootm_process_cmdline_env(void) { char *buf; const char *env_val; @@ -632,7 +632,7 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc, ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_PREP)) { if (images->os.os == IH_OS_LINUX) { - ret = fixup_silent_linux(); + ret = bootm_process_cmdline_env(); if (ret) { printf("Cmdline setup failed (err=%d)\n", ret); ret = CMD_RET_FAILURE; diff --git a/include/bootm.h b/include/bootm.h index 438829af0f..35c27ab960 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -86,13 +86,13 @@ void arch_preboot_os(void); void board_preboot_os(void); /* - * fixup_silent_linux() - Process fix-ups for the command line + * 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) * * @return 0 if OK, -ENOMEM if out of memory */ -int fixup_silent_linux(void); +int bootm_process_cmdline_env(void); #endif diff --git a/test/bootm.c b/test/bootm.c index ab1711609b..b69bfad4f6 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -23,26 +23,26 @@ static int bootm_test_silent_var(struct unit_test_state *uts) /* 'silent_linux' not set should do nothing */ env_set("silent_linux", NULL); env_set("bootargs", CONSOLE_STR); - ut_assertok(fixup_silent_linux()); + ut_assertok(bootm_process_cmdline_env()); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); env_set("bootargs", NULL); - ut_assertok(fixup_silent_linux()); + ut_assertok(bootm_process_cmdline_env()); ut_assertnull(env_get("bootargs")); ut_assertok(env_set("silent_linux", "no")); env_set("bootargs", CONSOLE_STR); - ut_assertok(fixup_silent_linux()); + ut_assertok(bootm_process_cmdline_env()); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); ut_assertok(env_set("silent_linux", "yes")); env_set("bootargs", CONSOLE_STR); - ut_assertok(fixup_silent_linux()); + ut_assertok(bootm_process_cmdline_env()); ut_asserteq_str("console=", env_get("bootargs")); /* Empty buffer should still add the string */ env_set("bootargs", NULL); - ut_assertok(fixup_silent_linux()); + ut_assertok(bootm_process_cmdline_env()); ut_asserteq_str("console=", env_get("bootargs")); return 0; From d9477a0a4d4c4561941007a8b3db588385aaad07 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:41 -0700 Subject: [PATCH 14/21] bootm: Add a bool parameter to bootm_process_cmdline_env() This function will soon do more than just handle the 'silent linux' feature. As a first step, update it to take a boolean parameter, indicating whether or not the processing is required. Signed-off-by: Simon Glass --- common/bootm.c | 20 ++++++++++---------- include/bootm.h | 3 ++- test/bootm.c | 10 +++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 54f64128f8..9b0c81d653 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -468,15 +468,17 @@ ulong bootm_disable_interrupts(void) #define CONSOLE_ARG "console=" #define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1) -int bootm_process_cmdline_env(void) +int bootm_process_cmdline_env(bool do_silent) { char *buf; const char *env_val; char *cmdline; int want_silent; - if (!IS_ENABLED(CONFIG_SILENT_CONSOLE) && - !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY)) + /* First check if any action is needed */ + do_silent = IS_ENABLED(CONFIG_SILENT_CONSOLE) && + !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && do_silent; + if (!do_silent) return 0; cmdline = env_get("bootargs"); @@ -631,13 +633,11 @@ 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 (images->os.os == IH_OS_LINUX) { - ret = bootm_process_cmdline_env(); - if (ret) { - printf("Cmdline setup failed (err=%d)\n", ret); - ret = CMD_RET_FAILURE; - goto err; - } + 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/include/bootm.h b/include/bootm.h index 35c27ab960..f12ee2b3cb 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -91,8 +91,9 @@ void board_preboot_os(void); * Updates the 'bootargs' envvar as required. This handles making Linux boot * silently if requested ('silent_linux' envvar) * + * @do_silent: Process bootargs for silent console * @return 0 if OK, -ENOMEM if out of memory */ -int bootm_process_cmdline_env(void); +int bootm_process_cmdline_env(bool do_silent); #endif diff --git a/test/bootm.c b/test/bootm.c index b69bfad4f6..c203f0acd6 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -23,26 +23,26 @@ static int bootm_test_silent_var(struct unit_test_state *uts) /* 'silent_linux' not set should do nothing */ env_set("silent_linux", NULL); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env()); + ut_assertok(bootm_process_cmdline_env(true)); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); env_set("bootargs", NULL); - ut_assertok(bootm_process_cmdline_env()); + ut_assertok(bootm_process_cmdline_env(true)); ut_assertnull(env_get("bootargs")); ut_assertok(env_set("silent_linux", "no")); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env()); + ut_assertok(bootm_process_cmdline_env(true)); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); ut_assertok(env_set("silent_linux", "yes")); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env()); + ut_assertok(bootm_process_cmdline_env(true)); ut_asserteq_str("console=", env_get("bootargs")); /* Empty buffer should still add the string */ env_set("bootargs", NULL); - ut_assertok(bootm_process_cmdline_env()); + ut_assertok(bootm_process_cmdline_env(true)); ut_asserteq_str("console=", env_get("bootargs")); return 0; From 6cd92b1a7c62dc808e74f4638a027da3f6a044ce Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:42 -0700 Subject: [PATCH 15/21] bootm: Use size rather than length for CONSOLE_ARG Use the size (including terminator) for in this function, rather than the length. This is arguably easier to follow, with the coming refactor. Signed-off-by: Simon Glass --- common/bootm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 9b0c81d653..9295cf5cd3 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -465,8 +465,8 @@ ulong bootm_disable_interrupts(void) return iflag; } -#define CONSOLE_ARG "console=" -#define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1) +#define CONSOLE_ARG "console=" +#define CONSOLE_ARG_SIZE sizeof(CONSOLE_ARG) int bootm_process_cmdline_env(bool do_silent) { @@ -500,7 +500,7 @@ int bootm_process_cmdline_env(bool do_silent) char *start = strstr(cmdline, CONSOLE_ARG); /* Allocate space for maximum possible new command line */ - buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_LEN + 1); + buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_SIZE); if (!buf) { debug("%s: out of memory\n", __func__); return -ENOSPC; @@ -508,13 +508,14 @@ int bootm_process_cmdline_env(bool do_silent) 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); } From b6386f38410f669f706a748d7d292d24ea14fe29 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:43 -0700 Subject: [PATCH 16/21] bootm: Split out bootargs environment reading / writing At present bootm_process_cmdline_env() reads the 'bootargs' variable and then writes it back afterwards. This is painful for tests, which would rather use a simple buffer. It is also useful for zimage to use a buffer, since it does not actually put the Linux command line in the bootargs variable. Refactor the existing code into two pieces. One handles reading and writing the environment variable, as well as allocating a buffer for use by the rest of the code, which now operates on a buffer. Signed-off-by: Simon Glass --- common/bootm.c | 95 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 9295cf5cd3..4fa909f23b 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -19,6 +19,7 @@ #include #include #include +#include #if defined(CONFIG_CMD_USB) #include #endif @@ -35,6 +36,8 @@ #define CONFIG_SYS_BOOTM_LEN 0x800000 #endif +#define MAX_CMDLINE_SIZE SZ_4K + #define IH_INITRD_ARCH IH_ARCH_DEFAULT #ifndef USE_HOSTCC @@ -468,20 +471,31 @@ ulong bootm_disable_interrupts(void) #define CONSOLE_ARG "console=" #define CONSOLE_ARG_SIZE sizeof(CONSOLE_ARG) -int bootm_process_cmdline_env(bool do_silent) +/** + * 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; int want_silent; + char *cmdline; + int size; - /* First check if any action is needed */ - do_silent = IS_ENABLED(CONFIG_SILENT_CONSOLE) && - !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && do_silent; - if (!do_silent) - return 0; - cmdline = env_get("bootargs"); - + /* + * 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: * @@ -496,15 +510,12 @@ int bootm_process_cmdline_env(bool do_silent) 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_SIZE); - if (!buf) { - debug("%s: out of memory\n", __func__); + /* Check space for maximum possible new command line */ + if (size + CONSOLE_ARG_SIZE > maxlen) return -ENOSPC; - } if (start) { char *end = strchr(start, ' '); @@ -519,15 +530,55 @@ int bootm_process_cmdline_env(bool do_silent) } 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); - env_set("bootargs", env_val); - debug("after silent fix-up: %s\n", env_val); + return 0; +} + +int bootm_process_cmdline_env(bool do_silent) +{ + const int maxlen = MAX_CMDLINE_SIZE; + 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) && do_silent; + if (!do_silent) + 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 = fixup_silent_linux(buf, maxlen); + 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; } From b3c01678fdb15c63b231743481b9b77c7c4f8549 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:44 -0700 Subject: [PATCH 17/21] bootm: Update bootm_process_cmdline_env() to use flags At present only one transformation is supported: making the Linux console silent. To prepare for adding more, convert the boolean parameter into a flag value. Signed-off-by: Simon Glass --- common/bootm.c | 8 +++++--- include/bootm.h | 11 +++++++++-- test/bootm.c | 10 +++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 4fa909f23b..912ed906ef 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -542,16 +542,17 @@ static int fixup_silent_linux(char *buf, int maxlen) return 0; } -int bootm_process_cmdline_env(bool do_silent) +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) && do_silent; + !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && (flags & BOOTM_CL_SILENT); if (!do_silent) return 0; @@ -685,7 +686,8 @@ 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)) { - ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX); + ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX ? + BOOTM_CL_SILENT : 0); if (ret) { printf("Cmdline setup failed (err=%d)\n", ret); ret = CMD_RET_FAILURE; diff --git a/include/bootm.h b/include/bootm.h index f12ee2b3cb..4876d7b288 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -75,6 +75,13 @@ 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_ALL = 1, /* All substitutions */ +}; + /** * arch_preboot_os() - arch specific configuration before booting */ @@ -91,9 +98,9 @@ void board_preboot_os(void); * Updates the 'bootargs' envvar as required. This handles making Linux boot * silently if requested ('silent_linux' envvar) * - * @do_silent: Process bootargs for silent console + * @flags: Flags to control what happens (see bootm_cmdline_t) * @return 0 if OK, -ENOMEM if out of memory */ -int bootm_process_cmdline_env(bool do_silent); +int bootm_process_cmdline_env(int flags); #endif diff --git a/test/bootm.c b/test/bootm.c index c203f0acd6..ba08920bb1 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -23,26 +23,26 @@ static int bootm_test_silent_var(struct unit_test_state *uts) /* 'silent_linux' not set should do nothing */ env_set("silent_linux", NULL); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env(true)); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); env_set("bootargs", NULL); - ut_assertok(bootm_process_cmdline_env(true)); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_assertnull(env_get("bootargs")); ut_assertok(env_set("silent_linux", "no")); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env(true)); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); ut_assertok(env_set("silent_linux", "yes")); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env(true)); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_asserteq_str("console=", env_get("bootargs")); /* Empty buffer should still add the string */ env_set("bootargs", NULL); - ut_assertok(bootm_process_cmdline_env(true)); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_asserteq_str("console=", env_get("bootargs")); return 0; From 4448fe8e4e7cc4dc5336a2d27fa6048057eaf1a6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:45 -0700 Subject: [PATCH 18/21] bootm: Allow updating the bootargs in a buffer At present we only support updating the 'bootargs' environment variable. Add another function to update a buffer instead. This will allow zimage to use this feature. Also add a lot more tests to cover various cases. Signed-off-by: Simon Glass --- common/bootm.c | 18 +++++++- include/bootm.h | 16 +++++++ test/bootm.c | 118 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 134 insertions(+), 18 deletions(-) diff --git a/common/bootm.c b/common/bootm.c index 912ed906ef..020449db3f 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -542,6 +542,22 @@ static int fixup_silent_linux(char *buf, int maxlen) return 0; } +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); + } + + return 0; +} + int bootm_process_cmdline_env(int flags) { const int maxlen = MAX_CMDLINE_SIZE; @@ -566,7 +582,7 @@ int bootm_process_cmdline_env(int flags) strcpy(buf, env); else *buf = '\0'; - ret = fixup_silent_linux(buf, maxlen); + ret = bootm_process_cmdline(buf, maxlen, flags); if (!ret) { ret = env_set("bootargs", buf); diff --git a/include/bootm.h b/include/bootm.h index 4876d7b288..8d95fb2a90 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -93,6 +93,22 @@ 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) + * + * @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 diff --git a/test/bootm.c b/test/bootm.c index ba08920bb1..d0b29441d6 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -15,33 +15,117 @@ 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 silent processing in the bootargs variable */ static int bootm_test_silent_var(struct unit_test_state *uts) { - /* 'silent_linux' not set should do nothing */ - env_set("silent_linux", NULL); - env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); - ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); - env_set("bootargs", NULL); + env_set("silent_linux", NULL); ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_assertnull(env_get("bootargs")); - ut_assertok(env_set("silent_linux", "no")); env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); - ut_asserteq_str(CONSOLE_STR, env_get("bootargs")); - - ut_assertok(env_set("silent_linux", "yes")); - env_set("bootargs", CONSOLE_STR); - ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); - ut_asserteq_str("console=", env_get("bootargs")); - - /* Empty buffer should still add the string */ - env_set("bootargs", NULL); + env_set("silent_linux", "yes"); ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); ut_asserteq_str("console=", env_get("bootargs")); From 488d89afb88af5f148c7c7cf97ac382a0537b4f7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:46 -0700 Subject: [PATCH 19/21] x86: zimage: Add silent-console processing At present zimage does its own command-line processing and does not support the 'silent console' feature. There doesn't seem to be any good reason for this. Add support for silent console to zimage. Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 +#include #include #include #include @@ -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) From 1a62d64c7de7e7de3facf221eb8408ddfb675cb8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:47 -0700 Subject: [PATCH 20/21] cli: Support macro processing with a fixed-size buffer At present cli_simple_process_macros() requires that the caller provide an output buffer that is exactly CONFIG_SYS_CBSIZE bytes in length. This makes sense since it is designed to be used from the command line. But we also want to use it for bootargs substitution. Update the function to allow the caller to specify the buffer size. Also return an error if the buffer is exhausted. The caller can ignore that if preferred. Signed-off-by: Simon Glass --- cmd/pxe_utils.c | 6 ++++-- common/cli_simple.c | 17 ++++++++++++----- include/cli.h | 4 +++- 3 files changed, 19 insertions(+), 8 deletions(-) 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/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/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 From 51bb33846ad2b045799d2c43ca773fafa36e6ec8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 5 Nov 2020 10:33:48 -0700 Subject: [PATCH 21/21] bootm: Support string substitution in bootargs In some cases it is necessary to pass parameters to Linux so that it will boot correctly. For example, the rootdev parameter is often used to specify the root device. However the root device may change depending on whence U-Boot loads the kernel. At present it is necessary to build up the command line by adding device strings to it one by one. It is often more convenient to provide a template for bootargs, with U-Boot doing the substitution from other environment variables. Add a way to substitute strings in the bootargs variable. This allows things like "rootdev=${rootdev}" to be used in bootargs, with the ${rootdev} substitution providing the UUID of the root device. For example, to substitute the GUID of the kernel partition: setenv bootargs "console=/dev/ttyS0 rootdev=${uuid}/PARTNROFF=1 kern_guid=${uuid}" part uuid mmc 2:2 uuid bootm This is particularly useful when the command line from another place. For example, Chrome OS stores the command line next to the kernel itself. It depends on the kernel version being used as well as the hardware features, so it is extremely difficult to devise a U-Boot script that works on all boards and kernel versions. With this feature, the command line can be read from disk and used directly, with a few substitutions set up. Signed-off-by: Simon Glass --- arch/Kconfig | 1 + common/Kconfig.boot | 17 +++++++ common/bootm.c | 38 +++++++++++++-- include/bootm.h | 14 ++++-- test/bootm.c | 116 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 173 insertions(+), 13 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index accd4df5b0..356193f9ec 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -147,6 +147,7 @@ config SANDBOX imply CMD_PMC imply CMD_CLONE imply SILENT_CONSOLE + imply BOOTARGS_SUBST config SH bool "SuperH architecture" 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 020449db3f..8298693900 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -7,6 +7,7 @@ #ifndef USE_HOSTCC #include #include +#include #include #include #include @@ -542,6 +543,33 @@ static int fixup_silent_linux(char *buf, int maxlen) 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; @@ -554,6 +582,11 @@ int bootm_process_cmdline(char *buf, int maxlen, int flags) 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; } @@ -569,7 +602,7 @@ int bootm_process_cmdline_env(int flags) /* 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) + if (!do_silent && !IS_ENABLED(CONFIG_BOOTARGS_SUBST)) return 0; env = env_get("bootargs"); @@ -702,8 +735,7 @@ 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)) { - ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX ? - BOOTM_CL_SILENT : 0); + 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; diff --git a/include/bootm.h b/include/bootm.h index 8d95fb2a90..7f88ec718b 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -78,8 +78,9 @@ 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 = 1, /* All substitutions */ + BOOTM_CL_ALL = 3, /* All substitutions */ }; /** @@ -95,7 +96,10 @@ 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) + * 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 @@ -111,8 +115,10 @@ 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) + * 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 diff --git a/test/bootm.c b/test/bootm.c index d0b29441d6..92dc2b6e17 100644 --- a/test/bootm.c +++ b/test/bootm.c @@ -116,23 +116,127 @@ static int bootm_test_silent(struct unit_test_state *uts) } 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); - env_set("silent_linux", NULL); - ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); + ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SUBST)); ut_assertnull(env_get("bootargs")); - env_set("bootargs", CONSOLE_STR); - env_set("silent_linux", "yes"); - ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT)); - ut_asserteq_str("console=", 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);