Commit 5d5fc33c authored by Anton Blanchard's avatar Anton Blanchard Committed by Palmer Dabbelt

riscv: Improve exception and system call latency

Many CPUs implement return address branch prediction as a stack. The
RISCV architecture refers to this as a return address stack (RAS). If
this gets corrupted then the CPU will mispredict at least one but
potentally many function returns.

There are two issues with the current RISCV exception code:

- We are using the alternate link stack (x5/t0) for the indirect branch
  which makes the hardware think this is a function return. This will
  corrupt the RAS.

- We modify the return address of handle_exception to point to
  ret_from_exception. This will also corrupt the RAS.

Testing the null system call latency before and after the patch:

Visionfive2 (StarFive JH7110 / U74)
baseline: 189.87 ns
patched:  176.76 ns

Lichee pi 4a (T-Head TH1520 / C910)
baseline: 666.58 ns
patched:  636.90 ns

Just over 7% on the U74 and just over 4% on the C910.
Signed-off-by: default avatarAnton Blanchard <antonb@tenstorrent.com>
Signed-off-by: default avatarCyril Bur <cyrilbur@tenstorrent.com>
Tested-by: default avatarJisheng Zhang <jszhang@kernel.org>
Reviewed-by: default avatarJisheng Zhang <jszhang@kernel.org>
Link: https://lore.kernel.org/r/20240607061335.2197383-1-cyrilbur@tenstorrent.comSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 8d22d0db
...@@ -88,7 +88,6 @@ SYM_CODE_START(handle_exception) ...@@ -88,7 +88,6 @@ SYM_CODE_START(handle_exception)
call riscv_v_context_nesting_start call riscv_v_context_nesting_start
#endif #endif
move a0, sp /* pt_regs */ move a0, sp /* pt_regs */
la ra, ret_from_exception
/* /*
* MSB of cause differentiates between * MSB of cause differentiates between
...@@ -97,7 +96,8 @@ SYM_CODE_START(handle_exception) ...@@ -97,7 +96,8 @@ SYM_CODE_START(handle_exception)
bge s4, zero, 1f bge s4, zero, 1f
/* Handle interrupts */ /* Handle interrupts */
tail do_irq call do_irq
j ret_from_exception
1: 1:
/* Handle other exceptions */ /* Handle other exceptions */
slli t0, s4, RISCV_LGPTR slli t0, s4, RISCV_LGPTR
...@@ -105,11 +105,14 @@ SYM_CODE_START(handle_exception) ...@@ -105,11 +105,14 @@ SYM_CODE_START(handle_exception)
la t2, excp_vect_table_end la t2, excp_vect_table_end
add t0, t1, t0 add t0, t1, t0
/* Check if exception code lies within bounds */ /* Check if exception code lies within bounds */
bgeu t0, t2, 1f bgeu t0, t2, 3f
REG_L t0, 0(t0) REG_L t1, 0(t0)
jr t0 2: jalr t1
1: j ret_from_exception
tail do_trap_unknown 3:
la t1, do_trap_unknown
j 2b
SYM_CODE_END(handle_exception) SYM_CODE_END(handle_exception)
ASM_NOKPROBE(handle_exception) ASM_NOKPROBE(handle_exception)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#ifdef CONFIG_FRAME_POINTER #ifdef CONFIG_FRAME_POINTER
extern asmlinkage void ret_from_exception(void); extern asmlinkage void handle_exception(void);
static inline int fp_is_valid(unsigned long fp, unsigned long sp) static inline int fp_is_valid(unsigned long fp, unsigned long sp)
{ {
...@@ -71,7 +71,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, ...@@ -71,7 +71,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
fp = frame->fp; fp = frame->fp;
pc = ftrace_graph_ret_addr(current, &graph_idx, frame->ra, pc = ftrace_graph_ret_addr(current, &graph_idx, frame->ra,
&frame->ra); &frame->ra);
if (pc == (unsigned long)ret_from_exception) { if (pc == (unsigned long)handle_exception) {
if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc))) if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment