From: Ahmad Fatoum <a.fatoum@barebox.org>
To: barebox@lists.infradead.org
Cc: mfe@pengutronix.de, mtr@pengutronix.de,
Ahmad Fatoum <a.fatoum@barebox.org>
Subject: [RFC PATCH 08/17] RISC-V: add PBL heads for the board info stage dispatch
Date: Tue, 27 Oct 2026 08:24:41 +0100 [thread overview]
Message-ID: <20261027074014.3280396-9-a.fatoum@barebox.org> (raw)
In-Reply-To: <20261027074014.3280396-1-a.fatoum@barebox.org>
Unlike on ARM, the privilege mode is part of the RISC-V boot protocol and
even the cache maintenance during relocation depends on it, so the head
needs to know which mode it was started in.
Let's add two heads: one for images that firmware enters in supervisor
mode like a Linux kernel, with the hart ID in a0 and the device tree in
a1, and one for images entered in machine mode without a boot protocol,
like Erizo and LiteX. Both lay out the same header as
__barebox_riscv_head(), so the image tools keep working, and branch to
pbl_head_start_v1(), which RISC-V implements in assembly.
Boards whose stage describes the memory for barebox proper can use the
new pbl_stage_barebox_entry() as chainload callback.
Assisted-by: Claude:fable-5.1
Assisted-by: Claude:opus-5.5
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
arch/riscv/Kconfig | 2 +
arch/riscv/boot/Makefile | 2 +-
arch/riscv/boot/entry.c | 16 ++
arch/riscv/boot/head.S | 198 +++++++++++++++++++++++++
arch/riscv/include/asm/barebox-riscv.h | 6 +
arch/riscv/lib/asm-offsets.c | 27 ++++
arch/riscv/lib/pbl.lds.S | 13 +-
7 files changed, 262 insertions(+), 2 deletions(-)
create mode 100644 arch/riscv/boot/entry.c
create mode 100644 arch/riscv/boot/head.S
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 40a79b6834ff..0041269123e3 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -20,6 +20,8 @@ config RISCV
select RISCV_TIMER if RISCV_SBI
select HW_HAS_PCI
select PBL_CONSTRUCTORS
+ select ARCH_HAS_PBL_ENTRY
+ select ARCH_HAS_PBL_HEAD_START_ASM
select PBL_IMAGE_ELF
select HAVE_ARCH_BOARD_GENERIC_DT
select HAVE_ARCH_BOOTM_OFTREE
diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile
index 2cd6f098d5ef..d98adf7f724b 100644
--- a/arch/riscv/boot/Makefile
+++ b/arch/riscv/boot/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-pbl-y += entry_ll.o uncompress.o
+pbl-y += head.o entry.o entry_ll.o uncompress.o
pbl-y += nmon_entry.o
pbl-$(CONFIG_BOARD_GENERIC_DT) += board-dt-2nd.o
diff --git a/arch/riscv/boot/entry.c b/arch/riscv/boot/entry.c
new file mode 100644
index 000000000000..11b66ab48b63
--- /dev/null
+++ b/arch/riscv/boot/entry.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <pbl/entry.h>
+#include <asm/barebox-riscv.h>
+
+/*
+ * soc_chainload callback for boards whose stage describes the memory for
+ * barebox proper. The head has already recorded the mode in the flags.
+ */
+void __noreturn pbl_stage_barebox_entry(void *boarddata)
+{
+ struct pbl_stage *stage = pbl_get_stage();
+
+ barebox_riscv_entry(stage->mem_start, stage->mem_minsz, boarddata,
+ riscv_get_flags());
+}
diff --git a/arch/riscv/boot/head.S b/arch/riscv/boot/head.S
new file mode 100644
index 000000000000..a205965e33ad
--- /dev/null
+++ b/arch/riscv/boot/head.S
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * PBL image heads for ENTRY_POINT() boards. The privilege mode is part of
+ * the RISC-V boot protocol and needed as early as the cache maintenance
+ * during relocation, so there is a head per mode, which records it like
+ * riscv_set_flags() would.
+ */
+
+/* Linker will point this at the selected board's struct pbl_board_info */
+.globl __pbl_board_info
+
+/*
+ * Same header as __barebox_riscv_head(), so the image tools keep working.
+ * Execution continues at \setup.
+ */
+.macro pbl_image_header setup
+ /* Relaxation and compressed instructions would shift the fields */
+ .option push
+ .option norelax
+ .option norvc
+ nop /* code0 */
+ j \setup /* code1 */
+ .balign 8
+ .dword 0 /* Image load offset from start of RAM */
+ .dword _barebox_image_size /* Effective Image size */
+ .dword 0 /* Kernel flags */
+ .word 0 /* version */
+ .word 0 /* reserved */
+ .dword 0 /* reserved */
+ .asciz "barebox" /* magic 1 */
+ .balign 8
+ .ascii "RSCV" /* magic 2 */
+ .word 0 /* reserved (PE-COFF offset) */
+ .option pop
+.endm
+
+/*
+ * Head for images entered like a Linux kernel: supervisor mode, hart ID
+ * in a0 for tp, where riscv_hartid() expects it, and the device tree in
+ * a1, which becomes entry_data.
+ */
+.section .text_head_prologue_v1_supervisor, "ax"
+ENTRY(__barebox_pbl_head_v1_supervisor)
+ pbl_image_header .Lsupervisor_setup
+
+.Lsupervisor_setup:
+ li fp, 0
+
+ li t0, RISCV_S_MODE_ASM
+ csrw sscratch, t0
+ mv tp, a0
+ mv a0, a1 /* entry_data = device tree */
+ tail pbl_head_start_v1
+ENDPROC(__barebox_pbl_head_v1_supervisor)
+
+/*
+ * Head for images entered in machine mode without a boot protocol, e.g.
+ * out of reset. a0 is passed on as entry_data.
+ */
+.section .text_head_prologue_v1_machine, "ax"
+ENTRY(__barebox_pbl_head_v1_machine)
+ pbl_image_header .Lmachine_setup
+
+.Lmachine_setup:
+ li fp, 0
+
+ li t0, RISCV_M_MODE_ASM
+ csrw mscratch, t0
+ tail pbl_head_start_v1
+ENDPROC(__barebox_pbl_head_v1_machine)
+
+/*
+ * asm_pbl_head_start_v1 - assembly version of pbl_head_start_v1()
+ *
+ * a0 = entry_data on entry, then struct pbl_board_info *
+ * a1 = struct pbl_stage * (may be NULL)
+ * s1 = entry_data
+ * s2 = runtime offset
+ * s3 = struct pbl_stage * across the prereloc_cpu_init() call
+ *
+ * s1-s3 are callee-saved, so they survive the callbacks.
+ */
+.section .text.asm_pbl_head_start_v1, "ax"
+ENTRY(asm_pbl_head_start_v1)
+ mv s1, a0
+
+ /* Board info pointers need the runtime offset until relocation ran */
+ call get_runtime_offset
+ mv s2, a0
+
+ lla a0, __pbl_board_info
+
+ /* Stage determination, mirroring pbl_determine_stage_idx() */
+ REG_L t0, PBI_LOCATE_PC(a0)
+ beqz t0, .Lscan
+
+ /* Must be a leaf function: there may be no stack yet */
+ add t0, t0, s2
+ jalr t0 /* returns stage index in a0 */
+ mv t1, a0 /* idx */
+ lla a0, __pbl_board_info
+ li a1, 0 /* pbl_stage(): NULL by default */
+
+ /*
+ * pbl_stage_case - one case of the pbl_stage() switch; the cases
+ * are mutually exclusive, so each falls through to the next.
+ */
+ .macro pbl_stage_case idx, offs
+ li t2, \idx
+ bne t1, t2, .Lnext_case\@
+ addi a1, a0, \offs
+.Lnext_case\@:
+ .endm
+
+ pbl_stage_case PBL_STAGE_ROM_ASM, PBI_ROM_STAGE
+ pbl_stage_case PBL_STAGE_OCRAM_ASM, PBI_FIRST_STAGE
+ pbl_stage_case PBL_STAGE_DRAM_ASM, PBI_SECOND_STAGE
+ j .Lhave_stage /* a1 stays NULL for other indices */
+
+.Lscan:
+ li a1, 0 /* earliest stage with entry */
+ auipc t3, 0 /* pc, as get_pc() does */
+
+ /*
+ * pbl_check_stage - one pbl_determine_stage_idx() iteration for the
+ * stage at byte offset \offs
+ */
+ .macro pbl_check_stage offs
+ addi t0, a0, \offs
+ /* stage_has_entry()? */
+ REG_L t4, PBS_SOC_INIT(t0)
+ REG_L t5, PBS_BOARD_INIT(t0)
+ or t4, t4, t5
+ REG_L t5, PBS_SOC_CHAINLOAD(t0)
+ or t4, t4, t5
+ beqz t4, .Lcheck_pc\@
+ bnez a1, .Lcheck_pc\@
+ mv a1, t0 /* earliest ?: stage */
+.Lcheck_pc\@:
+ /* pc_inside(mem_start, mem_maxsz ?: mem_minsz)? */
+ REG_L t4, PBS_MEM_START(t0)
+ REG_L t5, PBS_MEM_MAXSZ(t0)
+ bnez t5, .Lhave_memsz\@
+ REG_L t5, PBS_MEM_MINSZ(t0)
+.Lhave_memsz\@:
+ sub t4, t3, t4
+ bltu t4, t5, .Lfound
+ .endm
+
+ pbl_check_stage PBI_ROM_STAGE
+ pbl_check_stage PBI_FIRST_STAGE
+ pbl_check_stage PBI_SECOND_STAGE
+ j .Lhave_stage /* stage = earliest (a1) */
+.Lfound:
+ mv a1, t0
+
+.Lhave_stage:
+ /* Misconfigured board info; there may be no stack to call with */
+.Lno_stage:
+ beqz a1, .Lno_stage
+
+ /* stage->stacktop is a stack top or a PBL_STACKTOP_* value */
+ REG_L t0, PBS_STACKTOP(a1)
+ li t1, PBS_STACKTOP_BEFORE_BAREBOX
+ bne t0, t1, .Lnot_before_barebox
+ lla t0, __image_start
+ j .Lhave_stacktop
+.Lnot_before_barebox:
+ li t1, PBS_STACKTOP_AFTER_BAREBOX
+ bne t0, t1, .Lhave_stacktop
+ lla t0, __image_end
+ li t1, CONFIG_STACK_SIZE
+ add t0, t0, t1
+.Lhave_stacktop:
+ andi t0, t0, -16 /* ALIGN_DOWN(stacktop, 16) */
+ beqz t0, .Lstack_set
+ mv sp, t0
+.Lstack_set:
+ /* CPU init callback, unrelocated like assembly_locate_pc() above */
+ REG_L t0, PBS_CPU_INIT(a1)
+ beqz t0, .Lcpu_init_done
+ add t0, t0, s2
+ mv s3, a1
+ jalr t0
+ mv a1, s3
+.Lcpu_init_done:
+ mv a0, a1
+ mv a1, s1
+ tail pbl_head_reloc_v1 /* (a0 = stage, a1 = entry_data) */
+ENDPROC(asm_pbl_head_start_v1)
+
+#ifdef CONFIG_PBL_HEAD_START_ASM
+SYM_FUNC_ALIAS(pbl_head_start_v1, asm_pbl_head_start_v1)
+#endif
diff --git a/arch/riscv/include/asm/barebox-riscv.h b/arch/riscv/include/asm/barebox-riscv.h
index 4a7726ddc508..c7ca339607c4 100644
--- a/arch/riscv/include/asm/barebox-riscv.h
+++ b/arch/riscv/include/asm/barebox-riscv.h
@@ -33,6 +33,12 @@
barebox_riscv_entry(membase, memsize, boarddata, RISCV_S_MODE); \
} while (0)
+/* PBL image heads for ENTRY_POINT_HEAD(), see arch/riscv/boot/head.S */
+extern char __barebox_pbl_head_v1_supervisor[];
+extern char __barebox_pbl_head_v1_machine[];
+
+void __noreturn pbl_stage_barebox_entry(void *boarddata);
+
static inline unsigned long riscv_mem_stack_top(unsigned long membase,
unsigned long endmem)
{
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
index 48960e58a6bc..a7a092cb5d72 100644
--- a/arch/riscv/lib/asm-offsets.c
+++ b/arch/riscv/lib/asm-offsets.c
@@ -9,6 +9,8 @@
#include <linux/kbuild.h>
#include <linux/kernel.h>
#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <pbl/entry.h>
#define STACK_ALIGN 16
@@ -56,5 +58,30 @@ int main(void)
* We allocate a pt_regs on the stack. This ensures the alignment is sane.
*/
DEFINE(PT_SIZE_ON_STACK, ALIGN(sizeof(struct pt_regs), STACK_ALIGN));
+ BLANK();
+ COMMENT("struct pbl_board_info offsets");
+ OFFSET(PBI_LOCATE_PC, pbl_board_info, assembly_locate_pc);
+ OFFSET(PBI_ROM_STAGE, pbl_board_info, rom_stage);
+ OFFSET(PBI_FIRST_STAGE, pbl_board_info, first_stage);
+ OFFSET(PBI_SECOND_STAGE, pbl_board_info, second_stage);
+ DEFINE(PBI_SIZEOF, sizeof(struct pbl_board_info));
+ BLANK();
+ COMMENT("struct pbl_stage offsets");
+ OFFSET(PBS_STACKTOP, pbl_stage, stacktop);
+ OFFSET(PBS_MEM_START, pbl_stage, mem_start);
+ OFFSET(PBS_MEM_MINSZ, pbl_stage, mem_minsz);
+ OFFSET(PBS_MEM_MAXSZ, pbl_stage, mem_maxsz);
+ OFFSET(PBS_CPU_INIT, pbl_stage, prereloc_cpu_init);
+ OFFSET(PBS_SOC_INIT, pbl_stage, soc_init);
+ OFFSET(PBS_BOARD_INIT, pbl_stage, board_init);
+ OFFSET(PBS_SOC_CHAINLOAD, pbl_stage, soc_chainload);
+ BLANK();
+ DEFINE(PBL_STAGE_ROM_ASM, PBL_STAGE_ROM);
+ DEFINE(PBL_STAGE_OCRAM_ASM, PBL_STAGE_OCRAM);
+ DEFINE(PBL_STAGE_DRAM_ASM, PBL_STAGE_DRAM);
+ DEFINE(PBS_STACKTOP_BEFORE_BAREBOX, PBL_STACKTOP_BEFORE_BAREBOX);
+ DEFINE(PBS_STACKTOP_AFTER_BAREBOX, PBL_STACKTOP_AFTER_BAREBOX);
+ DEFINE(RISCV_S_MODE_ASM, RISCV_S_MODE);
+ DEFINE(RISCV_M_MODE_ASM, RISCV_M_MODE);
return 0;
}
diff --git a/arch/riscv/lib/pbl.lds.S b/arch/riscv/lib/pbl.lds.S
index e580ec06f32c..84c4917e67ad 100644
--- a/arch/riscv/lib/pbl.lds.S
+++ b/arch/riscv/lib/pbl.lds.S
@@ -5,6 +5,7 @@
#include <asm/barebox.lds.h>
#include <asm-generic/memory_layout.h>
#include <asm-generic/pointer.h>
+#include <asm/asm-offsets.h>
OUTPUT_ARCH(BAREBOX_OUTPUT_ARCH)
OUTPUT_FORMAT(BAREBOX_OUTPUT_FORMAT)
@@ -18,6 +19,9 @@ SECTIONS
.text :
{
_stext = .;
+ /* Custom image headers go before the common heads */
+ *(.text_image_header*)
+ *(.text_head_prologue*)
*(.text_head_entry*)
__bare_init_start = .;
*(.text_bare_init*)
@@ -28,8 +32,15 @@ SECTIONS
BAREBOX_BARE_INIT_SIZE
BAREBOX_PBL_SIZE
- . = ALIGN(4);
+ . = ALIGN(ASM_SZPTR);
__start_rodata = .;
+ __pbl_board_info = .;
+ .rodata.pbl_board_info : {
+ *(.pbl_board_info_*)
+ }
+ ASSERT(. - __pbl_board_info <= PBI_SIZEOF, "Only one PBL per image allowed")
+
+ . = ALIGN(4);
.rodata : { *(.rodata*) }
. = ALIGN(ASM_SZPTR);
--
2.47.3
next prev parent reply other threads:[~2026-10-27 7:50 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 7:24 [RFC PATCH 00/17] Switch RISC-V to declarative entry points Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 01/17] asm-generic: add registers.h with a pc_inside() helper Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 02/17] RISC-V: add call_with_stack() helper Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 03/17] RISC-V: implement relocate_to_adr_full() Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 04/17] PBL: add SoC type declaration and handoff support Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 05/17] PBL: introduce board info based entry point framework Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 06/17] PBL: describe the console in the board info and report the stage Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 07/17] RISC-V: make barebox_riscv_entry() non-naked Ahmad Fatoum
2026-10-27 7:24 ` Ahmad Fatoum [this message]
2026-10-27 7:24 ` [RFC PATCH 09/17] RISC-V: board-dt-2nd: migrate to board info entry point Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 10/17] RISC-V: hifive: " Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 11/17] RISC-V: allow relocating the PBL more than once Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 12/17] RISC-V: nmon: preserve s1-s3 for the caller Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 13/17] RISC-V: beaglev: migrate to board info entry point Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 14/17] RISC-V: allwinner-d1: " Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 15/17] RISC-V: erizo: " Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 16/17] RISC-V: litex-linux: " Ahmad Fatoum
2026-10-27 7:24 ` [RFC PATCH 17/17] Documentation: porting: describe the " Ahmad Fatoum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261027074014.3280396-9-a.fatoum@barebox.org \
--to=a.fatoum@barebox.org \
--cc=barebox@lists.infradead.org \
--cc=mfe@pengutronix.de \
--cc=mtr@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox