From 1c08ff3277d47979c7897842ba683c23aa8197f7 Mon Sep 17 00:00:00 2001 From: Salman Nabi Date: Thu, 12 Dec 2024 17:38:54 +0000 Subject: [PATCH 1/6] feat(arm): add initrd props to dtb at build time Add initrd properties to the device tree blob at build time, giving users the ability to run a linux kernel and successfully boot it to the terminal. Users can boot a linux kernel in a normal flow as well as in RESET_TO_BL31. This function is an extension of the build time option "ARM_LINUX_KERNEL_AS_BL33=1". The build time options INITRD_SIZE or INITRD_PATH will trigger the insertion of initrd properties in to the DTB. If both options are provided then the INITRD_SIZE will take precedence. The available options are: INITRD_SIZE: Provide the initrd size in dec or hex (hex format must precede with '0x'. Example: INITRD_SIZE=0x1000000 INITRD_PATH: Provide an initrd path for the build time to find its exact size. INITRD_BASE: A required build time option that sets the initrd base address in hex format. A default value can be set by the platform. Example: INITRD_BASE=0x90000000 Change-Id: Ief8de5f00c453509bcc6e978e0a95d768f1f509c Signed-off-by: Salman Nabi --- Makefile | 15 +++++++++++++++ make_helpers/build_macros.mk | 1 + plat/arm/board/fvp/platform.mk | 5 ++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 413ce46be..26636c8c9 100644 --- a/Makefile +++ b/Makefile @@ -1638,6 +1638,21 @@ endif #(NEED_BL2U) # Expand build macros for the different images ifeq (${NEED_FDT},yes) $(eval $(call MAKE_DTBS,$(BUILD_PLAT)/fdts,$(FDT_SOURCES))) + + ifneq (${INITRD_SIZE}${INITRD_PATH},) + ifndef INITRD_BASE + $(error INITRD_BASE must be set when inserting initrd properties to the DTB.) + endif + + INITRD_SIZE ?= $(shell printf "0x%x\n" $$(stat -Lc %s $(INITRD_PATH))) + initrd_end = $(shell printf "0x%x\n" $$(expr $$(($(INITRD_BASE) + $(INITRD_SIZE))))) + + define $(HW_CONFIG)-after += + $(s)echo " INITRD $(HW_CONFIG)" + $(q)fdtput -t x $@ /chosen linux,initrd-start $(INITRD_BASE) + $(q)fdtput -t x $@ /chosen linux,initrd-end $(initrd_end) + endef + endif endif #(NEED_FDT) # Add Secure Partition packages diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk index b1b299cd9..aa1675193 100644 --- a/make_helpers/build_macros.mk +++ b/make_helpers/build_macros.mk @@ -604,6 +604,7 @@ $(DPRE): $(2) | $$$$(@D)/ $(DOBJ): $(DPRE) $(filter-out %.d,$(MAKEFILE_LIST)) | $$$$(@D)/ $$(s)echo " DTC $$<" $$(q)$($(ARCH)-dtc) $$(DTC_FLAGS) -d $(DTBDEP) -o $$@ $$< + $$($$@-after) -include $(DTBDEP) -include $(DTSDEP) diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 1dd0b4930..5472a327e 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -367,6 +367,10 @@ FVP_HW_CONFIG_DTS := fdts/${FVP_DT_PREFIX}.dts FDT_SOURCES += ${FVP_HW_CONFIG_DTS} $(eval FVP_HW_CONFIG := ${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS))) +HW_CONFIG := ${FVP_HW_CONFIG} + +# Set default initrd base 128MiB offset of the default kernel address in FVP +INITRD_BASE ?= 0x90000000 ifeq (${TRANSFER_LIST}, 0) FDT_SOURCES += $(addprefix plat/arm/board/fvp/fdts/, \ @@ -419,7 +423,6 @@ ifeq (${TRANSFER_LIST}, 1) include lib/transfer_list/transfer_list.mk ifeq ($(RESET_TO_BL31), 1) -HW_CONFIG := ${FVP_HW_CONFIG} FW_HANDOFF_SIZE := 20000 TRANSFER_LIST_DTB_OFFSET := 0x20 From 1a219805187d0fe1194e4d0214313cbbe3783f2e Mon Sep 17 00:00:00 2001 From: Salman Nabi Date: Wed, 18 Dec 2024 11:00:17 +0000 Subject: [PATCH 2/6] docs(arm): add initrd props to dtb at build time Document the ability of the FVP platform to boot a Linux Kernel as a preloaded image. A preloaded Linux Kernel can be booted in a normal flow as well as in RESET_TO_BL31. This is made possible by updating the device tree with initrd properties at build time. Change-Id: I4e1d8c24f82510d21b2afa06b429a18da4d623bd Signed-off-by: Salman Nabi --- docs/plat/arm/fvp/fvp-specific-configs.rst | 131 +++++++++++---------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/docs/plat/arm/fvp/fvp-specific-configs.rst b/docs/plat/arm/fvp/fvp-specific-configs.rst index 63b3c31cc..a7fac913b 100644 --- a/docs/plat/arm/fvp/fvp-specific-configs.rst +++ b/docs/plat/arm/fvp/fvp-specific-configs.rst @@ -73,85 +73,96 @@ used: The address provided to the FVP must match the ``EL3_PAYLOAD_BASE`` address used when building TF-A. -Booting a preloaded kernel image (Base FVP) -------------------------------------------- +Booting a preloaded kernel image +-------------------------------- -The following example uses a simplified boot flow by directly jumping from the -TF-A to the Linux kernel, which will use a ramdisk as filesystem. This can be -useful if both the kernel and the device tree blob (DTB) are already present in -memory (like in FVP). +TF-A can boot a Linux kernel, which uses a ramdisk as a filesystem. The +required initrd properties are injected in to the device tree blob (DTB) at +build time. -For example, if the kernel is loaded at ``0x80080000`` and the DTB is loaded at -address ``0x82000000``, the firmware can be built like this: +Preloaded kernel image - Normal flow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following example uses a simplified boot flow to boot a Linux kernel +using TF-A. This can be useful if the kernel is already present in memory +(like in FVP). + +For example, if the kernel is loaded at ``0x80080000`` the firmware can be +built like this: .. code:: shell - CROSS_COMPILE=aarch64-none-elf- \ make PLAT=fvp DEBUG=1 \ - RESET_TO_BL31=1 \ ARM_LINUX_KERNEL_AS_BL33=1 \ PRELOADED_BL33_BASE=0x80080000 \ - ARM_PRELOADED_DTB_BASE=0x82000000 \ + INITRD_SIZE=0x8000000 \ all fip -Now, it is needed to modify the DTB so that the kernel knows the address of the -ramdisk. The following script generates a patched DTB from the provided one, -assuming that the ramdisk is loaded at address ``0x84000000``. Note that this -script assumes that the user is using a ramdisk image prepared for U-Boot, like -the ones provided by Linaro. If using a ramdisk without this header,the ``0x40`` -offset in ``INITRD_START`` has to be removed. +The options ``INITRD_SIZE`` or ``INITRD_PATH`` triggers the insertion of initrd +properties in to the DTB. ``INITRD_BASE`` is also required but a default value +is set by the FVP platform. -.. code:: bash +The options available here are: - #!/bin/bash + :: + INITRD_BASE: Set the initrd base address in memory. Defaults to 0x90000000 in FVP. + INITRD_SIZE: Set the initrd size in dec or hex format. Hex format must precede with '0x'. + INITRD_PATH: Provide an initrd path for the build time to determine its exact size. - # Path to the input DTB - KERNEL_DTB=/ - # Path to the output DTB - PATCHED_KERNEL_DTB=/ - # Base address of the ramdisk - INITRD_BASE=0x84000000 - # Path to the ramdisk - INITRD=/ +Users can provide either ``INITRD_SIZE`` or ``INITRD_PATH`` to set the initrd +size value. ``INITRD_SIZE`` takes prioty over ``INITRD_PATH``. - # Skip uboot header (64 bytes) - INITRD_START=$(printf "0x%x" $((${INITRD_BASE} + 0x40)) ) - INITRD_SIZE=$(stat -Lc %s ${INITRD}) - INITRD_END=$(printf "0x%x" $((${INITRD_BASE} + ${INITRD_SIZE})) ) - - CHOSEN_NODE=$(echo \ - "/ { \ - chosen { \ - linux,initrd-start = <${INITRD_START}>; \ - linux,initrd-end = <${INITRD_END}>; \ - }; \ - };") - - echo $(dtc -O dts -I dtb ${KERNEL_DTB}) ${CHOSEN_NODE} | \ - dtc -O dtb -o ${PATCHED_KERNEL_DTB} - - -And the FVP binary can be run with the following command: +Now the FVP binary can be run with the following command: .. code:: shell /FVP_Base_AEMv8A-AEMv8A \ - -C pctl.startup=0.0.0.0 \ - -C bp.secure_memory=1 \ - -C cluster0.NUM_CORES=4 \ - -C cluster1.NUM_CORES=4 \ - -C cache_state_modelled=1 \ - -C cluster0.cpu0.RVBAR=0x04001000 \ - -C cluster0.cpu1.RVBAR=0x04001000 \ - -C cluster0.cpu2.RVBAR=0x04001000 \ - -C cluster0.cpu3.RVBAR=0x04001000 \ - -C cluster1.cpu0.RVBAR=0x04001000 \ - -C cluster1.cpu1.RVBAR=0x04001000 \ - -C cluster1.cpu2.RVBAR=0x04001000 \ - -C cluster1.cpu3.RVBAR=0x04001000 \ - --data cluster0.cpu0="/bl31.bin"@0x04001000 \ - --data cluster0.cpu0="/"@0x82000000 \ + -C bp.secureflashloader.fname=/bl1.bin \ + -C bp.flashloader0.fname=/fip.bin \ --data cluster0.cpu0="/"@0x80080000 \ - --data cluster0.cpu0="/"@0x84000000 + --data cluster0.cpu0="/"@0x90000000 + +.. note:: + Providing a higher value for an initrd size than the actual size of the file + is supported but it will trigger a non-breaking "Initramfs unpacking failed" + error by the kernel at runtime. This error can be ignored because initrd's + can be stacked one after another, when the kernel unpacks the first initrd it + looks for another in the extra space which it won't find, hence the error. + +Booting a preloaded kernel image - Reset to BL31 (Base FVP) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We can also boot a Linux kernel by jumping directly to BL31 ``RESET_TO_BL31=1``. +This requires preloading a DTB into memory. We can inject the initrd start and +end properties into the DTB (HW_CONFIG) at build time which is then stored by +TF-A in ``build/fvp//fdts/`` directory. + +For example, we can build the firmware as: + +.. code:: shell + + make PLAT=fvp DEBUG=1 \ + RESET_TO_BL31=1 \ + ARM_LINUX_KERNEL_AS_BL33=1 \ + PRELOADED_BL33_BASE=0x80080000 \ + ARM_PRELOADED_DTB_BASE=0x87F00000 \ + INITRD_BASE=0x88000000 \ + INITRD_PATH=/initrd.bin + +Now we can run the binary as: + +.. code:: shell + + /FVP_Base_AEMv8A-AEMv8A \ + -C cluster0.NUM_CORES=4 \ + -C cluster0.cpu0.RVBAR=0x04001000 \ + -C cluster0.cpu1.RVBAR=0x04001000 \ + -C cluster0.cpu2.RVBAR=0x04001000 \ + -C cluster0.cpu3.RVBAR=0x04001000 \ + --data cluster0.cpu0="/bl31.bin"@0x04001000 \ + --data cluster0.cpu0="/"@0x80080000 \ + --data cluster0.cpu0="/"@0x88000000 \ + --data cluster0.cpu0="/fdts/fvp-base-gicv3-psci.dtb"@87F00000 Obtaining the Flattened Device Trees ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 0d49a415029532cd7c64d7961ff77c3b6e13042d Mon Sep 17 00:00:00 2001 From: Salman Nabi Date: Wed, 18 Dec 2024 11:04:18 +0000 Subject: [PATCH 3/6] docs(fvp): update fvp build time options Add new fvp specific build time options. Specifically the below: - INITRD_SIZE - INITRD_PATH - INITRD_BASE Change-Id: Ieadf01fce7a0a0a8e9e7582d7b7e371b247207c2 Signed-off-by: Salman Nabi --- docs/plat/arm/fvp/fvp-build-options.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/plat/arm/fvp/fvp-build-options.rst b/docs/plat/arm/fvp/fvp-build-options.rst index b0359fa91..79dc0dcf0 100644 --- a/docs/plat/arm/fvp/fvp-build-options.rst +++ b/docs/plat/arm/fvp/fvp-build-options.rst @@ -46,6 +46,16 @@ Arm FVP Platform Specific Build Options is ``0``, which means the redistributor pages of all CPU cores are marked as read and write. +- ``INITRD_SIZE`` : Enable the insertion of initrd properties to the device + tree blob at build time. Takes an initrd size value in hex format + +- ``INITRD_PATH`` : Enable the insertion of initrd properties to the device tree + blob at build time. Takes a path to an initrd file. Can be used as an + alternative to ``INITRD_SIZE``. ``INITRD_SIZE`` takes precedence over + ``INITRD_PATH`` if both values are provided. + +- ``INITRD_BASE`` : Provide the preloaded initrd base address in memory (hex format). + -------------- -*Copyright (c) 2019-2024, Arm Limited. All rights reserved.* +*Copyright (c) 2019-2025, Arm Limited. All rights reserved.* From eb8cb9534b58537e4ead8d1f8112ece45993c86d Mon Sep 17 00:00:00 2001 From: Salman Nabi Date: Wed, 18 Dec 2024 14:46:43 +0000 Subject: [PATCH 4/6] feat(arm): enable Linux boot from fip as BL33 Disable the reliance of ARM_LINUX_KERNEL_AS_BL33 on PRELOADED_BL33_BASE so that a Linux Kernel can be loaded and booted from the fip as BL33. Change-Id: I0437eec852cf17e0ed37a7ff77fcc4e66b1cea7a Signed-off-by: Salman Nabi --- plat/arm/common/arm_common.mk | 3 --- 1 file changed, 3 deletions(-) diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index 580ef5fa1..6d59bae63 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -108,9 +108,6 @@ ifeq (${ARM_LINUX_KERNEL_AS_BL33},1) $(error ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_SP_MIN=1.) endif endif - ifndef PRELOADED_BL33_BASE - $(error PRELOADED_BL33_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.) - endif ifeq (${RESET_TO_BL31},1) ifndef ARM_PRELOADED_DTB_BASE $(error ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used with RESET_TO_BL31.) From 2de9a254c8add40b9a49ee4fb1a85a6beba7d2c8 Mon Sep 17 00:00:00 2001 From: Salman Nabi Date: Wed, 18 Dec 2024 15:52:16 +0000 Subject: [PATCH 5/6] docs(arm): enable Linux boot from fip as BL33 Document additional functionality of TF-A to package the Linux kernel in the fip image as a BL33 and boot it. A ramdisk is used as a file system. The ramdisk properties are injected in to the device tree at build time. Change-Id: I326f920fdac4bd20572f6f0da07d012def114274 Signed-off-by: Salman Nabi --- docs/plat/arm/fvp/fvp-specific-configs.rst | 76 +++++++++++++++------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/docs/plat/arm/fvp/fvp-specific-configs.rst b/docs/plat/arm/fvp/fvp-specific-configs.rst index a7fac913b..0f51e4b35 100644 --- a/docs/plat/arm/fvp/fvp-specific-configs.rst +++ b/docs/plat/arm/fvp/fvp-specific-configs.rst @@ -73,13 +73,60 @@ used: The address provided to the FVP must match the ``EL3_PAYLOAD_BASE`` address used when building TF-A. -Booting a preloaded kernel image --------------------------------- +Booting a kernel image in BL33 +------------------------------ TF-A can boot a Linux kernel, which uses a ramdisk as a filesystem. The required initrd properties are injected in to the device tree blob (DTB) at build time. +Kernel image packaged in fip as a BL33 image +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A Linux kernel image can be packaged in the fip as a BL33 image and then +booted in TF-A. + +For example, the firmware can be built as: + +.. code:: shell + + make PLAT=fvp DEBUG=1 \ + ARM_LINUX_KERNEL_AS_BL33 \ + BL33= \ + INITRD_SIZE=0x8000000 \ + all fip + +The options ``INITRD_SIZE`` or ``INITRD_PATH`` triggers the insertion of initrd +properties in to the DTB. ``INITRD_BASE`` is also required but a default value +is set by the FVP platform. + +The options available here are: + +:: + + INITRD_BASE: Set the initrd base address in memory. Defaults to 0x90000000 in FVP. + INITRD_SIZE: Set the initrd size in dec or hex format. Hex format must precede with '0x'. + INITRD_PATH: Provide an initrd path for the build time to determine its exact size. + +Users can provide either ``INITRD_SIZE`` or ``INITRD_PATH`` to set the initrd +size value. ``INITRD_SIZE`` takes prioty over ``INITRD_PATH``. + +Now the fvp binary can be run as: + +.. code:: shell + + /FVP_Base_AEMv8A-AEMv8A \ + -C bp.secureflashloader.fname=/bl1.bin \ + -C bp.flashloader0.fname=/fip.bin \ + --data cluster0.cpu0="/"@0x90000000 + +.. note:: + Providing a higher value for an initrd size than the actual size of the file + is supported but it will trigger a non-breaking "Initramfs unpacking failed" + error by the kernel at runtime. This error can be ignored because initrd's + can be stacked one after another, when the kernel unpacks the first initrd it + looks for another in the extra space which it won't find, hence the error. + Preloaded kernel image - Normal flow ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,20 +145,6 @@ built like this: INITRD_SIZE=0x8000000 \ all fip -The options ``INITRD_SIZE`` or ``INITRD_PATH`` triggers the insertion of initrd -properties in to the DTB. ``INITRD_BASE`` is also required but a default value -is set by the FVP platform. - -The options available here are: - - :: - INITRD_BASE: Set the initrd base address in memory. Defaults to 0x90000000 in FVP. - INITRD_SIZE: Set the initrd size in dec or hex format. Hex format must precede with '0x'. - INITRD_PATH: Provide an initrd path for the build time to determine its exact size. - -Users can provide either ``INITRD_SIZE`` or ``INITRD_PATH`` to set the initrd -size value. ``INITRD_SIZE`` takes prioty over ``INITRD_PATH``. - Now the FVP binary can be run with the following command: .. code:: shell @@ -122,15 +155,8 @@ Now the FVP binary can be run with the following command: --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x90000000 -.. note:: - Providing a higher value for an initrd size than the actual size of the file - is supported but it will trigger a non-breaking "Initramfs unpacking failed" - error by the kernel at runtime. This error can be ignored because initrd's - can be stacked one after another, when the kernel unpacks the first initrd it - looks for another in the extra space which it won't find, hence the error. - -Booting a preloaded kernel image - Reset to BL31 (Base FVP) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Preloaded kernel image - Reset to BL31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We can also boot a Linux kernel by jumping directly to BL31 ``RESET_TO_BL31=1``. This requires preloading a DTB into memory. We can inject the initrd start and From bf9a25f075c4c94a3d47bc54c1a8a7b964444ff1 Mon Sep 17 00:00:00 2001 From: Salman Nabi Date: Thu, 13 Feb 2025 13:23:43 +0000 Subject: [PATCH 6/6] feat(fvp): set defaults for build commandline When using ARM_LINUX_KERNEL_AS_BL33, set defaults for the below for increased build time efficiency: PRELOADED_BL33_BASE=0x80080000 This address supports older kernels before v5.7 ARM_PRELOADED_DTB_BASE=0x87F00000 (only in RESET_TO_BL31) 1MiB before the address 0x88000000 in FVP. 1MiB seems enough for the device tree blob (DTB). Change-Id: I0396b597485e163b43f7c6677c04fcc08db55aa8 Signed-off-by: Salman Nabi --- plat/arm/board/fvp/platform.mk | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 5472a327e..7bd2a1dae 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -372,6 +372,15 @@ HW_CONFIG := ${FVP_HW_CONFIG} # Set default initrd base 128MiB offset of the default kernel address in FVP INITRD_BASE ?= 0x90000000 +# Kernel base address supports Linux kernels before v5.7 +# DTB base 1MiB before normal base kernel address in FVP (0x88000000) +ifeq (${ARM_LINUX_KERNEL_AS_BL33},1) + PRELOADED_BL33_BASE ?= 0x80080000 + ifeq (${RESET_TO_BL31},1) + ARM_PRELOADED_DTB_BASE ?= 0x87F00000 + endif +endif + ifeq (${TRANSFER_LIST}, 0) FDT_SOURCES += $(addprefix plat/arm/board/fvp/fdts/, \ ${PLAT}_fw_config.dts \