diff options
Diffstat (limited to 'common/spl')
-rw-r--r-- | common/spl/Kconfig | 24 | ||||
-rw-r--r-- | common/spl/Makefile | 2 | ||||
-rw-r--r-- | common/spl/spl.c | 11 | ||||
-rw-r--r-- | common/spl/spl_atf.c | 84 | ||||
-rw-r--r-- | common/spl/spl_fit.c | 193 |
5 files changed, 250 insertions, 64 deletions
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index c62b82fd68..b1ee15c96d 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -228,6 +228,22 @@ config SPL_SHA256_SUPPORT SHA256 variant is supported: SHA512 and others are not currently supported in U-Boot. +config SPL_FIT_IMAGE_TINY + bool "Remove functionality from SPL FIT loading to reduce size" + depends on SPL_FIT + default y if MACH_SUN50I || MACH_SUN50I_H5 + default y if ARCH_OMAP2PLUS + help + Enable this to reduce the size of the FIT image loading code + in SPL, if space for the SPL binary is very tight. + + This removes the detection of image types (which forces the + first image to be treated as having a U-Boot style calling + convention) and skips the recording of each loaded payload + (i.e. loadable) into the FDT (modifying the loaded FDT to + ensure this information is available to the next image + invoked). + config SPL_CPU_SUPPORT bool "Support CPU drivers" help @@ -702,7 +718,7 @@ config SPL_YMODEM_SUPPORT means of transmitting U-Boot over a serial line for using in SPL, with a checksum to ensure correctness. -config SPL_ATF_SUPPORT +config SPL_ATF bool "Support ARM Trusted Firmware" depends on ARM64 help @@ -710,12 +726,6 @@ config SPL_ATF_SUPPORT 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_TEXT_BASE - depends on SPL_ATF_SUPPORT - hex "ATF BL31 base address" - help - This is the base address in memory for ATF BL31 text and entry point. - config TPL bool depends on SUPPORT_TPL diff --git a/common/spl/Makefile b/common/spl/Makefile index e229947b53..9bf8a2d81a 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -22,7 +22,7 @@ endif obj-$(CONFIG_$(SPL_TPL_)UBI) += spl_ubi.o obj-$(CONFIG_$(SPL_TPL_)NET_SUPPORT) += spl_net.o obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += spl_mmc.o -obj-$(CONFIG_$(SPL_TPL_)ATF_SUPPORT) += spl_atf.o +obj-$(CONFIG_$(SPL_TPL_)ATF) += spl_atf.o obj-$(CONFIG_$(SPL_TPL_)USB_SUPPORT) += spl_usb.o obj-$(CONFIG_$(SPL_TPL_)FAT_SUPPORT) += spl_fat.o obj-$(CONFIG_$(SPL_TPL_)EXT_SUPPORT) += spl_ext.o diff --git a/common/spl/spl.c b/common/spl/spl.c index d232f67ba9..3bb20c7822 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -418,6 +418,12 @@ void board_init_r(gd_t *dummy1, ulong dummy2) case IH_OS_U_BOOT: debug("Jumping to U-Boot\n"); break; +#if CONFIG_IS_ENABLED(ATF) + case IH_OS_ARM_TRUSTED_FIRMWARE: + debug("Jumping to U-Boot via ARM Trusted Firmware\n"); + spl_invoke_atf(&spl_image); + break; +#endif #ifdef CONFIG_SPL_OS_BOOT case IH_OS_LINUX: debug("Jumping to Linux\n"); @@ -442,11 +448,6 @@ void board_init_r(gd_t *dummy1, ulong dummy2) debug("Failed to stash bootstage: err=%d\n", ret); #endif - if (CONFIG_IS_ENABLED(ATF_SUPPORT)) { - debug("loaded - jumping to U-Boot via ATF BL31.\n"); - bl31_entry(); - } - debug("loaded - jumping to U-Boot...\n"); spl_board_prepare_for_boot(); jump_to_image_no_args(&spl_image); diff --git a/common/spl/spl_atf.c b/common/spl/spl_atf.c index 6e8f928044..63557c01e8 100644 --- a/common/spl/spl_atf.c +++ b/common/spl/spl_atf.c @@ -5,6 +5,7 @@ * reserved. * Copyright (C) 2016 Rockchip Electronic Co.,Ltd * Written by Kever Yang <kever.yang@rock-chips.com> + * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH * * SPDX-License-Identifier: BSD-3-Clause */ @@ -30,7 +31,7 @@ static struct bl31_params *bl2_to_bl31_params; * * @return bl31 params structure pointer */ -struct bl31_params *bl2_plat_get_bl31_params(void) +static struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl33_entry) { struct entry_point_info *bl33_ep_info; @@ -66,7 +67,7 @@ struct bl31_params *bl2_plat_get_bl31_params(void) /* BL33 expects to receive the primary CPU MPID (through x0) */ bl33_ep_info->args.arg0 = 0xffff & read_mpidr(); - bl33_ep_info->pc = CONFIG_SYS_TEXT_BASE; + bl33_ep_info->pc = bl33_entry; bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXECPTIONS); @@ -77,21 +78,88 @@ struct bl31_params *bl2_plat_get_bl31_params(void) return bl2_to_bl31_params; } -void raw_write_daif(unsigned int daif) +static inline void raw_write_daif(unsigned int daif) { __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory"); } -void bl31_entry(void) +typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params); + +static void bl31_entry(uintptr_t bl31_entry, uintptr_t bl33_entry, + uintptr_t fdt_addr) { struct bl31_params *bl31_params; - void (*entry)(struct bl31_params *params, void *plat_params) = NULL; + atf_entry_t atf_entry = (atf_entry_t)bl31_entry; - bl31_params = bl2_plat_get_bl31_params(); - entry = (void *)CONFIG_SPL_ATF_TEXT_BASE; + bl31_params = bl2_plat_get_bl31_params(bl33_entry); raw_write_daif(SPSR_EXCEPTION_MASK); dcache_disable(); - entry(bl31_params, NULL); + atf_entry((void *)bl31_params, (void *)fdt_addr); +} + +static int spl_fit_images_find_uboot(void *blob) +{ + int parent, node, ndepth; + const void *data; + + if (!blob) + return -FDT_ERR_BADMAGIC; + + parent = fdt_path_offset(blob, "/fit-images"); + if (parent < 0) + return -FDT_ERR_NOTFOUND; + + for (node = fdt_next_node(blob, parent, &ndepth); + (node >= 0) && (ndepth > 0); + node = fdt_next_node(blob, node, &ndepth)) { + if (ndepth != 1) + continue; + + data = fdt_getprop(blob, node, FIT_OS_PROP, NULL); + if (!data) + continue; + + if (genimg_get_os_id(data) == IH_OS_U_BOOT) + return node; + }; + + return -FDT_ERR_NOTFOUND; +} + +uintptr_t spl_fit_images_get_entry(void *blob, int node) +{ + ulong val; + + val = fdt_getprop_u32(blob, node, "entry-point"); + if (val == FDT_ERROR) + val = fdt_getprop_u32(blob, node, "load-addr"); + + debug("%s: entry point 0x%lx\n", __func__, val); + return val; +} + +void spl_invoke_atf(struct spl_image_info *spl_image) +{ + uintptr_t bl33_entry = CONFIG_SYS_TEXT_BASE; + void *blob = spl_image->fdt_addr; + int node; + + /* + * Find the U-Boot binary (in /fit-images) load addreess or + * entry point (if different) and pass it as the BL3-3 entry + * point. + * This will need to be extended to support Falcon mode. + */ + + node = spl_fit_images_find_uboot(blob); + if (node >= 0) + bl33_entry = spl_fit_images_get_entry(blob, node); + + /* + * We don't provide a BL3-2 entry yet, but this will be possible + * using similar logic. + */ + bl31_entry(spl_image->entry_point, bl33_entry, (uintptr_t)blob); } diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 32d9ee5901..72ae8f4c50 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -2,7 +2,7 @@ * Copyright (C) 2016 Google, Inc * Written by Simon Glass <sjg@chromium.org> * - * SPDX-License-Identifier: GPL-2.0+ + * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> @@ -16,22 +16,24 @@ #endif /** - * spl_fit_get_image_node(): By using the matching configuration subnode, + * spl_fit_get_image_name(): By using the matching configuration subnode, * retrieve the name of an image, specified by a property name and an index * into that. * @fit: Pointer to the FDT blob. * @images: Offset of the /images subnode. * @type: Name of the property within the configuration subnode. * @index: Index into the list of strings in this property. + * @outname: Name of the image * - * Return: the node offset of the respective image node or a negative - * error number. + * Return: 0 on success, or a negative error number */ -static int spl_fit_get_image_node(const void *fit, int images, - const char *type, int index) +static int spl_fit_get_image_name(const void *fit, int images, + const char *type, int index, + char **outname) { const char *name, *str; - int node, conf_node; + __maybe_unused int node; + int conf_node; int len, i; conf_node = fit_find_config_node(fit); @@ -63,7 +65,35 @@ static int spl_fit_get_image_node(const void *fit, int images, } } + *outname = (char *)str; + return 0; +} + +/** + * spl_fit_get_image_node(): By using the matching configuration subnode, + * retrieve the name of an image, specified by a property name and an index + * into that. + * @fit: Pointer to the FDT blob. + * @images: Offset of the /images subnode. + * @type: Name of the property within the configuration subnode. + * @index: Index into the list of strings in this property. + * + * Return: the node offset of the respective image node or a negative + * error number. + */ +static int spl_fit_get_image_node(const void *fit, int images, + const char *type, int index) +{ + char *str; + int err; + int node; + + err = spl_fit_get_image_name(fit, images, type, index, &str); + if (err) + return err; + debug("%s: '%s'\n", type, str); + node = fdt_subnode_offset(fit, images, str); if (node < 0) { debug("cannot find image node '%s': %d\n", str, node); @@ -116,15 +146,15 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size, * @info: points to information about the device to load data from * @sector: the start sector of the FIT image on the device * @fit: points to the flattened device tree blob describing the FIT - * image + * image * @base_offset: the beginning of the data area containing the actual * image data, relative to the beginning of the FIT * @node: offset of the DT node describing the image to load (relative - * to @fit) + * to @fit) * @image_info: will be filled with information about the loaded image - * If the FIT node does not contain a "load" (address) property, - * the image gets loaded to the address pointed to by the - * load_addr member in this struct. + * If the FIT node does not contain a "load" (address) property, + * the image gets loaded to the address pointed to by the + * load_addr member in this struct. * * Return: 0 on success or a negative error number. */ @@ -218,6 +248,73 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, return 0; } +static int spl_fit_append_fdt(struct spl_image_info *spl_image, + struct spl_load_info *info, ulong sector, + void *fit, int images, ulong base_offset) +{ + struct spl_image_info image_info; + int node, ret; + + /* Figure out which device tree the board wants to use */ + node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); + if (node < 0) { + debug("%s: cannot find FDT node\n", __func__); + return node; + } + + /* + * Read the device tree and place it after the image. + * Align the destination address to ARCH_DMA_MINALIGN. + */ + image_info.load_addr = spl_image->load_addr + spl_image->size; + ret = spl_load_fit_image(info, sector, fit, base_offset, node, + &image_info); + + if (ret < 0) + return ret; + + /* Make the load-address of the FDT available for the SPL framework */ + spl_image->fdt_addr = (void *)image_info.load_addr; +#if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) + /* Try to make space, so we can inject details on the loadables */ + ret = fdt_shrink_to_minimum(spl_image->fdt_addr, 8192); +#endif + + return ret; +} + +static int spl_fit_record_loadable(const void *fit, int images, int index, + void *blob, struct spl_image_info *image) +{ + int ret = 0; +#if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY) + char *name; + int node; + + ret = spl_fit_get_image_name(fit, images, "loadables", + index, &name); + if (ret < 0) + return ret; + + node = spl_fit_get_image_node(fit, images, "loadables", index); + + ret = fdt_record_loadable(blob, index, name, image->load_addr, + image->size, image->entry_point, + fdt_getprop(fit, node, "type", NULL), + fdt_getprop(fit, node, "os", NULL)); +#endif + return ret; +} + +static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os) +{ +#if CONFIG_IS_ENABLED(FIT_IMAGE_TINY) + return -ENOTSUPP; +#else + return fit_image_get_os(fit, noffset, os); +#endif +} + int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_load_info *info, ulong sector, void *fit) { @@ -225,7 +322,6 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, ulong size; unsigned long count; struct spl_image_info image_info; - bool boot_os = false; int node = -1; int images, ret; int base_offset, align_len = ARCH_DMA_MINALIGN - 1; @@ -273,17 +369,18 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, return -1; } + /* + * Find the U-Boot image using the following search order: + * - start at 'firmware' (e.g. an ARM Trusted Firmware) + * - fall back 'kernel' (e.g. a Falcon-mode OS boot + * - fall back to using the first 'loadables' entry + */ + if (node < 0) + node = spl_fit_get_image_node(fit, images, "firmware", 0); #ifdef CONFIG_SPL_OS_BOOT - /* Find OS image first */ - node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0); if (node < 0) - debug("No kernel image.\n"); - else - boot_os = true; + node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0); #endif - /* find the U-Boot image */ - if (node < 0) - node = spl_fit_get_image_node(fit, images, "firmware", 0); if (node < 0) { debug("could not find firmware image, trying loadables...\n"); node = spl_fit_get_image_node(fit, images, "loadables", 0); @@ -305,34 +402,29 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (ret) return ret; -#ifdef CONFIG_SPL_OS_BOOT - if (!fit_image_get_os(fit, node, &spl_image->os)) + /* + * For backward compatibility, we treat the first node that is + * as a U-Boot image, if no OS-type has been declared. + */ + if (!spl_fit_image_get_os(fit, node, &spl_image->os)) debug("Image OS is %s\n", genimg_get_os_name(spl_image->os)); -#else - spl_image->os = IH_OS_U_BOOT; +#if !defined(CONFIG_SPL_OS_BOOT) + else + spl_image->os = IH_OS_U_BOOT; #endif - if (!boot_os) { - /* Figure out which device tree the board wants to use */ - node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0); - if (node < 0) { - debug("%s: cannot find FDT node\n", __func__); - return node; - } - - /* - * Read the device tree and place it after the image. - * Align the destination address to ARCH_DMA_MINALIGN. - */ - image_info.load_addr = spl_image->load_addr + spl_image->size; - ret = spl_load_fit_image(info, sector, fit, base_offset, node, - &image_info); - if (ret < 0) - return ret; - } + /* + * Booting a next-stage U-Boot may require us to append the FDT. + * We allow this to fail, as the U-Boot image might embed its FDT. + */ + if (spl_image->os == IH_OS_U_BOOT) + spl_fit_append_fdt(spl_image, info, sector, fit, + images, base_offset); /* Now check if there are more images for us to load */ for (; ; index++) { + uint8_t os_type = IH_OS_INVALID; + node = spl_fit_get_image_node(fit, images, "loadables", index); if (node < 0) break; @@ -342,6 +434,15 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (ret < 0) continue; + if (!spl_fit_image_get_os(fit, node, &os_type)) + debug("Loadable is %s\n", genimg_get_os_name(os_type)); + + if (os_type == IH_OS_U_BOOT) { + spl_fit_append_fdt(&image_info, info, sector, + fit, images, base_offset); + spl_image->fdt_addr = image_info.fdt_addr; + } + /* * If the "firmware" image did not provide an entry point, * use the first valid entry point from the loadables. @@ -349,6 +450,12 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (spl_image->entry_point == FDT_ERROR && image_info.entry_point != FDT_ERROR) spl_image->entry_point = image_info.entry_point; + + /* Record our loadables into the FDT */ + if (spl_image->fdt_addr) + spl_fit_record_loadable(fit, images, index, + spl_image->fdt_addr, + &image_info); } /* |