firmware: Allow firmwares to provide next mode and options
authorAnup Patel <anup.patel@wdc.com>
Mon, 29 Apr 2019 05:14:15 +0000 (10:44 +0530)
committerAnup Patel <anup@brainfault.org>
Fri, 10 May 2019 06:56:22 +0000 (12:26 +0530)
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>
firmware/fw_base.S
firmware/fw_jump.S
firmware/fw_payload.S

index 7897314..0d7cf69 100644 (file)
 #include <sbi/sbi_scratch.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
        .section .entry, "ax", %progbits
        .globl _start
@@ -25,9 +39,15 @@ _start:
        csrr    a6, CSR_MHARTID
        blt     zero, a6, _wait_for_boot_hart
 
+       /* Reset all registers for boot HART */
        li      ra, 0
        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
         * s7 -> HART Count
         * s8 -> HART Stack Size
@@ -59,6 +79,7 @@ _scratch_init:
        sub     tp, tp, a5
 
        /* Initialize scratch space */
+       /* Store fw_start and fw_size in scratch space */
        la      a4, _fw_start
        la      a5, _fw_end
        mul     t0, s7, s8
@@ -66,27 +87,44 @@ _scratch_init:
        sub     a5, a5, a4
        REG_S   a4, SBI_SCRATCH_FW_START_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
        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
        REG_S   a0, SBI_SCRATCH_NEXT_ADDR_OFFSET(tp)
-       li      a4, PRV_S
-       REG_S   a4, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
+       MOV_3R  a0, s0, a1, s1, a2, s2
+       /* 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
        REG_S   a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
+       /* Store platform address in scratch space */
        la      a4, platform
        REG_S   a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
+       /* Store hartid-to-scratch function address in scratch space */
        la      a4, _hartid_to_scratch
        REG_S   a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
+       /* Clear tmp0 in scratch space */
        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
        li      a4, FW_OPTIONS
-       REG_S   a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
 #else
-       REG_S   zero, SBI_SCRATCH_OPTIONS_OFFSET(tp)
+       add     a4, zero, zero
 #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
        blt     t1, s7, _scratch_init
 
@@ -99,12 +137,10 @@ _bss_zero:
        blt     a4, a5, _bss_zero
 
        /* Override pervious arg1 */
-       add     s0, a0, zero
-       add     s1, a1, zero
+       MOV_3R  s0, a0, s1, a1, s2, a2
        call    fw_prev_arg1
        add     t1, a0, zero
-       add     a0, s0, zero
-       add     a1, s1, zero
+       MOV_3R  a0, s0, a1, s1, a2, s2
        beqz    t1, _prev_arg1_override_done
        add     a1, t1, zero
 _prev_arg1_override_done:
@@ -122,13 +158,12 @@ _prev_arg1_override_done:
        li      a3, ~(__SIZEOF_POINTER__ - 1)
        li      a4, 0xff
        /* t1 = destination FDT start address */
-       add     s0, a0, zero
-       add     s1, a1, zero
+       MOV_3R  s0, a0, s1, a1, s2, a2
        call    fw_next_arg1
        add     t1, a0, zero
-       add     a0, s0, zero
-       add     a1, s1, zero
+       MOV_3R  a0, s0, a1, s1, a2, s2
        beqz    t1, _fdt_reloc_done
+       beq     t1, a1, _fdt_reloc_done
        and     t1, t1, a3
        /* t0 = source FDT start address */
        add     t0, a1, zero
@@ -188,6 +223,7 @@ _wait_for_boot_hart:
        beqz    a5, _wait_for_boot_hart
 
 _start_warm:
+       /* Reset all registers for non-boot HARTs */
        li      ra, 0
        call    _reset_regs
 
@@ -430,7 +466,7 @@ _reset_regs:
 
        /* flush the instruction cache */
        fence.i
-       /* Reset all registers except ra, a0,a1 */
+       /* Reset all registers except ra, a0, a1 and a2 */
        li sp, 0
        li gp, 0
        li tp, 0
@@ -439,7 +475,6 @@ _reset_regs:
        li t2, 0
        li s0, 0
        li s1, 0
-       li a2, 0
        li a3, 0
        li a4, 0
        li a5, 0
index 4b71863..cdf1f41 100644 (file)
 
        .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
        .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:
-       /* We return previous arg1 in 'a0' */
        add     a0, zero, zero
        ret
 
        .align 3
        .section .entry, "ax", %progbits
        .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:
-       /* We return next arg1 in 'a0' */
 #ifdef FW_JUMP_FDT_ADDR
        li      a0, FW_JUMP_FDT_ADDR
 #else
@@ -32,12 +50,38 @@ fw_next_arg1:
        .align 3
        .section .entry, "ax", %progbits
        .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:
-       /* We return next address in 'a0' */
        la      a0, _jump_addr
        REG_L   a0, (a0)
        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
 #error "Must define FW_JUMP_ADDR"
 #endif
index b86b63c..4b4527a 100644 (file)
@@ -9,11 +9,26 @@
 
 #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
        .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:
-       /* We return previous arg1 in 'a0' */
 #ifdef FW_PAYLOAD_FDT_PATH
        la      a0, fdt_bin
 #else
@@ -21,11 +36,14 @@ fw_prev_arg1:
 #endif
        ret
 
-       .align 4
+       .align 3
        .section .entry, "ax", %progbits
        .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:
-       /* We return next arg1 in 'a0' */
 #ifdef FW_PAYLOAD_FDT_ADDR
        li      a0, FW_PAYLOAD_FDT_ADDR
 #else
@@ -33,14 +51,40 @@ fw_next_arg1:
 #endif
        ret
 
-       .align 4
+       .align 3
        .section .entry, "ax", %progbits
        .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:
-       /* We return next address in 'a0' */
        la      a0, payload_bin
        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
        .align 4
        .section .text, "ax", %progbits