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 <dsankou...@gmail.com>
Cc: Tom Rini <tr...@konsulko.com>
---
Changes for v2:
- change signed off line

 arch/arm/lib/Makefile            |  2 +
 arch/arm/lib/save_prev_bl_data.c | 93 ++++++++++++++++++++++++++++++++
 boot/Kconfig                     | 79 +++++++++++++++++----------
 include/init.h                   | 13 +++++
 4 files changed, 160 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..aacd2253da 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -48,6 +48,8 @@ obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o
 endif
 obj-$(CONFIG_SEMIHOSTING) += semihosting.o
 
+obj-$(filter y, $(CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR) 
$(CONFIG_SAVE_PREV_BL_FDT_ADDR)) += save_prev_bl_data.o
+# 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..2f88874484
--- /dev/null
+++ b/arch/arm/lib/save_prev_bl_data.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * save_prev_bl_data - saving previous bootloader data
+ * to environment variables.
+ *
+ * Copyright (c) 2022 Dzmitry Sankouski (dsankou...@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 defined(CONFIG_SAVE_PREV_BL_FDT_ADDR)
+               env_set_addr("prevbl_fdt_addr", (void *)reg0);
+       #endif
+       #if !defined(CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR)
+               return 0;
+       #endif
+
+       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/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

Reply via email to