From 52ece15559cdb67ed3da2d6e1ce06bad0dc722f8 Mon Sep 17 00:00:00 2001 From: Dzmitry Sankouski Date: Tue, 25 Jan 2022 22:15:50 +0300 Subject: [PATCH 1/3 v3] arm: init: save previous bootloader data When u-boot is used as a chain-loaded bootloader (replacing OS kernel), previous bootloader leaves data in RAM, that can be reused. For example, on recent arm linux system, when chainloading u-boot, there are initramfs and fdt in RAM prepared for OS booting. Initramfs may be modified to store u-boot's payload, thus providing the ability to use chainloaded u-boot to boot OS without any storage support. Two config options added: - SAVE_PREV_BL_INITRAMFS_START_ADDR saves initramfs start address to 'prevbl_initrd_start_addr' environment variable - SAVE_PREV_BL_FDT_ADDR saves fdt address to 'prevbl_fdt_addr' environment variable Signed-off-by: Dzmitry Sankouski Cc: Tom Rini --- Changes for v2: - change signed off line Changes for v3: - use if (CONFIG_IS_ENABLED... instead of #if defined - fix save_prev_bl_data.o in Makefile - add save_prev_bl_data call to env initialization arch/arm/lib/Makefile | 5 ++ arch/arm/lib/save_prev_bl_data.c | 91 ++++++++++++++++++++++++++++++++ boot/Kconfig | 79 +++++++++++++++++---------- common/board_r.c | 5 ++ include/init.h | 13 +++++ 5 files changed, 166 insertions(+), 27 deletions(-) create mode 100644 arch/arm/lib/save_prev_bl_data.c diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index c48e1f622d..f3c31c05e5 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -48,6 +48,11 @@ obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o endif obj-$(CONFIG_SEMIHOSTING) += semihosting.o +ifneq ($(filter y,$(CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR) $(CONFIG_SAVE_PREV_BL_FDT_ADDR)),) +obj-y += save_prev_bl_data.o +endif + +# obj-$(CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR) += save_prev_bl_data.o obj-y += bdinfo.o obj-y += sections.o CFLAGS_REMOVE_sections.o := $(LTO_CFLAGS) diff --git a/arch/arm/lib/save_prev_bl_data.c b/arch/arm/lib/save_prev_bl_data.c new file mode 100644 index 0000000000..f4ee86a89c --- /dev/null +++ b/arch/arm/lib/save_prev_bl_data.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * save_prev_bl_data - saving previous bootloader data + * to environment variables. + * + * Copyright (c) 2022 Dzmitry Sankouski (dsankouski@gmail.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static ulong reg0 __section(".data"); + +/** + * Save x0 register value, assuming previous bootloader set it to + * point on loaded fdt or (for older linux kernels)atags. + */ +void save_boot_params(ulong r0) +{ + reg0 = r0; + save_boot_params_ret(); +} + +bool is_addr_accessible(phys_addr_t addr) +{ + struct mm_region *mem = mem_map; + phys_addr_t bank_start; + phys_addr_t bank_end; + + while (mem->size) { + bank_start = mem->phys; + bank_end = bank_start + mem->size; + debug("check if block %pap - %pap includes %pap\n", &bank_start, &bank_end, &addr); + if (addr > bank_start && addr < bank_end) + return true; + mem++; + } + + return false; +} + +int save_prev_bl_data(void) +{ + struct fdt_header *fdt_blob; + int node; + u64 initrd_start_prop; + + if (!is_addr_accessible((phys_addr_t)reg0)) + return -ENODATA; + + fdt_blob = (struct fdt_header *)reg0; + if (!fdt_valid(&fdt_blob)) { + pr_warn("%s: address 0x%lx is not a valid fdt\n", __func__, reg0); + return -ENODATA; + } + + if (CONFIG_IS_ENABLED(SAVE_PREV_BL_FDT_ADDR)) + env_set_addr("prevbl_fdt_addr", (void *)reg0); + if (!CONFIG_IS_ENABLED(SAVE_PREV_BL_INITRAMFS_START_ADDR)) + return 0; + + node = fdt_path_offset(fdt_blob, "/chosen"); + if (!node) { + pr_warn("%s: chosen node not found in device tree at addr: 0x%lx\n", + __func__, reg0); + return -ENODATA; + } + /* + * linux,initrd-start property might be either 64 or 32 bit, + * depending on primary bootloader implementation. + */ + initrd_start_prop = fdtdec_get_uint64(fdt_blob, node, "linux,initrd-start", 0); + if (!initrd_start_prop) { + debug("%s: attempt to get uint64 linux,initrd-start property failed, trying uint\n", + __func__); + initrd_start_prop = fdtdec_get_uint(fdt_blob, node, "linux,initrd-start", 0); + if (!initrd_start_prop) { + debug("%s: attempt to get uint failed, too\n", __func__); + return -ENODATA; + } + } + env_set_addr("prevbl_initrd_start_addr", (void *)initrd_start_prop); + + return 0; +} diff --git a/boot/Kconfig b/boot/Kconfig index c8d5906cd3..da2f0797e0 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -135,10 +135,10 @@ config FIT_IMAGE_POST_PROCESS processed before being added to the FIT image). config FIT_PRINT - bool "Support FIT printing" - default y - help - Support printing the content of the fitImage in a verbose manner. + bool "Support FIT printing" + default y + help + Support printing the content of the fitImage in a verbose manner. if SPL @@ -207,12 +207,12 @@ config SPL_LOAD_FIT This path has the following limitations: 1. "loadables" images, other than FDTs, which do not have a "load" - property will not be loaded. This limitation also applies to FPGA - images with the correct "compatible" string. + property will not be loaded. This limitation also applies to FPGA + images with the correct "compatible" string. 2. For FPGA images, only the "compatible" = "u-boot,fpga-legacy" - loading method is supported. + loading method is supported. 3. FDTs are only loaded for images with an "os" property of "u-boot". - "linux" images are also supported with Falcon boot mode. + "linux" images are also supported with Falcon boot mode. config SPL_LOAD_FIT_ADDRESS hex "load address of fit image" @@ -345,8 +345,8 @@ config SYS_EXTRA_OPTIONS The old configuration infrastructure (= mkconfig + boards.cfg) provided the extra options field. If you have something like "HAS_BAR,BAZ=64", the optional options - #define CONFIG_HAS - #define CONFIG_BAZ 64 + #define CONFIG_HAS + #define CONFIG_BAZ 64 will be defined in include/config.h. This option was prepared for the smooth migration from the old configuration to Kconfig. Since this option will be removed sometime, @@ -380,7 +380,7 @@ config SYS_CLK_FREQ int "CPU clock frequency" default 125000000 if ARCH_LS1012A default 100000000 if ARCH_P2020 || ARCH_T1024 || ARCH_T1042 || \ - ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 + ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 default 66666666 if ARCH_P1010 || ARCH_P1020 || ARCH_T4240 default 66660000 if ARCH_T2080 default 33333333 if RCAR_GEN3 @@ -485,15 +485,15 @@ config BOOTSTAGE_REPORT boot process. The report looks something like this: Timer summary in microseconds: - Mark Elapsed Stage - 0 0 reset + Mark Elapsed Stage + 0 0 reset 3,575,678 3,575,678 board_init_f start - 3,575,695 17 arch_cpu_init A9 - 3,575,777 82 arch_cpu_init done - 3,659,598 83,821 board_init_r start - 3,910,375 250,777 main_loop + 3,575,695 17 arch_cpu_init A9 + 3,575,777 82 arch_cpu_init done + 3,659,598 83,821 board_init_r start + 3,910,375 250,777 main_loop 29,916,167 26,005,792 bootm_start - 30,361,327 445,160 start_kernel + 30,361,327 445,160 start_kernel config BOOTSTAGE_RECORD_COUNT int "Number of boot stage records to store" @@ -580,24 +580,24 @@ config SHOW_BOOT_PROGRESS Legacy uImage format: Arg Where When - 1 common/cmd_bootm.c before attempting to boot an image + 1 common/cmd_bootm.c before attempting to boot an image -1 common/cmd_bootm.c Image header has bad magic number - 2 common/cmd_bootm.c Image header has correct magic number + 2 common/cmd_bootm.c Image header has correct magic number -2 common/cmd_bootm.c Image header has bad checksum - 3 common/cmd_bootm.c Image header has correct checksum + 3 common/cmd_bootm.c Image header has correct checksum -3 common/cmd_bootm.c Image data has bad checksum - 4 common/cmd_bootm.c Image data has correct checksum + 4 common/cmd_bootm.c Image data has correct checksum -4 common/cmd_bootm.c Image is for unsupported architecture - 5 common/cmd_bootm.c Architecture check OK + 5 common/cmd_bootm.c Architecture check OK -5 common/cmd_bootm.c Wrong Image Type (not kernel, multi) - 6 common/cmd_bootm.c Image Type check OK + 6 common/cmd_bootm.c Image Type check OK -6 common/cmd_bootm.c gunzip uncompression error -7 common/cmd_bootm.c Unimplemented compression type - 7 common/cmd_bootm.c Uncompression OK - 8 common/cmd_bootm.c No uncompress/copy overwrite error + 7 common/cmd_bootm.c Uncompression OK + 8 common/cmd_bootm.c No uncompress/copy overwrite error -9 common/cmd_bootm.c Unsupported OS (not Linux, BSD, VxWorks, QNX) - 9 common/image.c Start initial ramdisk verification + 9 common/image.c Start initial ramdisk verification -10 common/image.c Ramdisk header has bad magic number -11 common/image.c Ramdisk header has bad checksum 10 common/image.c Ramdisk header is OK @@ -1067,4 +1067,29 @@ config DEFAULT_FDT_FILE help This option is used to set the default fdt file to boot OS. +config SAVE_PREV_BL_FDT_ADDR + depends on ARM + bool "Saves fdt address, passed by the previous bootloader, to env var" + default n + help + When u-boot is used as a chain-loaded bootloader (replacing OS kernel), + enable this option to save fdt address, passed by the + previous bootloader for future use. + Address is saved to `prevbl_fdt_addr` environment variable. + + If no fdt was provided by previous bootloader, no env variables + will be created. + +config SAVE_PREV_BL_INITRAMFS_START_ADDR + depends on ARM + bool "Saves initramfs address, passed by the previous bootloader, to env var" + default n + help + When u-boot is used as a chain-loaded bootloader(replacing OS kernel), + enable this option to save initramfs address, passed by the + previous bootloader for future use. + Address is saved to `prevbl_initrd_start_addr` environment variable. + + If no initramfs was provided by previous bootloader, no env variables + will be created. endmenu # Booting diff --git a/common/board_r.c b/common/board_r.c index c24d9b4e22..5b717e2162 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -445,6 +445,11 @@ static int initr_env(void) env_set_hex("fdtcontroladdr", (unsigned long)map_to_sysmem(gd->fdt_blob)); + #if (CONFIG_IS_ENABLED(SAVE_PREV_BL_INITRAMFS_START_ADDR) || \ + CONFIG_IS_ENABLED(SAVE_PREV_BL_FDT_ADDR)) + save_prev_bl_data(); + #endif + /* Initialize from environment */ image_load_addr = env_get_ulong("loadaddr", 16, image_load_addr); diff --git a/include/init.h b/include/init.h index 20c3976af0..1a55a0e2e4 100644 --- a/include/init.h +++ b/include/init.h @@ -166,6 +166,19 @@ int arch_setup_bdinfo(void); */ int setup_bdinfo(void); +#if defined(CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR) || \ +defined(CONFIG_SAVE_PREV_BL_FDT_ADDR) +/** + * save_prev_bl_data - Save prev bl data in env vars. + * + * When u-boot is chain-loaded, save previous bootloader data, + * like initramfs address to environment variables. + * + * Return: 0 if ok; -ENODATA on error + */ +int save_prev_bl_data(void); +#endif + /** * cpu_secondary_init_r() - CPU-specific secondary initialization * -- 2.20.1