forked from Mirrors/opensbi
firmware: Allow firmwares to provide next mode and options
This patch extends existing firmwares (i.e. fw_jump and fw_payload) to explicitly provide next mode and options to fw_base. We also introduce fw_save_info() which is called by fw_base very early on boot HART. This function can be used by existing firmwares (i.e. fw_jump and fw_payload) to save information passed by previous booting stage. Overall, this is a preparatory patch for implementing fw_dynamic. Signed-off-by: Anup Patel <anup.patel@wdc.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
@@ -13,6 +13,20 @@
|
|||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
|
||||||
|
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
|
||||||
|
add \__d0, \__s0, zero
|
||||||
|
add \__d1, \__s1, zero
|
||||||
|
add \__d2, \__s2, zero
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro MOV_5R __d0, __s0, __d1, __s1, __d2, __s2, __d3, __s3, __d4, __s4
|
||||||
|
add \__d0, \__s0, zero
|
||||||
|
add \__d1, \__s1, zero
|
||||||
|
add \__d2, \__s2, zero
|
||||||
|
add \__d3, \__s3, zero
|
||||||
|
add \__d4, \__s4, zero
|
||||||
|
.endm
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.globl _start
|
.globl _start
|
||||||
@@ -25,9 +39,15 @@ _start:
|
|||||||
csrr a6, CSR_MHARTID
|
csrr a6, CSR_MHARTID
|
||||||
blt zero, a6, _wait_for_boot_hart
|
blt zero, a6, _wait_for_boot_hart
|
||||||
|
|
||||||
|
/* Reset all registers for boot HART */
|
||||||
li ra, 0
|
li ra, 0
|
||||||
call _reset_regs
|
call _reset_regs
|
||||||
|
|
||||||
|
/* Allow main firmware to save info */
|
||||||
|
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
|
||||||
|
call fw_save_info
|
||||||
|
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||||
|
|
||||||
/* Preload HART details
|
/* Preload HART details
|
||||||
* s7 -> HART Count
|
* s7 -> HART Count
|
||||||
* s8 -> HART Stack Size
|
* s8 -> HART Stack Size
|
||||||
@@ -59,6 +79,7 @@ _scratch_init:
|
|||||||
sub tp, tp, a5
|
sub tp, tp, a5
|
||||||
|
|
||||||
/* Initialize scratch space */
|
/* Initialize scratch space */
|
||||||
|
/* Store fw_start and fw_size in scratch space */
|
||||||
la a4, _fw_start
|
la a4, _fw_start
|
||||||
la a5, _fw_end
|
la a5, _fw_end
|
||||||
mul t0, s7, s8
|
mul t0, s7, s8
|
||||||
@@ -66,27 +87,44 @@ _scratch_init:
|
|||||||
sub a5, a5, a4
|
sub a5, a5, a4
|
||||||
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
|
REG_S a4, SBI_SCRATCH_FW_START_OFFSET(tp)
|
||||||
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
|
REG_S a5, SBI_SCRATCH_FW_SIZE_OFFSET(tp)
|
||||||
/* Note: fw_next_arg1() uses a0, a1, and ra */
|
/* Store next arg1 in scratch space */
|
||||||
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
call fw_next_arg1
|
call fw_next_arg1
|
||||||
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
|
REG_S a0, SBI_SCRATCH_NEXT_ARG1_OFFSET(tp)
|
||||||
/* Note: fw_next_addr() uses a0, a1, and ra */
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
|
/* Store next address in scratch space */
|
||||||
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
call fw_next_addr
|
call fw_next_addr
|
||||||
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
|
REG_S a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
|
||||||
li a4, PRV_S
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
REG_S a4, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
|
/* Store next mode in scratch space */
|
||||||
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
|
call fw_next_mode
|
||||||
|
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
|
||||||
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
|
/* Store warm_boot address in scratch space */
|
||||||
la a4, _start_warm
|
la a4, _start_warm
|
||||||
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
|
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
|
||||||
|
/* Store platform address in scratch space */
|
||||||
la a4, platform
|
la a4, platform
|
||||||
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
|
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
|
||||||
|
/* Store hartid-to-scratch function address in scratch space */
|
||||||
la a4, _hartid_to_scratch
|
la a4, _hartid_to_scratch
|
||||||
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
|
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
|
||||||
|
/* Clear tmp0 in scratch space */
|
||||||
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
|
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||||
|
/* Store firmware options in scratch space */
|
||||||
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
#ifdef FW_OPTIONS
|
#ifdef FW_OPTIONS
|
||||||
li a4, FW_OPTIONS
|
li a4, FW_OPTIONS
|
||||||
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
|
||||||
#else
|
#else
|
||||||
REG_S zero, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
add a4, zero, zero
|
||||||
#endif
|
#endif
|
||||||
|
call fw_options
|
||||||
|
or a4, a4, a0
|
||||||
|
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
||||||
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
|
/* Move to next scratch space */
|
||||||
add t1, t1, t2
|
add t1, t1, t2
|
||||||
blt t1, s7, _scratch_init
|
blt t1, s7, _scratch_init
|
||||||
|
|
||||||
@@ -99,12 +137,10 @@ _bss_zero:
|
|||||||
blt a4, a5, _bss_zero
|
blt a4, a5, _bss_zero
|
||||||
|
|
||||||
/* Override pervious arg1 */
|
/* Override pervious arg1 */
|
||||||
add s0, a0, zero
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
add s1, a1, zero
|
|
||||||
call fw_prev_arg1
|
call fw_prev_arg1
|
||||||
add t1, a0, zero
|
add t1, a0, zero
|
||||||
add a0, s0, zero
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
add a1, s1, zero
|
|
||||||
beqz t1, _prev_arg1_override_done
|
beqz t1, _prev_arg1_override_done
|
||||||
add a1, t1, zero
|
add a1, t1, zero
|
||||||
_prev_arg1_override_done:
|
_prev_arg1_override_done:
|
||||||
@@ -122,13 +158,12 @@ _prev_arg1_override_done:
|
|||||||
li a3, ~(__SIZEOF_POINTER__ - 1)
|
li a3, ~(__SIZEOF_POINTER__ - 1)
|
||||||
li a4, 0xff
|
li a4, 0xff
|
||||||
/* t1 = destination FDT start address */
|
/* t1 = destination FDT start address */
|
||||||
add s0, a0, zero
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
add s1, a1, zero
|
|
||||||
call fw_next_arg1
|
call fw_next_arg1
|
||||||
add t1, a0, zero
|
add t1, a0, zero
|
||||||
add a0, s0, zero
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
add a1, s1, zero
|
|
||||||
beqz t1, _fdt_reloc_done
|
beqz t1, _fdt_reloc_done
|
||||||
|
beq t1, a1, _fdt_reloc_done
|
||||||
and t1, t1, a3
|
and t1, t1, a3
|
||||||
/* t0 = source FDT start address */
|
/* t0 = source FDT start address */
|
||||||
add t0, a1, zero
|
add t0, a1, zero
|
||||||
@@ -188,6 +223,7 @@ _wait_for_boot_hart:
|
|||||||
beqz a5, _wait_for_boot_hart
|
beqz a5, _wait_for_boot_hart
|
||||||
|
|
||||||
_start_warm:
|
_start_warm:
|
||||||
|
/* Reset all registers for non-boot HARTs */
|
||||||
li ra, 0
|
li ra, 0
|
||||||
call _reset_regs
|
call _reset_regs
|
||||||
|
|
||||||
@@ -430,7 +466,7 @@ _reset_regs:
|
|||||||
|
|
||||||
/* flush the instruction cache */
|
/* flush the instruction cache */
|
||||||
fence.i
|
fence.i
|
||||||
/* Reset all registers except ra, a0,a1 */
|
/* Reset all registers except ra, a0, a1 and a2 */
|
||||||
li sp, 0
|
li sp, 0
|
||||||
li gp, 0
|
li gp, 0
|
||||||
li tp, 0
|
li tp, 0
|
||||||
@@ -439,7 +475,6 @@ _reset_regs:
|
|||||||
li t2, 0
|
li t2, 0
|
||||||
li s0, 0
|
li s0, 0
|
||||||
li s1, 0
|
li s1, 0
|
||||||
li a2, 0
|
|
||||||
li a3, 0
|
li a3, 0
|
||||||
li a4, 0
|
li a4, 0
|
||||||
li a5, 0
|
li a5, 0
|
||||||
|
@@ -9,19 +9,37 @@
|
|||||||
|
|
||||||
#include "fw_base.S"
|
#include "fw_base.S"
|
||||||
|
|
||||||
|
.align 3
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.global fw_save_info
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||||
|
* The a0, a1, and a2 registers will be same as passed by
|
||||||
|
* previous booting stage.
|
||||||
|
* Nothing to be returned here.
|
||||||
|
*/
|
||||||
|
fw_save_info:
|
||||||
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.global fw_prev_arg1
|
.global fw_prev_arg1
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The previous arg1 should be returned in 'a0'.
|
||||||
|
*/
|
||||||
fw_prev_arg1:
|
fw_prev_arg1:
|
||||||
/* We return previous arg1 in 'a0' */
|
|
||||||
add a0, zero, zero
|
add a0, zero, zero
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.global fw_next_arg1
|
.global fw_next_arg1
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The next arg1 should be returned in 'a0'.
|
||||||
|
*/
|
||||||
fw_next_arg1:
|
fw_next_arg1:
|
||||||
/* We return next arg1 in 'a0' */
|
|
||||||
#ifdef FW_JUMP_FDT_ADDR
|
#ifdef FW_JUMP_FDT_ADDR
|
||||||
li a0, FW_JUMP_FDT_ADDR
|
li a0, FW_JUMP_FDT_ADDR
|
||||||
#else
|
#else
|
||||||
@@ -32,12 +50,38 @@ fw_next_arg1:
|
|||||||
.align 3
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.global fw_next_addr
|
.global fw_next_addr
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The next address should be returned in 'a0'.
|
||||||
|
*/
|
||||||
fw_next_addr:
|
fw_next_addr:
|
||||||
/* We return next address in 'a0' */
|
|
||||||
la a0, _jump_addr
|
la a0, _jump_addr
|
||||||
REG_L a0, (a0)
|
REG_L a0, (a0)
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.align 3
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.global fw_next_mode
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The next address should be returned in 'a0'
|
||||||
|
*/
|
||||||
|
fw_next_mode:
|
||||||
|
li a0, PRV_S
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 3
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.global fw_options
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The 'a4' register will have default options.
|
||||||
|
* The next address should be returned in 'a0'.
|
||||||
|
*/
|
||||||
|
fw_options:
|
||||||
|
add a0, zero, zero
|
||||||
|
ret
|
||||||
|
|
||||||
#ifndef FW_JUMP_ADDR
|
#ifndef FW_JUMP_ADDR
|
||||||
#error "Must define FW_JUMP_ADDR"
|
#error "Must define FW_JUMP_ADDR"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -9,11 +9,26 @@
|
|||||||
|
|
||||||
#include "fw_base.S"
|
#include "fw_base.S"
|
||||||
|
|
||||||
.align 4
|
.align 3
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.global fw_save_info
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, a2, a3, and a4 registers here.
|
||||||
|
* The a0, a1, and a2 registers will be same as passed by
|
||||||
|
* previous booting stage.
|
||||||
|
* Nothing to be returned here.
|
||||||
|
*/
|
||||||
|
fw_save_info:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.global fw_prev_arg1
|
.global fw_prev_arg1
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The previous arg1 should be returned in 'a0'.
|
||||||
|
*/
|
||||||
fw_prev_arg1:
|
fw_prev_arg1:
|
||||||
/* We return previous arg1 in 'a0' */
|
|
||||||
#ifdef FW_PAYLOAD_FDT_PATH
|
#ifdef FW_PAYLOAD_FDT_PATH
|
||||||
la a0, fdt_bin
|
la a0, fdt_bin
|
||||||
#else
|
#else
|
||||||
@@ -21,11 +36,14 @@ fw_prev_arg1:
|
|||||||
#endif
|
#endif
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 4
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.global fw_next_arg1
|
.global fw_next_arg1
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The next arg1 should be returned in 'a0'.
|
||||||
|
*/
|
||||||
fw_next_arg1:
|
fw_next_arg1:
|
||||||
/* We return next arg1 in 'a0' */
|
|
||||||
#ifdef FW_PAYLOAD_FDT_ADDR
|
#ifdef FW_PAYLOAD_FDT_ADDR
|
||||||
li a0, FW_PAYLOAD_FDT_ADDR
|
li a0, FW_PAYLOAD_FDT_ADDR
|
||||||
#else
|
#else
|
||||||
@@ -33,14 +51,40 @@ fw_next_arg1:
|
|||||||
#endif
|
#endif
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 4
|
.align 3
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.global fw_next_addr
|
.global fw_next_addr
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The next address should be returned in 'a0'.
|
||||||
|
*/
|
||||||
fw_next_addr:
|
fw_next_addr:
|
||||||
/* We return next address in 'a0' */
|
|
||||||
la a0, payload_bin
|
la a0, payload_bin
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.align 3
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.global fw_next_mode
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The next address should be returned in 'a0'.
|
||||||
|
*/
|
||||||
|
fw_next_mode:
|
||||||
|
li a0, PRV_S
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 3
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.global fw_options
|
||||||
|
/*
|
||||||
|
* We can only use a0, a1, and a2 registers here.
|
||||||
|
* The 'a4' register will have default options.
|
||||||
|
* The next address should be returned in 'a0'.
|
||||||
|
*/
|
||||||
|
fw_options:
|
||||||
|
add a0, zero, zero
|
||||||
|
ret
|
||||||
|
|
||||||
#ifdef FW_PAYLOAD_FDT_PATH
|
#ifdef FW_PAYLOAD_FDT_PATH
|
||||||
.align 4
|
.align 4
|
||||||
.section .text, "ax", %progbits
|
.section .text, "ax", %progbits
|
||||||
|
Reference in New Issue
Block a user