From 343f183f0500134a15f1af1567949555580e1cbc Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Wed, 26 Aug 2020 15:19:47 +0200 Subject: [PATCH 1/5] fe310: Merge intr.S into irq_arch --- cpu/fe310/intr.S | 114 ------------------------------------------- cpu/fe310/irq_arch.c | 109 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 114 deletions(-) delete mode 100644 cpu/fe310/intr.S diff --git a/cpu/fe310/intr.S b/cpu/fe310/intr.S deleted file mode 100644 index cb759759c7..0000000000 --- a/cpu/fe310/intr.S +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2017, 2019 JP Bonn, Ken Rabold - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -#include "vendor/encoding.h" -#include "context_frame.h" - - .section .text.entry - .align 2 - .global trap_entry - -trap_entry: - /* Save registers to stack */ - addi sp, sp, -CONTEXT_FRAME_SIZE - - sw s0, s0_OFFSET(sp) - sw s1, s1_OFFSET(sp) - sw s2, s2_OFFSET(sp) - sw s3, s3_OFFSET(sp) - sw s4, s4_OFFSET(sp) - sw s5, s5_OFFSET(sp) - sw s6, s6_OFFSET(sp) - sw s7, s7_OFFSET(sp) - sw s8, s8_OFFSET(sp) - sw s9, s9_OFFSET(sp) - sw s10, s10_OFFSET(sp) - sw s11, s11_OFFSET(sp) - sw ra, ra_OFFSET(sp) - sw t0, t0_OFFSET(sp) - sw t1, t1_OFFSET(sp) - sw t2, t2_OFFSET(sp) - sw t3, t3_OFFSET(sp) - sw t4, t4_OFFSET(sp) - sw t5, t5_OFFSET(sp) - sw t6, t6_OFFSET(sp) - sw a0, a0_OFFSET(sp) - sw a1, a1_OFFSET(sp) - sw a2, a2_OFFSET(sp) - sw a3, a3_OFFSET(sp) - sw a4, a4_OFFSET(sp) - sw a5, a5_OFFSET(sp) - sw a6, a6_OFFSET(sp) - sw a7, a7_OFFSET(sp) - - - /* Get the interrupt cause, PC, and address */ - csrr a0, mcause - csrr a1, mepc - csrr a2, mtval - - /* Save return PC in stack frame */ - sw a1, pc_OFFSET(sp) - - /* Get the active thread (could be NULL) */ - lw tp, sched_active_thread - beqz tp, null_thread - - /* Save stack pointer of current thread */ - sw sp, SP_OFFSET_IN_THREAD(tp) - -null_thread: - /* Switch to ISR stack. Interrupts are not nested so use fixed - * starting address and just abandon stack when finished. */ - la sp, _sp - - /* Call handle_trap with MCAUSE and MEPC register value as args */ - call handle_trap - - /* Get the active thread (guaranteed to be non NULL) */ - lw tp, sched_active_thread - - /* Load the thread SP of scheduled thread */ - lw sp, SP_OFFSET_IN_THREAD(tp) - - /* Set return PC */ - lw a1, pc_OFFSET(sp) - csrw mepc, a1 - - /* Restore registers from stack */ - lw s0, s0_OFFSET(sp) - lw s1, s1_OFFSET(sp) - lw s2, s2_OFFSET(sp) - lw s3, s3_OFFSET(sp) - lw s4, s4_OFFSET(sp) - lw s5, s5_OFFSET(sp) - lw s6, s6_OFFSET(sp) - lw s7, s7_OFFSET(sp) - lw s8, s8_OFFSET(sp) - lw s9, s9_OFFSET(sp) - lw s10, s10_OFFSET(sp) - lw s11, s11_OFFSET(sp) - lw ra, ra_OFFSET(sp) - lw t0, t0_OFFSET(sp) - lw t1, t1_OFFSET(sp) - lw t2, t2_OFFSET(sp) - lw t3, t3_OFFSET(sp) - lw t4, t4_OFFSET(sp) - lw t5, t5_OFFSET(sp) - lw t6, t6_OFFSET(sp) - lw a0, a0_OFFSET(sp) - lw a1, a1_OFFSET(sp) - lw a2, a2_OFFSET(sp) - lw a3, a3_OFFSET(sp) - lw a4, a4_OFFSET(sp) - lw a5, a5_OFFSET(sp) - lw a6, a6_OFFSET(sp) - lw a7, a7_OFFSET(sp) - - addi sp, sp, CONTEXT_FRAME_SIZE - mret diff --git a/cpu/fe310/irq_arch.c b/cpu/fe310/irq_arch.c index d449afcaac..e138d3dae8 100644 --- a/cpu/fe310/irq_arch.c +++ b/cpu/fe310/irq_arch.c @@ -21,7 +21,9 @@ #include #include +#include "macros/xtstr.h" #include "cpu.h" +#include "context_frame.h" #include "irq.h" #include "irq_arch.h" #include "panic.h" @@ -151,3 +153,110 @@ void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval) /* ISR done - no more changes to thread states */ fe310_in_isr = 0; } + +void __attribute__((naked)) trap_entry(void) { + __asm__ volatile ( + /* Save registers to stack */ + "addi sp, sp, -"XTSTR(CONTEXT_FRAME_SIZE)" \n" + + "sw s0, "XTSTR(s0_OFFSET)"(sp) \n" + "sw s1, "XTSTR(s1_OFFSET)"(sp) \n" + "sw s2, "XTSTR(s2_OFFSET)"(sp) \n" + "sw s3, "XTSTR(s3_OFFSET)"(sp) \n" + "sw s4, "XTSTR(s4_OFFSET)"(sp) \n" + "sw s5, "XTSTR(s5_OFFSET)"(sp) \n" + "sw s6, "XTSTR(s6_OFFSET)"(sp) \n" + "sw s7, "XTSTR(s7_OFFSET)"(sp) \n" + "sw s8, "XTSTR(s8_OFFSET)"(sp) \n" + "sw s9, "XTSTR(s9_OFFSET)"(sp) \n" + "sw s10, "XTSTR(s10_OFFSET)"(sp) \n" + "sw s11, "XTSTR(s11_OFFSET)"(sp) \n" + "sw ra, "XTSTR(ra_OFFSET)"(sp) \n" + "sw t0, "XTSTR(t0_OFFSET)"(sp) \n" + "sw t1, "XTSTR(t1_OFFSET)"(sp) \n" + "sw t2, "XTSTR(t2_OFFSET)"(sp) \n" + "sw t3, "XTSTR(t3_OFFSET)"(sp) \n" + "sw t4, "XTSTR(t4_OFFSET)"(sp) \n" + "sw t5, "XTSTR(t5_OFFSET)"(sp) \n" + "sw t6, "XTSTR(t6_OFFSET)"(sp) \n" + "sw a0, "XTSTR(a0_OFFSET)"(sp) \n" + "sw a1, "XTSTR(a1_OFFSET)"(sp) \n" + "sw a2, "XTSTR(a2_OFFSET)"(sp) \n" + "sw a3, "XTSTR(a3_OFFSET)"(sp) \n" + "sw a4, "XTSTR(a4_OFFSET)"(sp) \n" + "sw a5, "XTSTR(a5_OFFSET)"(sp) \n" + "sw a6, "XTSTR(a6_OFFSET)"(sp) \n" + "sw a7, "XTSTR(a7_OFFSET)"(sp) \n" + + + /* Get the interrupt cause, PC, and address */ + "csrr a0, mcause \n" + "csrr a1, mepc \n" + "csrr a2, mtval \n" + + /* Save return PC in stack frame */ + "sw a1, "XTSTR(pc_OFFSET)"(sp) \n" + + /* Get the active thread (could be NULL) */ + "lw tp, sched_active_thread \n" + "beqz tp, null_thread \n" + + /* Save stack pointer of current thread */ + "sw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(tp) \n" + + "null_thread: \n" + /* Switch to ISR stack. Interrupts are not nested so use fixed + * starting address and just abandon stack when finished. */ + "la sp, _sp \n" + + /* Call handle_trap with MCAUSE and MEPC register value as args */ + "call handle_trap \n" + + /* Get the active thread (guaranteed to be non NULL) */ + "lw tp, sched_active_thread \n" + + /* Load the thread SP of scheduled thread */ + "lw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(tp) \n" + + /* Set return PC */ + "lw a1, "XTSTR(pc_OFFSET)"(sp) \n" + "csrw mepc, a1 \n" + + /* Restore registers from stack */ + "lw s0, "XTSTR(s0_OFFSET)"(sp) \n" + "lw s1, "XTSTR(s1_OFFSET)"(sp) \n" + "lw s2, "XTSTR(s2_OFFSET)"(sp) \n" + "lw s3, "XTSTR(s3_OFFSET)"(sp) \n" + "lw s4, "XTSTR(s4_OFFSET)"(sp) \n" + "lw s5, "XTSTR(s5_OFFSET)"(sp) \n" + "lw s6, "XTSTR(s6_OFFSET)"(sp) \n" + "lw s7, "XTSTR(s7_OFFSET)"(sp) \n" + "lw s8, "XTSTR(s8_OFFSET)"(sp) \n" + "lw s9, "XTSTR(s9_OFFSET)"(sp) \n" + "lw s10, "XTSTR(s10_OFFSET)"(sp) \n" + "lw s11, "XTSTR(s11_OFFSET)"(sp) \n" + "lw ra, "XTSTR(ra_OFFSET)"(sp) \n" + "lw t0, "XTSTR(t0_OFFSET)"(sp) \n" + "lw t1, "XTSTR(t1_OFFSET)"(sp) \n" + "lw t2, "XTSTR(t2_OFFSET)"(sp) \n" + "lw t3, "XTSTR(t3_OFFSET)"(sp) \n" + "lw t4, "XTSTR(t4_OFFSET)"(sp) \n" + "lw t5, "XTSTR(t5_OFFSET)"(sp) \n" + "lw t6, "XTSTR(t6_OFFSET)"(sp) \n" + "lw a0, "XTSTR(a0_OFFSET)"(sp) \n" + "lw a1, "XTSTR(a1_OFFSET)"(sp) \n" + "lw a2, "XTSTR(a2_OFFSET)"(sp) \n" + "lw a3, "XTSTR(a3_OFFSET)"(sp) \n" + "lw a4, "XTSTR(a4_OFFSET)"(sp) \n" + "lw a5, "XTSTR(a5_OFFSET)"(sp) \n" + "lw a6, "XTSTR(a6_OFFSET)"(sp) \n" + "lw a7, "XTSTR(a7_OFFSET)"(sp) \n" + + "addi sp, sp, "XTSTR(CONTEXT_FRAME_SIZE)" \n" + "mret \n" + + : + : + : + ); +} From 503806cbb3bfa0f0dd3b9308c52bd9458296676d Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Wed, 26 Aug 2020 21:02:23 +0200 Subject: [PATCH 2/5] fe310: Only save caller-saved registers on regular trap This commit reworks the trap entry to only save the callee-saved registers when a context switch is required. the caller-saved registers are always stored and restored to adhere to the RISC-V ABI. This saves considerable cycles on interrupts. --- cpu/fe310/irq_arch.c | 199 ++++++++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 89 deletions(-) diff --git a/cpu/fe310/irq_arch.c b/cpu/fe310/irq_arch.c index e138d3dae8..f1fa5da587 100644 --- a/cpu/fe310/irq_arch.c +++ b/cpu/fe310/irq_arch.c @@ -44,7 +44,7 @@ static external_isr_ptr_t _ext_isrs[PLIC_NUM_INTERRUPTS]; /** * @brief ISR trap vector */ -void trap_entry(void); +static void trap_entry(void); /** * @brief Timer ISR @@ -97,12 +97,13 @@ void external_isr(void) /** * @brief Global trap and interrupt handler */ -void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval) +int handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval) { #ifndef DEVELHELP (void) mepc; (void) mtval; #endif + int res = 0; /* Tell RIOT to set sched_context_switch_request instead of * calling thread_yield(). */ fe310_in_isr = 1; @@ -147,114 +148,134 @@ void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval) /* Check if context change was requested */ if (sched_context_switch_request) { - sched_run(); + res = sched_run(); } /* ISR done - no more changes to thread states */ fe310_in_isr = 0; + return res; } -void __attribute__((naked)) trap_entry(void) { +/* Marking this as interrupt to ensure an mret at the end, provided by the + * compiler. Aligned to 4-byte boundary as per RISC-V spec */ +static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void) { __asm__ volatile ( - /* Save registers to stack */ - "addi sp, sp, -"XTSTR(CONTEXT_FRAME_SIZE)" \n" + "addi sp, sp, -"XTSTR(CONTEXT_FRAME_SIZE)" \n" - "sw s0, "XTSTR(s0_OFFSET)"(sp) \n" - "sw s1, "XTSTR(s1_OFFSET)"(sp) \n" - "sw s2, "XTSTR(s2_OFFSET)"(sp) \n" - "sw s3, "XTSTR(s3_OFFSET)"(sp) \n" - "sw s4, "XTSTR(s4_OFFSET)"(sp) \n" - "sw s5, "XTSTR(s5_OFFSET)"(sp) \n" - "sw s6, "XTSTR(s6_OFFSET)"(sp) \n" - "sw s7, "XTSTR(s7_OFFSET)"(sp) \n" - "sw s8, "XTSTR(s8_OFFSET)"(sp) \n" - "sw s9, "XTSTR(s9_OFFSET)"(sp) \n" - "sw s10, "XTSTR(s10_OFFSET)"(sp) \n" - "sw s11, "XTSTR(s11_OFFSET)"(sp) \n" - "sw ra, "XTSTR(ra_OFFSET)"(sp) \n" - "sw t0, "XTSTR(t0_OFFSET)"(sp) \n" - "sw t1, "XTSTR(t1_OFFSET)"(sp) \n" - "sw t2, "XTSTR(t2_OFFSET)"(sp) \n" - "sw t3, "XTSTR(t3_OFFSET)"(sp) \n" - "sw t4, "XTSTR(t4_OFFSET)"(sp) \n" - "sw t5, "XTSTR(t5_OFFSET)"(sp) \n" - "sw t6, "XTSTR(t6_OFFSET)"(sp) \n" - "sw a0, "XTSTR(a0_OFFSET)"(sp) \n" - "sw a1, "XTSTR(a1_OFFSET)"(sp) \n" - "sw a2, "XTSTR(a2_OFFSET)"(sp) \n" - "sw a3, "XTSTR(a3_OFFSET)"(sp) \n" - "sw a4, "XTSTR(a4_OFFSET)"(sp) \n" - "sw a5, "XTSTR(a5_OFFSET)"(sp) \n" - "sw a6, "XTSTR(a6_OFFSET)"(sp) \n" - "sw a7, "XTSTR(a7_OFFSET)"(sp) \n" + /* Save caller-saved registers */ + "sw ra, "XTSTR(ra_OFFSET)"(sp) \n" + "sw t0, "XTSTR(t0_OFFSET)"(sp) \n" + "sw t1, "XTSTR(t1_OFFSET)"(sp) \n" + "sw t2, "XTSTR(t2_OFFSET)"(sp) \n" + "sw t3, "XTSTR(t3_OFFSET)"(sp) \n" + "sw t4, "XTSTR(t4_OFFSET)"(sp) \n" + "sw t5, "XTSTR(t5_OFFSET)"(sp) \n" + "sw t6, "XTSTR(t6_OFFSET)"(sp) \n" + "sw a0, "XTSTR(a0_OFFSET)"(sp) \n" + "sw a1, "XTSTR(a1_OFFSET)"(sp) \n" + "sw a2, "XTSTR(a2_OFFSET)"(sp) \n" + "sw a3, "XTSTR(a3_OFFSET)"(sp) \n" + "sw a4, "XTSTR(a4_OFFSET)"(sp) \n" + "sw a5, "XTSTR(a5_OFFSET)"(sp) \n" + "sw a6, "XTSTR(a6_OFFSET)"(sp) \n" + "sw a7, "XTSTR(a7_OFFSET)"(sp) \n" - - /* Get the interrupt cause, PC, and address */ - "csrr a0, mcause \n" - "csrr a1, mepc \n" - "csrr a2, mtval \n" - - /* Save return PC in stack frame */ - "sw a1, "XTSTR(pc_OFFSET)"(sp) \n" + /* Save s0 and s1 extra for the active thread and the stack ptr */ + "sw s0, "XTSTR(s0_OFFSET)"(sp) \n" + "sw s1, "XTSTR(s1_OFFSET)"(sp) \n" /* Get the active thread (could be NULL) */ - "lw tp, sched_active_thread \n" - "beqz tp, null_thread \n" + "lw s1, sched_active_thread \n" + /* Save the user stack ptr */ + "mv s0, sp \n" + /* Load exception stack ptr */ + "la sp, _sp \n" + + /* Get the interrupt cause, PC and trap vector */ + "csrr a0, mcause \n" + "csrr a1, mepc \n" + "csrr a2, mtval \n" + /* Call trap handler */ + "call handle_trap \n" + + /* Move stack pointer back */ + "mv sp, s0 \n" + + /* No context switch required, shortcut to restore */ + "beqz a0, no_switch \n" + + /* Skips the rest of the save if no active thread */ + "beqz s1, null_thread \n" + + /* Store s2-s11 */ + "sw s2, "XTSTR(s2_OFFSET)"(sp) \n" + "sw s3, "XTSTR(s3_OFFSET)"(sp) \n" + "sw s4, "XTSTR(s4_OFFSET)"(sp) \n" + "sw s5, "XTSTR(s5_OFFSET)"(sp) \n" + "sw s6, "XTSTR(s6_OFFSET)"(sp) \n" + "sw s7, "XTSTR(s7_OFFSET)"(sp) \n" + "sw s8, "XTSTR(s8_OFFSET)"(sp) \n" + "sw s9, "XTSTR(s9_OFFSET)"(sp) \n" + "sw s10, "XTSTR(s10_OFFSET)"(sp) \n" + "sw s11, "XTSTR(s11_OFFSET)"(sp) \n" + + /* Grab mepc to save it to the stack */ + "csrr s2, mepc \n" + /* Save return PC in stack frame */ + "sw s2, "XTSTR(pc_OFFSET)"(sp) \n" + /* Skips the stack pointer save if no active thread */ + "beqz s1, null_thread \n" /* Save stack pointer of current thread */ - "sw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(tp) \n" + "sw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(s1) \n" - "null_thread: \n" - /* Switch to ISR stack. Interrupts are not nested so use fixed - * starting address and just abandon stack when finished. */ - "la sp, _sp \n" + "null_thread: \n" - /* Call handle_trap with MCAUSE and MEPC register value as args */ - "call handle_trap \n" - - /* Get the active thread (guaranteed to be non NULL) */ - "lw tp, sched_active_thread \n" + /* Get the new active thread (guaranteed to be non NULL) */ + "lw s1, sched_active_thread \n" /* Load the thread SP of scheduled thread */ - "lw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(tp) \n" + "lw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(s1) \n" - /* Set return PC */ - "lw a1, "XTSTR(pc_OFFSET)"(sp) \n" - "csrw mepc, a1 \n" + /* Set return PC to mepc */ + "lw a1, "XTSTR(pc_OFFSET)"(sp) \n" + "csrw mepc, a1 \n" - /* Restore registers from stack */ - "lw s0, "XTSTR(s0_OFFSET)"(sp) \n" - "lw s1, "XTSTR(s1_OFFSET)"(sp) \n" - "lw s2, "XTSTR(s2_OFFSET)"(sp) \n" - "lw s3, "XTSTR(s3_OFFSET)"(sp) \n" - "lw s4, "XTSTR(s4_OFFSET)"(sp) \n" - "lw s5, "XTSTR(s5_OFFSET)"(sp) \n" - "lw s6, "XTSTR(s6_OFFSET)"(sp) \n" - "lw s7, "XTSTR(s7_OFFSET)"(sp) \n" - "lw s8, "XTSTR(s8_OFFSET)"(sp) \n" - "lw s9, "XTSTR(s9_OFFSET)"(sp) \n" - "lw s10, "XTSTR(s10_OFFSET)"(sp) \n" - "lw s11, "XTSTR(s11_OFFSET)"(sp) \n" - "lw ra, "XTSTR(ra_OFFSET)"(sp) \n" - "lw t0, "XTSTR(t0_OFFSET)"(sp) \n" - "lw t1, "XTSTR(t1_OFFSET)"(sp) \n" - "lw t2, "XTSTR(t2_OFFSET)"(sp) \n" - "lw t3, "XTSTR(t3_OFFSET)"(sp) \n" - "lw t4, "XTSTR(t4_OFFSET)"(sp) \n" - "lw t5, "XTSTR(t5_OFFSET)"(sp) \n" - "lw t6, "XTSTR(t6_OFFSET)"(sp) \n" - "lw a0, "XTSTR(a0_OFFSET)"(sp) \n" - "lw a1, "XTSTR(a1_OFFSET)"(sp) \n" - "lw a2, "XTSTR(a2_OFFSET)"(sp) \n" - "lw a3, "XTSTR(a3_OFFSET)"(sp) \n" - "lw a4, "XTSTR(a4_OFFSET)"(sp) \n" - "lw a5, "XTSTR(a5_OFFSET)"(sp) \n" - "lw a6, "XTSTR(a6_OFFSET)"(sp) \n" - "lw a7, "XTSTR(a7_OFFSET)"(sp) \n" + /* restore s2-s11 */ + "lw s2, "XTSTR(s2_OFFSET)"(sp) \n" + "lw s3, "XTSTR(s3_OFFSET)"(sp) \n" + "lw s4, "XTSTR(s4_OFFSET)"(sp) \n" + "lw s5, "XTSTR(s5_OFFSET)"(sp) \n" + "lw s6, "XTSTR(s6_OFFSET)"(sp) \n" + "lw s7, "XTSTR(s7_OFFSET)"(sp) \n" + "lw s8, "XTSTR(s8_OFFSET)"(sp) \n" + "lw s9, "XTSTR(s9_OFFSET)"(sp) \n" + "lw s10, "XTSTR(s10_OFFSET)"(sp) \n" + "lw s11, "XTSTR(s11_OFFSET)"(sp) \n" - "addi sp, sp, "XTSTR(CONTEXT_FRAME_SIZE)" \n" - "mret \n" + "no_switch: \n" + /* restore the caller-saved registers */ + "lw ra, "XTSTR(ra_OFFSET)"(sp) \n" + "lw t0, "XTSTR(t0_OFFSET)"(sp) \n" + "lw t1, "XTSTR(t1_OFFSET)"(sp) \n" + "lw t2, "XTSTR(t2_OFFSET)"(sp) \n" + "lw t3, "XTSTR(t3_OFFSET)"(sp) \n" + "lw t4, "XTSTR(t4_OFFSET)"(sp) \n" + "lw t5, "XTSTR(t5_OFFSET)"(sp) \n" + "lw t6, "XTSTR(t6_OFFSET)"(sp) \n" + "lw a0, "XTSTR(a0_OFFSET)"(sp) \n" + "lw a1, "XTSTR(a1_OFFSET)"(sp) \n" + "lw a2, "XTSTR(a2_OFFSET)"(sp) \n" + "lw a3, "XTSTR(a3_OFFSET)"(sp) \n" + "lw a4, "XTSTR(a4_OFFSET)"(sp) \n" + "lw a5, "XTSTR(a5_OFFSET)"(sp) \n" + "lw a6, "XTSTR(a6_OFFSET)"(sp) \n" + "lw a7, "XTSTR(a7_OFFSET)"(sp) \n" + "lw s0, "XTSTR(s0_OFFSET)"(sp) \n" + "lw s1, "XTSTR(s1_OFFSET)"(sp) \n" + + "addi sp, sp, "XTSTR(CONTEXT_FRAME_SIZE)" \n" : : : From acf948a2964958f61f6743c0dfb02432c8eb8c95 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Thu, 27 Aug 2020 00:41:02 +0200 Subject: [PATCH 3/5] fe310: Only retrieve mepc and mtval on exception --- cpu/fe310/irq_arch.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cpu/fe310/irq_arch.c b/cpu/fe310/irq_arch.c index f1fa5da587..f6ca276fa5 100644 --- a/cpu/fe310/irq_arch.c +++ b/cpu/fe310/irq_arch.c @@ -97,12 +97,8 @@ void external_isr(void) /** * @brief Global trap and interrupt handler */ -int handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval) +int handle_trap(unsigned int mcause) { -#ifndef DEVELHELP - (void) mepc; - (void) mtval; -#endif int res = 0; /* Tell RIOT to set sched_context_switch_request instead of * calling thread_yield(). */ @@ -139,8 +135,8 @@ int handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval) #ifdef DEVELHELP printf("Unhandled trap:\n"); printf(" mcause: 0x%08x\n", mcause); - printf(" mepc: 0x%08x\n", mepc); - printf(" mtval: 0x%08x\n", mtval); + printf(" mepc: 0x%"PRIx32"\n", read_csr(mepc)); + printf(" mtval: 0x%"PRIx32"\n", read_csr(mtval)); #endif /* Unknown trap */ core_panic(PANIC_GENERAL_ERROR, "Unhandled trap"); @@ -194,9 +190,7 @@ static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void /* Get the interrupt cause, PC and trap vector */ "csrr a0, mcause \n" - "csrr a1, mepc \n" - "csrr a2, mtval \n" - /* Call trap handler */ + /* Call trap handler, a0 contains the return value */ "call handle_trap \n" /* Move stack pointer back */ From 4289b09a33deaf914a2edd580784d8b5fbf5f0ef Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Thu, 27 Aug 2020 00:43:42 +0200 Subject: [PATCH 4/5] fe310: Skip most context save on null thread --- cpu/fe310/irq_arch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpu/fe310/irq_arch.c b/cpu/fe310/irq_arch.c index f6ca276fa5..0245588bb0 100644 --- a/cpu/fe310/irq_arch.c +++ b/cpu/fe310/irq_arch.c @@ -218,8 +218,7 @@ static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void "csrr s2, mepc \n" /* Save return PC in stack frame */ "sw s2, "XTSTR(pc_OFFSET)"(sp) \n" - /* Skips the stack pointer save if no active thread */ - "beqz s1, null_thread \n" + /* Save stack pointer of current thread */ "sw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(s1) \n" From 1e5dc928ad32cca01e1af8810c9dbfcac28b9180 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Thu, 27 Aug 2020 21:15:18 +0200 Subject: [PATCH 5/5] fe310: Split sched_run call from handle_trap This is a small optimization to the RISC-V trap handler. By splitting the call to sched_run from the trap_handle call, loading the previous thread ptr can be delayed until after it is determined that a schedule run is required. This shaves of a few cycles during regular interrupts that do not trigger the scheduler. --- cpu/fe310/irq_arch.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/cpu/fe310/irq_arch.c b/cpu/fe310/irq_arch.c index 0245588bb0..53931a5eb3 100644 --- a/cpu/fe310/irq_arch.c +++ b/cpu/fe310/irq_arch.c @@ -97,9 +97,8 @@ void external_isr(void) /** * @brief Global trap and interrupt handler */ -int handle_trap(unsigned int mcause) +void handle_trap(uint32_t mcause) { - int res = 0; /* Tell RIOT to set sched_context_switch_request instead of * calling thread_yield(). */ fe310_in_isr = 1; @@ -134,22 +133,15 @@ int handle_trap(unsigned int mcause) else { #ifdef DEVELHELP printf("Unhandled trap:\n"); - printf(" mcause: 0x%08x\n", mcause); + printf(" mcause: 0x%"PRIx32"\n", mcause); printf(" mepc: 0x%"PRIx32"\n", read_csr(mepc)); printf(" mtval: 0x%"PRIx32"\n", read_csr(mtval)); #endif /* Unknown trap */ core_panic(PANIC_GENERAL_ERROR, "Unhandled trap"); } - - /* Check if context change was requested */ - if (sched_context_switch_request) { - res = sched_run(); - } - /* ISR done - no more changes to thread states */ fe310_in_isr = 0; - return res; } /* Marking this as interrupt to ensure an mret at the end, provided by the @@ -180,23 +172,38 @@ static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void "sw s0, "XTSTR(s0_OFFSET)"(sp) \n" "sw s1, "XTSTR(s1_OFFSET)"(sp) \n" - /* Get the active thread (could be NULL) */ - "lw s1, sched_active_thread \n" - /* Save the user stack ptr */ "mv s0, sp \n" /* Load exception stack ptr */ "la sp, _sp \n" - /* Get the interrupt cause, PC and trap vector */ + /* Get the interrupt cause */ "csrr a0, mcause \n" - /* Call trap handler, a0 contains the return value */ + + /* Call trap handler, a0 contains mcause before, and the return value after + * the call */ "call handle_trap \n" - /* Move stack pointer back */ + /* Load the sched_context_switch_request */ + "lw a0, sched_context_switch_request \n" + + /* And skip the context switch if not requested */ + "beqz a0, no_sched \n" + + /* Get the previous active thread (could be NULL) */ + "lw s1, sched_active_thread \n" + + /* Run the scheduler */ + "call sched_run \n" + + "no_sched: \n" + /* Restore the thread stack pointer and check if a new thread must be + * scheduled */ "mv sp, s0 \n" - /* No context switch required, shortcut to restore */ + /* No context switch required, shortcut to restore. a0 contains the return + * value of sched_run, or the sched_context_switch_request if the sched_run + * was skipped */ "beqz a0, no_switch \n" /* Skips the rest of the save if no active thread */ @@ -216,12 +223,14 @@ static void __attribute((aligned(4))) __attribute__((interrupt)) trap_entry(void /* Grab mepc to save it to the stack */ "csrr s2, mepc \n" + /* Save return PC in stack frame */ "sw s2, "XTSTR(pc_OFFSET)"(sp) \n" /* Save stack pointer of current thread */ "sw sp, "XTSTR(SP_OFFSET_IN_THREAD)"(s1) \n" + /* Context saving done, from here on the new thread is scheduled */ "null_thread: \n" /* Get the new active thread (guaranteed to be non NULL) */