Re: [RFC PATCH v2 2/3] riscv: add support for SBI Supervisor Software Events extension

From: Clément Léger
Date: Mon Jan 15 2024 - 03:57:59 EST


Hi Deepak,

On 13/01/2024 01:43, Deepak Gupta wrote:
> On Fri, Jan 12, 2024 at 12:17:14PM +0100, Clément Léger wrote:
>> The SBI SSE extension allows the supervisor software to be notified by
>> the SBI of specific events that are not maskable. The context switch is
>> handled partially by the firmware which will save registers a0, a6, a7.
>> When entering kernel we can rely on these 3 registers to setup the stack
>> and save all the registers.
>>
>> Since each events (and each CPU for local events) have their own
>> context and can preempt each other, allocate a stack for each of them
>> (and for each cpu for local events).
>>
>> When completing the event, if we were coming from kernel with interrupts
>> disabled, simply return there. If coming from userspace or kernel with
>> interrupts enabled, simulate an interrupt exception to allow delivery of
>> signal to user task. For instance this can happen, when a RAS event has
>> been generated and a SIGBUS has been sent to a task.
>>
>> Signed-off-by: Clément Léger <cleger@xxxxxxxxxxxx>
>> ---
>> arch/riscv/include/asm/asm-prototypes.h |   4 +
>> arch/riscv/include/asm/asm.h            |  42 +-
>> arch/riscv/include/asm/scs.h            |   7 +
>> arch/riscv/include/asm/sse.h            |  12 +
>> arch/riscv/include/asm/thread_info.h    |   1 +
>> arch/riscv/kernel/Makefile              |   1 +
>> arch/riscv/kernel/asm-offsets.c         |  26 ++
>> arch/riscv/kernel/entry.S               | 202 +++++++++
>> arch/riscv/kernel/sse.c                 | 130 ++++++
>> arch/riscv/kernel/stacktrace.c          |  13 +
>> arch/riscv/kernel/vmlinux.lds.S         |   6 +
>> drivers/firmware/Kconfig                |  10 +
>> drivers/firmware/Makefile               |   1 +
>> drivers/firmware/riscv_sse.c            | 567 ++++++++++++++++++++++++
>> include/linux/riscv_sse.h               |  76 ++++
>> 15 files changed, 1089 insertions(+), 9 deletions(-)
>> create mode 100644 arch/riscv/include/asm/sse.h
>> create mode 100644 arch/riscv/kernel/sse.c
>> create mode 100644 drivers/firmware/riscv_sse.c
>> create mode 100644 include/linux/riscv_sse.h
>>
>> diff --git a/arch/riscv/include/asm/asm-prototypes.h
>> b/arch/riscv/include/asm/asm-prototypes.h
>> index 36b955c762ba..d163912166d4 100644
>> --- a/arch/riscv/include/asm/asm-prototypes.h
>> +++ b/arch/riscv/include/asm/asm-prototypes.h
>> @@ -3,6 +3,8 @@
>> #define _ASM_RISCV_PROTOTYPES_H
>>
>> #include <linux/ftrace.h>
>> +#include <linux/riscv_sse.h>
>> +#include <asm/sse.h>
>> #include <asm-generic/asm-prototypes.h>
>>
>> long long __lshrti3(long long a, int b);
>> @@ -28,5 +30,7 @@ DECLARE_DO_ERROR_INFO(do_trap_break);
>> asmlinkage void handle_bad_stack(struct pt_regs *regs);
>> asmlinkage void do_page_fault(struct pt_regs *regs);
>> asmlinkage void do_irq(struct pt_regs *regs);
>> +asmlinkage void do_sse(struct sse_registered_event *reg_evt,
>> +                struct pt_regs *reg);
>>
>> #endif /* _ASM_RISCV_PROTOTYPES_H */
>> diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h
>> index b0487b39e674..b5cdd791fc26 100644
>> --- a/arch/riscv/include/asm/asm.h
>> +++ b/arch/riscv/include/asm/asm.h
>> @@ -123,20 +123,16 @@
>> .endm
>> #endif /* CONFIG_SHADOW_CALL_STACK */
>>
>> -    /* save all GPs except x1 ~ x5 */
>> -    .macro save_from_x6_to_x31
>> +    .macro save_x6_to_x31_except_x10_x16_x17
>>     REG_S x6,  PT_T1(sp)
>>     REG_S x7,  PT_T2(sp)
>>     REG_S x8,  PT_S0(sp)
>>     REG_S x9,  PT_S1(sp)
>> -    REG_S x10, PT_A0(sp)
>>     REG_S x11, PT_A1(sp)
>>     REG_S x12, PT_A2(sp)
>>     REG_S x13, PT_A3(sp)
>>     REG_S x14, PT_A4(sp)
>>     REG_S x15, PT_A5(sp)
>> -    REG_S x16, PT_A6(sp)
>> -    REG_S x17, PT_A7(sp)
>>     REG_S x18, PT_S2(sp)
>>     REG_S x19, PT_S3(sp)
>>     REG_S x20, PT_S4(sp)
>> @@ -153,20 +149,33 @@
>>     REG_S x31, PT_T6(sp)
>>     .endm
>>
>> +    /* save all GPs except x1 ~ x5 */
>> +    .macro save_from_x6_to_x31
>> +    save_x6_to_x31_except_x10_x16_x17
>> +    REG_S x10, PT_A0(sp)
>> +    REG_S x16, PT_A6(sp)
>> +    REG_S x17, PT_A7(sp)
>> +    .endm
>> +
>> +    .macro save_regs_for_sse
>> +    save_x6_to_x31_except_x10_x16_x17
>> +    REG_S ra,  PT_RA(sp)
>> +    REG_S gp,  PT_GP(sp)
>> +    REG_S tp,  PT_TP(sp)
>> +    REG_S t0,  PT_T0(sp)
>> +    .endm
>> +
>>     /* restore all GPs except x1 ~ x5 */
>> -    .macro restore_from_x6_to_x31
>> +    .macro restore_from_x6_to_x31_except_x10_x16_x17
>>     REG_L x6,  PT_T1(sp)
>>     REG_L x7,  PT_T2(sp)
>>     REG_L x8,  PT_S0(sp)
>>     REG_L x9,  PT_S1(sp)
>> -    REG_L x10, PT_A0(sp)
>>     REG_L x11, PT_A1(sp)
>>     REG_L x12, PT_A2(sp)
>>     REG_L x13, PT_A3(sp)
>>     REG_L x14, PT_A4(sp)
>>     REG_L x15, PT_A5(sp)
>> -    REG_L x16, PT_A6(sp)
>> -    REG_L x17, PT_A7(sp)
>>     REG_L x18, PT_S2(sp)
>>     REG_L x19, PT_S3(sp)
>>     REG_L x20, PT_S4(sp)
>> @@ -183,6 +192,21 @@
>>     REG_L x31, PT_T6(sp)
>>     .endm
>>
>> +    .macro restore_from_x6_to_x31
>> +    restore_from_x6_to_x31_except_x10_x16_x17
>> +    REG_L x10, PT_A0(sp)
>> +    REG_L x16, PT_A6(sp)
>> +    REG_L x17, PT_A7(sp)
>> +    .endm
>> +
>> +    .macro restore_regs_for_sse
>> +    restore_from_x6_to_x31_except_x10_x16_x17
>> +    REG_L ra,  PT_RA(sp)
>> +    REG_L gp,  PT_GP(sp)
>> +    REG_L tp,  PT_TP(sp)
>> +    REG_L t0,  PT_T0(sp)
>> +    .endm
>> +
>> #endif /* __ASSEMBLY__ */
>>
>> #endif /* _ASM_RISCV_ASM_H */
>> diff --git a/arch/riscv/include/asm/scs.h b/arch/riscv/include/asm/scs.h
>> index 0e45db78b24b..62344daad73d 100644
>> --- a/arch/riscv/include/asm/scs.h
>> +++ b/arch/riscv/include/asm/scs.h
>> @@ -18,6 +18,11 @@
>>     load_per_cpu gp, irq_shadow_call_stack_ptr, \tmp
>> .endm
>>
>> +/* Load the per-CPU IRQ shadow call stack to gp. */
>> +.macro scs_load_sse_stack reg_evt
>> +    REG_L gp, SSE_REG_EVT_SHADOW_STACK(\reg_evt)
>> +.endm
>> +
>> /* Load task_scs_sp(current) to gp. */
>> .macro scs_load_current
>>     REG_L    gp, TASK_TI_SCS_SP(tp)
>> @@ -41,6 +46,8 @@
>> .endm
>> .macro scs_load_irq_stack tmp
>> .endm
>> +.macro scs_load_sse_stack reg_evt
>> +.endm
>> .macro scs_load_current
>> .endm
>> .macro scs_load_current_if_task_changed prev
>> diff --git a/arch/riscv/include/asm/sse.h b/arch/riscv/include/asm/sse.h
>> new file mode 100644
>> index 000000000000..7f8e6f09085c
>> --- /dev/null
>> +++ b/arch/riscv/include/asm/sse.h
>> @@ -0,0 +1,12 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (C) 2023 Rivos Inc.
>> + */
>> +#ifndef __ASM_SSE_H
>> +#define __ASM_SSE_H
>> +
>> +struct sse_registered_event;
>> +int sse_init_event(int cpu, struct sse_registered_event *reg_evt);
>> +void sse_free_event(struct sse_registered_event *reg_evt);
>> +
>> +#endif
>> diff --git a/arch/riscv/include/asm/thread_info.h
>> b/arch/riscv/include/asm/thread_info.h
>> index 574779900bfb..90f357dc5bf3 100644
>> --- a/arch/riscv/include/asm/thread_info.h
>> +++ b/arch/riscv/include/asm/thread_info.h
>> @@ -31,6 +31,7 @@
>> #define SHADOW_OVERFLOW_STACK_SIZE (1024)
>>
>> #define IRQ_STACK_SIZE        THREAD_SIZE
>> +#define SSE_STACK_SIZE        THREAD_SIZE
>>
>> #ifndef __ASSEMBLY__
>>
>> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
>> index fee22a3d1b53..a2febdc1618b 100644
>> --- a/arch/riscv/kernel/Makefile
>> +++ b/arch/riscv/kernel/Makefile
>> @@ -80,6 +80,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE)    += mcount-dyn.o
>> obj-$(CONFIG_PERF_EVENTS)    += perf_callchain.o
>> obj-$(CONFIG_HAVE_PERF_REGS)    += perf_regs.o
>> obj-$(CONFIG_RISCV_SBI)        += sbi.o
>> +obj-$(CONFIG_RISCV_SSE)        += sse.o
>> ifeq ($(CONFIG_RISCV_SBI), y)
>> obj-$(CONFIG_SMP)        += sbi-ipi.o
>> obj-$(CONFIG_SMP) += cpu_ops_sbi.o
>> diff --git a/arch/riscv/kernel/asm-offsets.c
>> b/arch/riscv/kernel/asm-offsets.c
>> index a03129f40c46..eee99c0fbd27 100644
>> --- a/arch/riscv/kernel/asm-offsets.c
>> +++ b/arch/riscv/kernel/asm-offsets.c
>> @@ -10,12 +10,16 @@
>> #include <linux/mm.h>
>> #include <linux/sched.h>
>> #include <linux/suspend.h>
>> +#include <linux/riscv_sse.h>
>> #include <asm/kvm_host.h>
>> #include <asm/thread_info.h>
>> #include <asm/ptrace.h>
>> #include <asm/cpu_ops_sbi.h>
>> #include <asm/stacktrace.h>
>> +#include <asm/sbi.h>
>> +#include <asm/sse.h>
>> #include <asm/suspend.h>
>> +#include <asm/stacktrace.h>
>>
>> void asm_offsets(void);
>>
>> @@ -488,4 +492,26 @@ void asm_offsets(void)
>>     DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe),
>> STACK_ALIGN));
>>     OFFSET(STACKFRAME_FP, stackframe, fp);
>>     OFFSET(STACKFRAME_RA, stackframe, ra);
>> +
>> +#ifdef CONFIG_RISCV_SSE
>> +    OFFSET(SSE_REG_EVT_STACK, sse_registered_event, stack);
>> +    OFFSET(SSE_REG_EVT_SHADOW_STACK, sse_registered_event,
>> shadow_stack);
>> +    OFFSET(SSE_REG_EVT_EVT_ID, sse_registered_event, evt_id);
>> +    OFFSET(SSE_REG_EVT_STATE, sse_registered_event, state);
>> +    OFFSET(SSE_REG_EVT_STATE_PHYS, sse_registered_event, state_phys);
>> +    OFFSET(SSE_REG_EVT_STATE_MODE, sse_registered_event, state.mode);
>> +    OFFSET(SSE_REG_EVT_STATE_PC, sse_registered_event, state.pc);
>> +    OFFSET(SSE_REG_EVT_STATE_A0, sse_registered_event, state.a0);
>> +    OFFSET(SSE_REG_EVT_STATE_A6, sse_registered_event, state.a6);
>> +    OFFSET(SSE_REG_EVT_STATE_A7, sse_registered_event, state.a7);
>> +
>> +    DEFINE(SBI_EXT_SSE, SBI_EXT_SSE);
>> +    DEFINE(SBI_SSE_EVENT_COMPLETE, SBI_SSE_EVENT_COMPLETE);
>> +    DEFINE(SBI_SSE_EVENT_ATTR_READ, SBI_SSE_EVENT_ATTR_READ);
>
>
>> +    DEFINE(SBI_SSE_ATTR_INTERRUPTED_MODE,
>> SBI_SSE_ATTR_INTERRUPTED_MODE);
>> +    DEFINE(SBI_SSE_ATTR_INTERRUPTED_SIZE, SBI_SSE_ATTR_INTERRUPTED_A7 -
>> +                          SBI_SSE_ATTR_INTERRUPTED_MODE);
>> +#endif
>> +
>> +    DEFINE(ASM_PAGE_OFFSET, CONFIG_PAGE_OFFSET);
>> }
>> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
>> index 54ca4564a926..c9046c59e06c 100644
>> --- a/arch/riscv/kernel/entry.S
>> +++ b/arch/riscv/kernel/entry.S
>> @@ -19,17 +19,49 @@
>>
>>     .section .irqentry.text, "ax"
>>
>> +#ifdef CONFIG_RISCV_SSE
>> +#define IN_TP            0
>> +#define IN_SSCRATCH        1
>> +#define PRV_U_TASK_LOC(loc)    (loc << 0)
>> +#define PRV_S_TASK_LOC(loc)    (loc << 1)
>> +#define TASK_LOC(s_loc, u_loc)    (PRV_U_TASK_LOC(u_loc) |
>> PRV_S_TASK_LOC(s_loc))
>> +#define TASK_LOC_ENTRY_SIZE    (RISCV_SZPTR + 1)
>> +
>> +/* __SSE_TASK_LOC - Annotate e'xception code with the location of
>> current task
>> + *            struct when coming from S/U mode
>> + *
>> + * When entering handle_exception(), the current task struct is
>> located either
>> + * in tp or sscratch depending on interrupted mode. Since SSE
>> handlers can be
>> + * triggered at any time during the execution of the kernel, we need
>> to be able
>> + * to retrieve the current task struct even if in handle_exception.
>> This macro
>> + * create an entry into the __task_loc section that holds the
>> location of
>> + * the current task struct for the subsequent assembly located after
>> that up to
>> + * .Lret_from_exception_end or the next __TASK_LOC.
>> + */
>> +#define __SSE_TASK_LOC(s_loc, u_loc)            \
>> +    .pushsection __task_loc,"a";    \
>> +    RISCV_PTR 99f;                \
>> +    .byte TASK_LOC(s_loc, u_loc);        \
>> +    .popsection;                \
>> +    99:
>> +#else
>> +#define __SSE_TASK_LOC(s_loc, u_loc)
>> +#endif
>> +
>> SYM_CODE_START(handle_exception)
>>     /*
>>      * If coming from userspace, preserve the user thread pointer and
>> load
>>      * the kernel thread pointer.  If we came from the kernel, the
>> scratch
>>      * register will contain 0, and we should continue on the current TP.
>>      */
>> +__SSE_TASK_LOC(IN_TP, IN_SSCRATCH)
>>     csrrw tp, CSR_SCRATCH, tp
>> +__SSE_TASK_LOC(IN_SSCRATCH, IN_TP)
>>     bnez tp, .Lsave_context
>>
>> .Lrestore_kernel_tpsp:
>>     csrr tp, CSR_SCRATCH
>> +__SSE_TASK_LOC(IN_TP, IN_TP)
>>     REG_S sp, TASK_TI_KERNEL_SP(tp)
>>
>> #ifdef CONFIG_VMAP_STACK
>> @@ -160,6 +192,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception)
>>     REG_SC x0, a2, PT_EPC(sp)
>>
>>     csrw CSR_STATUS, a0
>> +__SSE_TASK_LOC(IN_TP, IN_SSCRATCH)
>>     csrw CSR_EPC, a2
>>
>>     REG_L x1,  PT_RA(sp)
>> @@ -175,6 +208,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception)
>> #else
>>     sret
>> #endif
>> +.Lret_from_exception_end:
>> SYM_CODE_END(ret_from_exception)
>>
>> #ifdef CONFIG_VMAP_STACK
>> @@ -262,6 +296,171 @@ SYM_FUNC_START(call_on_irq_stack)
>> SYM_FUNC_END(call_on_irq_stack)
>> #endif /* CONFIG_IRQ_STACKS */
>>
>> +#ifdef CONFIG_RISCV_SSE
>> +
>> +/* When entering handle_sse, the following registers are set:
>> + * a0: contains struct sse_registered_event pointer.
>> + *
>> + * See sse_entry_init().
>> + */
>> +SYM_CODE_START(handle_sse)
>> +    /* Save stack temporarily */
>> +    move a7, sp
>> +    /* Set entry stack */
>> +    REG_L sp, SSE_REG_EVT_STACK(a0)
>> +    li a6, IRQ_STACK_SIZE
>
> SSE_STACK_SIZE ?

Yes

>
>> +    add sp, sp, a6
>> +
>> +    addi sp, sp, -(PT_SIZE_ON_STACK)
>> +    REG_S a7,  PT_SP(sp)
>> +    save_regs_for_sse
>> +
>> +    load_global_pointer
>> +    scs_load_sse_stack a0
>> +
>> +    REG_L s3, SSE_REG_EVT_EVT_ID(a0)
>> +    /* a0 is clobbered by sbi calls return, save it for later
>> (reg_event)*/
>> +    move s2, a0
>> +    /* event id */
>> +    move a0, s3
>> +    /* base_attr_id */
>> +    li a1, SBI_SSE_ATTR_INTERRUPTED_MODE
>> +    /* attr_count */
>> +    li a2, SBI_SSE_ATTR_INTERRUPTED_SIZE
>> +    /* phys_lo */
>> +    REG_L a3, SSE_REG_EVT_STATE_PHYS(s2)
>> +    /* phys_hi */
>> +    move a4, zero
>> +    li a7, SBI_EXT_SSE
>> +    li a6, SBI_SSE_EVENT_ATTR_READ
>
> Doesn't this interface allow kernel to perform writes to any physical
> location
> using sbi as proxy? or sbi fw will perform some sort of whitelisting and
> actually
> will write to physical location belonging to kernel and will exclude
> physical
> memory location belonging to opensbi firmware. If it doesn't then using
> this interface
> kernel can use sbi fw as a proxy to perform some controlled writes in fw
> memory.
> Let me know if my understanding is incorrect here.

The SBI code actually check for the memory to belong to S-mode of the
domain of this hart. So I think this is safe on that side.

>
>> +    ecall
>> +
>> +    REG_L t2, SSE_REG_EVT_STATE_MODE(s2)
>> +
>> +    /*
>> +     * Depending on where the sse event interrupted the kernel
>> execution,
>> +     * sscratch content might be 0 or not even if kernel was
>> interrupted.
>> +     * This might happen if the sse event was triggered while in
>> +     * handle_exception() right after entry. In that case, sscratch
>> might
>> +     * contain 0 if coming from kernel. In order to handle that easily,
>> +     * simply save sscratch content and restore it when returning
>> from sse
>> +     * event.
>> +     */
>> +    csrr s4, CSR_SSCRATCH
>> +    /*
>> +     * Save CAUSE and TVAL in case of nested exceptions, EPC/STATUS are
>> +     * already saved/restored by handle_exception() for nested
>> exceptions.
>> +     */
>> +    csrr a2, CSR_SCAUSE
>> +    csrr a3, CSR_STVAL
>> +    REG_S a2, PT_CAUSE(sp)
>> +    REG_S a3, PT_BADADDR(sp)
>> +    andi s5, t2, 0x1
>> +
>> +    move a0, s2 /* reg_evt for do_sse() */
>> +    move a1, sp /* pt_regs for do_sse() */
>> +
>> +    /* Userspace was interrupted, simply restore TP from scratch */
>> +    bnez s5, .Lsse_from_kernel
>> +    /* Set tp to point to sscratch content */
>> +    move tp, s4
>> +    j .Lcall_do_sse
>> +
>> +.Lsse_from_kernel:
>> +    REG_L t0, SSE_REG_EVT_STATE_PC(s2)
>> +#ifdef CONFIG_FRAME_POINTER
>> +    /*
>> +     * Else, kernel was interrupted and we will create a correct
>> stack frame
>> +     * from interrupted context.
>> +     */
>> +    addi sp, sp, -STACKFRAME_SIZE_ON_STACK
>> +    REG_S s0, STACKFRAME_FP(sp)
>> +    REG_S t0, STACKFRAME_RA(sp)
>> +    addi s0, sp, STACKFRAME_SIZE_ON_STACK
>> +#endif
>> +
>> +    /*
>> +     * If interrupting the kernel during exception handling
>> +     * (see handle_exception), then, we might have tp either in
>> SSCRATCH or
>> +     * in tp, this part is non regular and requires some more work to
>> +     * determine were is located the current task.
>> +     */
>> +    la t1, handle_exception
>> +    la t2, .Lret_from_exception_end
>
> Since SSE events are nested, is below possible ?
>
> Event 1 happened when `handle_exception` < PC < `ret_from_exception` and
> `tp = 0`
> `handle_see` is called and this code hasn't reached a point of obtaining
> correct `tp`
> Firmware is triggered again on this or another hart.
> Firmware decides to inject another event on this hart (either global or
> local) i.e. Event 2
>
> Now `handle_sse` for Event 2 will think I am good because PC is outside
> the range of `handle_exception`
> and `ret_from_exception`. And go ahead and call `do_sse` which will lead
> to crash eventually.

And you are right :D That part of the exception is a pain to handle,
I(ll try to find a way to handle nested event at the beginning of SSE
handler.

>
>
>> +    bltu t0, t1, .Lcall_do_sse
>> +    bltu t0, t2, .Lsse_exception_slow_path
>> +
>> +.Lcall_do_sse:
>> +    /* In-kernel scratch is 0 */
>> +    csrw CSR_SCRATCH, x0
>> +    la ra, ret_from_sse
>> +    tail do_sse
>> +
>> +.global ret_from_sse
>> +ret_from_sse:
>> +    /* Restore saved CSRs */
>> +    csrw CSR_SSCRATCH, s4
>> +    /* Preserve event_id before restoring registers */
>> +    move a6, s3
>> +
>> +#ifdef CONFIG_FRAME_POINTER
>> +    /* Frame pointer is created only when kernel is interrupted */
>> +    beqz s5, .Lret_from_sse_to_user
>> +    addi sp, sp, STACKFRAME_SIZE_ON_STACK
>> +.Lret_from_sse_to_user:
>> +#endif
>> +
>> +    REG_L a2, PT_CAUSE(sp)
>> +    REG_L a3, PT_BADADDR(sp)
>> +    csrw CSR_SCAUSE, a2
>> +    csrw CSR_STVAL, a3
>> +
>> +    restore_regs_for_sse
>> +    REG_L sp,  PT_SP(sp)
>> +
>> +    /* prepare ecall with event_id */
>> +    move a0, a6
>> +    li a7, SBI_EXT_SSE
>> +    li a6, SBI_SSE_EVENT_COMPLETE
>> +    ecall
>> +
>> +/*
>> + * t0 contains interrupted pc
>> + * When called, t0 must be in [handle_exception,
>> .Lret_from_exception_end[
>> + */
>> +.Lsse_exception_slow_path:
>> +    la t3, __stop___task_loc
>> +    add t3, t3, -TASK_LOC_ENTRY_SIZE
>> +    la t4, __start___task_loc
>> +    /*
>> +     * Reverse iterate the task location section to find where is
>> located
>> +     * the task struct
>> +     */
>> +1:
>> +    REG_L    t2, 0(t3)
>> +    bgeu t0, t2, 2f
>> +    add t3, t3, -TASK_LOC_ENTRY_SIZE
>> +    bgeu t3, t4, 1b
>> +
>> +2:
>> +    lbu t2, RISCV_SZPTR(t3)
>> +
>> +    /* Get the value of SR_SPP */
>> +    csrr t1, CSR_SSTATUS
>> +    andi t1, t1, SR_SPP
>> +    snez t1, t1
>> +
>> +    srl t2, t2, t1
>> +    andi t2, t2, 1
>> +    beqz t2, .Lcall_do_sse
>> +
>> +_restore_tp_from_sscratch:
>> +    csrr tp, CSR_SCRATCH
>> +    j .Lcall_do_sse
>> +
>> +SYM_CODE_END(handle_sse)
>> +#endif
>> +
>> /*
>>  * Integer register context switch
>>  * The callee-saved registers must be saved and restored.
>> @@ -348,3 +547,6 @@ SYM_DATA_START(__user_rt_sigreturn)
>>     ecall
>> SYM_DATA_END(__user_rt_sigreturn)
>> #endif
>> +
>> +sse_panic_string:
>> +    .ascii "SSE TP is invalid, last state %px"
> Is this string used somewhere? I don't see it in this commit.

Nice catch, it was actually used as a part of sanity check code. I'll
remove that.

Thanks,

Clément