[PATCH 6/7] docs: firmware: document the FW_DYNAMIC_APPEND firmware type
Zong Li <[email protected]> Mon, 6 Jul 2026 20:39:53 -0700
| Newsgroups | org.infradead.lists.opensbi |
|---|---|
| Message-ID | <[email protected]> |
Add docs/firmware/fw_dynamic_append.md describing the new firmware type: how it differs from FW_DYNAMIC, why struct fw_dynamic_info is appended before .bss (so it stays inside the flat .bin), the version 3 structure layout with the new boot_dtb field, that the previous stage patches every field at runtime, the boot register setup performed by fw_base.S, and how to build it. Signed-off-by: Zong Li <[email protected]> --- docs/firmware/fw_dynamic_append.md | 110 +++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 docs/firmware/fw_dynamic_append.md diff --git a/docs/firmware/fw_dynamic_append.md b/docs/firmware/fw_dynamic_append.md new file mode 100644 index 00000000..25e951d9 --- /dev/null +++ b/docs/firmware/fw_dynamic_append.md @@ -0,0 +1,110 @@ +OpenSBI Firmware with Appended Dynamic Information (FW_DYNAMIC_APPEND) +===================================================================== + +OpenSBI **firmware with appended dynamic info (FW_DYNAMIC_APPEND)** is a +variant of the FW_DYNAMIC firmware. Like FW_DYNAMIC, it gets information +about the next booting stage (e.g. a bootloader or an OS) and runtime +OpenSBI library options from a *struct fw_dynamic_info*. + +The difference is *how* that structure is delivered: + +* For *FW_DYNAMIC*, the previous booting stage creates a struct fw_dynamic_info + in memory and passes its address to OpenSBI via the *a2* register. +* For *FW_DYNAMIC_APPEND*, the struct fw_dynamic_info is *appended into the + OpenSBI binary itself*. It is laid out immediately before the *.bss* section so + that it is the last byte-content of the flat binary (`.bin`) image. The + previous booting stage locates the structure at the tail of the image, patches + its fields at runtime, and then jumps to the OpenSBI entry point *without* + having to set up the a0/a1/a2 registers. + +A FW_DYNAMIC_APPEND firmware is useful when the previous booting stage cannot +easily allocate a separate struct fw_dynamic_info and pass its pointer in a2, +but can load the OpenSBI image and patch a few words at a known offset (the en +of the file) before jumping to it. For example, the previous boot stage runs on +a dedicated hart. Therefore, it cannot set up CSRs of another hart that runs +OpenSBI. This scenario will occurs in server systems with secure boot. + +Why the structure is placed before .bss +--------------------------------------- + +The flat `.bin` image is produced with `objcopy -O binary`. The *.bss* section +has type NOBITS and is therefore *not* stored in the file. It does not count +towards the binary file size. If the appended struct fw_dynamic_info were placed +after *.bss*, it would not be part of the `.bin` file and the previous booting +stage would compute the wrong address for it. + +By placing the structure right before *.bss*, it becomes the last PROGBITS +content and sits exactly at the tail of the `.bin` file: + +``` + .text | .rodata | .rela.dyn | .data | .fw_dynamic_info | .bss (NOBITS, dropped) + <------------------- .bin file size -------------------><--- not in file ---> + ^ struct fw_dynamic_info (image tail) +``` + +The previous booting stage can therefore find the structure at: + +``` + struct_addr = load_address + binary_file_size - sizeof(struct fw_dynamic_info) +``` + +The structure layout +--------------------- + +FW_DYNAMIC_APPEND uses struct fw_dynamic_info version 3, which adds a *boot_dtb* +field after *boot_hart*: + +| Field | Notes | +|------------|-----------------------------------------| +| magic | 'OSBI' (0x4942534f), patched at runtime | +| version | 3, patched at runtime | +| next_addr | next stage entry, patched at runtime | +| next_mode | next stage privilege mode | +| options | OpenSBI library options | +| boot_hart | preferred boot HART id (-1 = lottery) | +| boot_dtb | DTB address, patched at runtime | + +In the OpenSBI image the structure is reserved as all zeros. It is a placeholder +only. The previous booting stage is responsible for patching *every* field, +before jumping to OpenSBI. Because the reserved block is a PROGBITS section that +is KEEP() in the linker script, the zero bytes are still emitted at the tail of +the `.bin` (unlike a NOBITS/.bss reservation, which would be dropped). + +Boot register setup +------------------- + +Because the previous booting stage does not pass a0/a1/a2, the OpenSBI cold-boot +entry path (in firmware/fw_base.S, guarded by FW_DYNAMIC_APPEND) synthesizes the +expected boot state: + +* all general purpose registers are cleared to a known state, +* *a0* is loaded with the current *mhartid*, +* *a2* is pointed at the appended struct fw_dynamic_info, and +* *a1* is loaded with the *boot_dtb* field from that structure, but only when + the appended structure reports version >= FW_DYNAMIC_INFO_VERSION_3 (the + version that introduced *boot_dtb*). For an older layout that lacks the + field, *a1* is left at 0 rather than reading past the end of the structure. + +From this point the boot flow is identical to FW_DYNAMIC. Only the cold-boot path +is affected, secondary HARTs enter through the warm-boot path unchanged. + +FW_DYNAMIC_APPEND Compilation +----------------------------- + +A platform can enable FW_DYNAMIC_APPEND firmware using any of the following +methods: + +1. Specifying *FW_DYNAMIC_APPEND=y* on the top level make command line. +2. Specifying *FW_DYNAMIC_APPEND=y* in the target platform *objects.mk* + configuration file. + +For example: + +``` +make PLATFORM=<platform_subdir> FW_DYNAMIC_APPEND=y +``` + +The compiled FW_DYNAMIC_APPEND firmware ELF file is named *fw_dynamic_append.elf*. +Its expanded image file is *fw_dynamic_append.bin*. Both files are created in the +platform specific build directory under the +*build/platform/<platform_subdir>/firmware* directory. -- 2.43.7 -- opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi