diff options
-rw-r--r-- | Documentation/lib/payloads/fit.md | 8 | ||||
-rw-r--r-- | payloads/Kconfig | 4 | ||||
-rw-r--r-- | src/arch/arm/Makefile.inc | 1 | ||||
-rw-r--r-- | src/arch/arm/fit_payload.c | 90 |
4 files changed, 101 insertions, 2 deletions
diff --git a/Documentation/lib/payloads/fit.md b/Documentation/lib/payloads/fit.md index c6ccc7b868..ef5e892c36 100644 --- a/Documentation/lib/payloads/fit.md +++ b/Documentation/lib/payloads/fit.md @@ -5,6 +5,7 @@ ## Supported architectures +* aarch32 * aarch64 * riscv @@ -26,6 +27,13 @@ The section must be named in order to be found by the FIT parser: The FIT parser needs architecure support. +### aarch32 +The source code can be found in `src/arch/arm/fit_payload.c`. + +On aarch32 the kernel (a section named 'kernel') must be in **Image** +format and it needs a devicetree (a section named 'fdt') to boot. +The kernel will be placed close to "*DRAMSTART*". + ### aarch64 The source code can be found in `src/arch/arm64/fit_payload.c`. diff --git a/payloads/Kconfig b/payloads/Kconfig index cfb28d6e81..627bb95c9c 100644 --- a/payloads/Kconfig +++ b/payloads/Kconfig @@ -30,7 +30,7 @@ config PAYLOAD_ELF config PAYLOAD_FIT bool "A FIT payload" - depends on ARCH_ARM64 || ARCH_RISCV + depends on ARCH_ARM64 || ARCH_RISCV || ARCH_ARM select PAYLOAD_FIT_SUPPORT help Select this option if you have a payload image (a FIT file) which @@ -97,7 +97,7 @@ config PAYLOAD_FIT_SUPPORT bool "FIT support" default n default y if PAYLOAD_LINUX && (ARCH_ARM || ARCH_ARM64 || ARCH_RISCV) - depends on ARCH_ARM64 || ARCH_RISCV + depends on ARCH_ARM64 || ARCH_RISCV || ARCH_ARM select FLATTENED_DEVICE_TREE help Select this option if your payload is of type FIT. diff --git a/src/arch/arm/Makefile.inc b/src/arch/arm/Makefile.inc index eef2650685..241bfe5051 100644 --- a/src/arch/arm/Makefile.inc +++ b/src/arch/arm/Makefile.inc @@ -119,6 +119,7 @@ ramstage-y += memset.S ramstage-y += memcpy.S ramstage-y += memmove.S ramstage-y += clock.c +ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit_payload.c rmodules_arm-y += memset.S rmodules_arm-y += memcpy.S diff --git a/src/arch/arm/fit_payload.c b/src/arch/arm/fit_payload.c new file mode 100644 index 0000000000..f5470071d4 --- /dev/null +++ b/src/arch/arm/fit_payload.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <bootmem.h> +#include <program_loading.h> +#include <fit.h> +#include <symbols.h> + +/** + * Place the region in free memory range. + */ +static bool fit_place_mem(const struct range_entry *r, void *arg) +{ + struct region *region = arg; + resource_t start; + + if (range_entry_tag(r) != BM_MEM_RAM) + return true; + + /* Linux 4.15 doesn't like 4KiB alignment. Align to 1 MiB for now. */ + start = ALIGN_UP(MAX(region->offset, range_entry_base(r)), 1 * MiB); + + if (start + region->size < range_entry_end(r)) { + region->offset = (size_t)start; + return false; + } + + return true; +} + + +bool fit_payload_arch(struct prog *payload, struct fit_config_node *config, + struct region *kernel, + struct region *fdt, + struct region *initrd) +{ + void *arg = NULL; + + /** + * The kernel ARM documentation recommends loading the kernel above 32MiB + * in order to avoid the need to need to relocate prior to decompression. + */ + kernel->offset = (uintptr_t)_dram + 32 * MiB; + + /** + * The code assumes that bootmem_walk provides a sorted list of memory + * regions, starting from the lowest address. + * The order of the calls here doesn't matter, as the placement is + * enforced in the called functions. + * For details check code on top. + */ + if (!bootmem_walk(fit_place_mem, kernel)) + return false; + + /* Mark as reserved for future allocations. */ + bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD); + + /** + * To ensure the fdt is not overwritten by the kernel decompressor, place + * the fdt above the 128 MB from the start of RAM, as recommended by the + * kernel documentation. + */ + fdt->offset = (uintptr_t)_dram + 128 * MiB; + + if (!bootmem_walk(fit_place_mem, fdt)) + return false; + + /* Mark as reserved for future allocations. */ + bootmem_add_range(fdt->offset, fdt->size, BM_MEM_PAYLOAD); + + /* Place INITRD */ + if (config->ramdisk) { + initrd->offset = fdt->offset + fdt->size; + + if (!bootmem_walk(fit_place_mem, initrd)) + return false; + + /* Mark as reserved for future allocations. */ + bootmem_add_range(initrd->offset, initrd->size, BM_MEM_PAYLOAD); + } + + /* Kernel expects FDT as argument */ + arg = (void *)fdt->offset; + + prog_set_entry(payload, (void *)kernel->offset, arg); + + bootmem_dump_ranges(); + + return true; +} |