[PATCH 1/3] firmware: fw_base.S: add a formatted OpenSBI firmware header

Zong Li zong.li at sifive.com
Mon Aug 31 19:22:09 PDT 2026


Add a fixed 128-byte header at the very beginning of every OpenSBI
firmware image, regardless of the firmware type. The header lets the
previous booting stage identify an OpenSBI image and, more importantly,
gives it a well-known place inside the image to hand over information
to OpenSBI by patching a few words instead of setting up registers.

This first patch only introduces the layout:

  - a 4-byte jump over the header to _start_real, so that _start stays
    the entry point of the image. The jump is assembled with
    '.option norvc' so that the fields behind it are always at a fixed
    offset, even for a build with compressed instructions enabled,

  - the 'OSBI' magic, a header version, the XLEN the firmware was built
    for and the size of the firmware image, so that the previous booting
    stage can validate the image and figure out how much memory it
    occupies,

  - a flags word and three 8-byte override values, which are unused
    (and zero) for now and are wired up by the next patch.

The layout is deliberately identical for RV32 and RV64 so that the
previous booting stage can parse the header without knowing the XLEN of
the firmware upfront. Each override value is followed by a reserved
8-byte slot so that the same layout can be extended to RV128 later.

Suggested-by: Anup Patel <anup at brainfault.org>
Signed-off-by: Zong Li <zong.li at sifive.com>
---
 firmware/fw_base.S | 68 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/firmware/fw_base.S b/firmware/fw_base.S
index 0c5c65c1..dd2adb8a 100644
--- a/firmware/fw_base.S
+++ b/firmware/fw_base.S
@@ -17,6 +17,15 @@
 #define BOOT_LOTTERY_ACQUIRED		1
 #define BOOT_STATUS_BOOT_HART_DONE	1
 
+/* OpenSBI firmware header */
+#define FW_HEADER_MAGIC_VALUE		0x4942534f /* ASCII string "OSBI" */
+#define FW_HEADER_VERSION		0x1
+#define FW_HEADER_SIZE			128
+#define FW_HEADER_RESERVED_OFFSET	0x48
+#define FW_HEADER_FLAGS_OVERRIDE_A0	(1 << 0)
+#define FW_HEADER_FLAGS_OVERRIDE_A1	(1 << 1)
+#define FW_HEADER_FLAGS_OVERRIDE_A2	(1 << 2)
+
 .macro	MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
 	add	\__d0, \__s0, zero
 	add	\__d1, \__s1, zero
@@ -44,8 +53,67 @@
 	.section .entry, "ax", %progbits
 	.align 3
 	.globl _start
+	.globl _start_real
 	.globl _start_warm
 _start:
+	/*
+	 * OpenSBI firmware header
+	 *
+	 * Every OpenSBI firmware image starts with this fixed 128-byte
+	 * header. The layout is identical for RV32 and RV64 (and can be
+	 * extended for RV128 by using the reserved half of each override
+	 * field), so the previous booting stage can parse the header without
+	 * knowing the XLEN of the firmware upfront.
+	 *
+	 * Offset  Size  Field
+	 *   0x00     4  jump to _start_real
+	 *   0x04     4  magic ('OSBI')
+	 *   0x08     4  header version
+	 *   0x0c     4  firmware XLEN
+	 *   0x10     4  firmware size (_fw_end - _fw_start)
+	 *   0x14     4  flags (FW_HEADER_FLAGS_*)
+	 *   0x18     8  override value for a0
+	 *   0x20     8  reserved (upper half of the a0 value on RV128)
+	 *   0x28     8  override value for a1
+	 *   0x30     8  reserved (upper half of the a1 value on RV128)
+	 *   0x38     8  override value for a2
+	 *   0x40     8  reserved (upper half of the a2 value on RV128)
+	 *   0x48    56  reserved
+	 */
+_fw_header_jump:
+	/*
+	 * Must stay a 4-byte instruction so that the fields below are always
+	 * at a fixed offset. 'norvc' keeps the assembler from picking c.j and
+	 * 'norelax' keeps the linker from compressing it later on, which it
+	 * would otherwise happily do for a jump this short.
+	 */
+	.option push
+	.option norvc
+	.option norelax
+	j	_start_real
+	.option pop
+_fw_header_magic:
+	.word	FW_HEADER_MAGIC_VALUE
+_fw_header_version:
+	.word	FW_HEADER_VERSION
+_fw_header_xlen:
+	.word	__riscv_xlen
+_fw_header_size:
+	.word	(_fw_end - _fw_start)
+_fw_header_flags:
+	.word	0
+_fw_header_override_a0:
+	.dword	0
+	.dword	0			/* reserved */
+_fw_header_override_a1:
+	.dword	0
+	.dword	0			/* reserved */
+_fw_header_override_a2:
+	.dword	0
+	.dword	0			/* reserved */
+	/* Reserved, pads the header up to FW_HEADER_SIZE bytes */
+	.fill	(FW_HEADER_SIZE - FW_HEADER_RESERVED_OFFSET), 1, 0
+_start_real:
 	/* Find preferred boot HART id */
 	MOV_3R	s0, a0, s1, a1, s2, a2
 	call	fw_boot_hart
-- 
2.43.7




More information about the opensbi mailing list