riscv: Add kconfig option to run U-Boot in S-mode
authorAnup Patel <anup@brainfault.org>
Mon, 3 Dec 2018 05:27:40 +0000 (10:57 +0530)
committerAndes <uboot@andestech.com>
Wed, 5 Dec 2018 06:13:53 +0000 (14:13 +0800)
This patch adds kconfig option RISCV_SMODE to run U-Boot in
S-mode. When this opition is enabled we use s<xyz> CSRs instead
of m<xyz> CSRs.

It is important to note that there is no equivalent S-mode CSR
for misa and mhartid CSRs so we expect M-mode runtime firmware
(BBL or equivalent) to emulate misa and mhartid CSR read.

In-future, we will have more patches to avoid accessing misa and
mhartid CSRs from S-mode.

Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
arch/riscv/Kconfig
arch/riscv/cpu/start.S
arch/riscv/include/asm/encoding.h
arch/riscv/lib/interrupts.c

index 3e0af55e7152c7b334a7b045ff7a8bffb4e39d52..732a357a99b93682eb71fbbada1e31dff8ba7dda 100644 (file)
@@ -55,6 +55,11 @@ config RISCV_ISA_C
 config RISCV_ISA_A
        def_bool y
 
+config RISCV_SMODE
+       bool "Run in S-Mode"
+       help
+         Enable this option to build U-Boot for RISC-V S-Mode
+
 config 32BIT
        bool
 
index 15e1b8199a3bfef01f0cdab7058ac101e2ec9d61..3f055bdb7ede06a3a1f1451dd6bc58df0d76401e 100644 (file)
@@ -41,10 +41,10 @@ _start:
        li      t0, CONFIG_SYS_SDRAM_BASE
        SREG    a2, 0(t0)
        la      t0, trap_entry
-       csrw    mtvec, t0
+       csrw    MODE_PREFIX(tvec), t0
 
        /* mask all interrupts */
-       csrw    mie, zero
+       csrw    MODE_PREFIX(ie), zero
 
        /* Enable cache */
        jal     icache_enable
@@ -166,7 +166,7 @@ fix_rela_dyn:
 */
        la      t0, trap_entry
        add     t0, t0, t6
-       csrw    mtvec, t0
+       csrw    MODE_PREFIX(tvec), t0
 
 clear_bss:
        la      t0, __bss_start         /* t0 <- rel __bss_start in FLASH */
@@ -238,17 +238,24 @@ trap_entry:
        SREG    x29, 29*REGBYTES(sp)
        SREG    x30, 30*REGBYTES(sp)
        SREG    x31, 31*REGBYTES(sp)
-       csrr    a0, mcause
-       csrr    a1, mepc
+       csrr    a0, MODE_PREFIX(cause)
+       csrr    a1, MODE_PREFIX(epc)
        mv      a2, sp
        jal     handle_trap
-       csrw    mepc, a0
+       csrw    MODE_PREFIX(epc), a0
 
+#ifdef CONFIG_RISCV_SMODE
+/*
+ * Remain in S-mode after sret
+ */
+       li      t0, SSTATUS_SPP
+#else
 /*
  * Remain in M-mode after mret
  */
        li      t0, MSTATUS_MPP
-       csrs    mstatus, t0
+#endif
+       csrs    MODE_PREFIX(status), t0
        LREG    x1, 1*REGBYTES(sp)
        LREG    x2, 2*REGBYTES(sp)
        LREG    x3, 3*REGBYTES(sp)
@@ -281,4 +288,4 @@ trap_entry:
        LREG    x30, 30*REGBYTES(sp)
        LREG    x31, 31*REGBYTES(sp)
        addi    sp, sp, 32*REGBYTES
-       mret
+       MODE_PREFIX(ret)
index 9ea50ce64079cdd14e7585f42872e4bafb3bb4f5..97cf906aa63b9ce5e4384a9b4b3e581d6d08d408 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef RISCV_CSR_ENCODING_H
 #define RISCV_CSR_ENCODING_H
 
+#ifdef CONFIG_RISCV_SMODE
+#define MODE_PREFIX(__suffix)  s##__suffix
+#else
+#define MODE_PREFIX(__suffix)  m##__suffix
+#endif
+
 #define MSTATUS_UIE    0x00000001
 #define MSTATUS_SIE    0x00000002
 #define MSTATUS_HIE    0x00000004
index 903a1c4cd55766f7383b6c3eb93fff67c72ef652..3aff00697732fe5a1950d53d9a9c42f3be4ae722 100644 (file)
@@ -34,17 +34,30 @@ int disable_interrupts(void)
        return 0;
 }
 
-ulong handle_trap(ulong mcause, ulong epc, struct pt_regs *regs)
+ulong handle_trap(ulong cause, ulong epc, struct pt_regs *regs)
 {
-       ulong is_int;
+       ulong is_irq, irq;
 
-       is_int = (mcause & MCAUSE_INT);
-       if ((is_int) && ((mcause & MCAUSE_CAUSE)  == IRQ_M_EXT))
-               external_interrupt(0);  /* handle_m_ext_interrupt */
-       else if ((is_int) && ((mcause & MCAUSE_CAUSE)  == IRQ_M_TIMER))
-               timer_interrupt(0);     /* handle_m_timer_interrupt */
-       else
-               _exit_trap(mcause, epc, regs);
+       is_irq = (cause & MCAUSE_INT);
+       irq = (cause & ~MCAUSE_INT);
+
+       if (is_irq) {
+               switch (irq) {
+               case IRQ_M_EXT:
+               case IRQ_S_EXT:
+                       external_interrupt(0);  /* handle external interrupt */
+                       break;
+               case IRQ_M_TIMER:
+               case IRQ_S_TIMER:
+                       timer_interrupt(0);     /* handle timer interrupt */
+                       break;
+               default:
+                       _exit_trap(cause, epc, regs);
+                       break;
+               };
+       } else {
+               _exit_trap(cause, epc, regs);
+       }
 
        return epc;
 }