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 <dsankouski@gmail.com> Cc: Tom Rini <trini@konsulko.com>
This commit is contained in:
parent
5c9b420ada
commit
12a3e1ada0
@ -48,6 +48,11 @@ obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o
|
||||
endif
|
||||
obj-$(CONFIG_$(SPL_TPL_)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)
|
||||
|
91
arch/arm/lib/save_prev_bl_data.c
Normal file
91
arch/arm/lib/save_prev_bl_data.c
Normal file
@ -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 <init.h>
|
||||
#include <env.h>
|
||||
#include <fdtdec.h>
|
||||
#include <fdt_support.h>
|
||||
#include <fdt.h>
|
||||
#include <common.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/armv8/mmu.h>
|
||||
|
||||
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;
|
||||
}
|
24
boot/Kconfig
24
boot/Kconfig
@ -1192,4 +1192,28 @@ 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"
|
||||
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"
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -155,6 +155,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
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user