summaryrefslogtreecommitdiff
path: root/libcpu/risc-v/common/vector_gcc.S
blob: dff9a48181422177f584426d3fe1e74bbf768fa7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * Copyright (c) 2006-2025, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-10-02     Bernard      The first version
 * 2018-12-27     Jesven       Add SMP schedule
 * 2021-02-02     lizhirui     Add userspace support
 * 2021-12-24     JasonHu      Add user setting save/restore
 * 2022-10-22     Shell        Support kernel mode RVV;
 *                             Rewrite trap handling routine
 * 2025-04-20     GuEe-GUI     Support SMP
 */

#include <asm.h>
#include <csr.h>

    .section ".text","ax"
    .align 6
START_POINT(system_vectors)
#ifdef ARCH_RISCV_USING_IRQ_STACK
    /*
     * Keep the exception frame on the interrupted stack so the scheduler can
     * store it in the thread TCB. Only C-level trap handling uses the IRQ
     * stack. A zero xscratch means that a nested trap is already on it.
     */
    csrrw   sp, CSR_SCRATCH, sp
    beqz    sp, _irq_stack_nested

    /* Recover the interrupted SP without losing the original t0 and t1. */
    addi    sp, sp, -(2 * SZREG)
    REG_S   t0, 0 * SZREG(sp)
    REG_S   t1, 1 * SZREG(sp)
    mv      t1, sp
    csrr    t0, CSR_SCRATCH
    mv      sp, t0
    REG_L   t0, 0 * SZREG(t1)
    REG_L   t1, 1 * SZREG(t1)
    csrw    CSR_SCRATCH, sp

    SAVE_ALL
    mv      s0, sp
    li      s1, 1
    call    riscv_irq_stack_top
    mv      sp, a0
    csrw    CSR_SCRATCH, zero
    j       _context_saved

_irq_stack_nested:
    csrr    sp, CSR_SCRATCH
    SAVE_ALL
    mv      s0, sp
    mv      s1, zero
    csrw    CSR_SCRATCH, zero
#else
    /* Distingush exception from kernel or user */
    csrrw   sp, CSR_SCRATCH, sp
    bnez    sp, _save_context

    /*
     * BE REALLY careful with xscratch,
     * if it's wrong, we could looping here forever
     * or accessing random memory and seeing things totally
     * messy after a long time and don't even know why
     */
_from_kernel:
    csrr    sp, CSR_SCRATCH
    j       _save_context

_save_context:
    SAVE_ALL

    /* Clear xscratch to say 'now in kernel mode' */
    csrw    CSR_SCRATCH, zero
#endif /* ARCH_RISCV_USING_IRQ_STACK */

_context_saved:
    LOAD_GLOBAL_POINTER

    /* Now we are ready to enter interrupt / excepiton handler */
#ifdef RT_USING_SMART
_distinguish_syscall:
    csrr    t0, CSR_CAUSE
    li      t1, EXC_SYSCALL
    bne     t0, t1, _handle_interrupt_and_exception

    call    syscall_entry
    /* Syscall never return here */
#endif /* RT_USING_SMART */

_handle_interrupt_and_exception:
    mv      a0, sp
#ifdef ARCH_RISCV_USING_IRQ_STACK
    mv      a0, s0
#endif
    call    rt_hw_trap

_interrupt_exit:
#ifdef ARCH_RISCV_USING_IRQ_STACK
    /* Restore the exception stack before invoking the scheduler. */
    mv      sp, s0
    beqz    s1, 1f
    call    riscv_irq_stack_top
    csrw    CSR_SCRATCH, a0
    j       2f
1:
    csrw    CSR_SCRATCH, zero
2:
#endif
#ifdef RT_USING_SMP
    mv      a0, sp
    call    rt_scheduler_do_irq_switch
#else
    la      t0, rt_thread_switch_interrupt_flag
    lw      t1, 0(t0)
    beqz    t1, _resume_execution
    sw      zero, 0(t0)

_context_switch:
    la      t0, rt_interrupt_from_thread
    REG_L   a0, 0(t0)
    la      t0, rt_interrupt_to_thread
    REG_L   a1, 0(t0)
    csrr    t0, CSR_STATUS
    andi    t0, t0, ~SR_PIE
    csrw    CSR_STATUS, t0
    jal     rt_hw_context_switch
#endif /* RT_USING_SMP */

_resume_execution:
.globl rt_hw_resume_interrupt
rt_hw_resume_interrupt:
#ifdef RT_USING_SMART
    REG_L   t0, FRAME_OFF_XSTATUS(sp)
    andi    t0, t0, SR_PP
    bnez    t0, rt_hw_resume_kernel
    call    arch_ret_to_user
#endif /* RT_USING_SMART */

    j       rt_hw_resume_kernel
START_POINT_END(system_vectors)

.globl rt_hw_resume_kernel
rt_hw_resume_kernel:
    RESTORE_ALL
#ifndef ARCH_RISCV_USING_IRQ_STACK
    csrw    CSR_SCRATCH, zero
#endif
    XRET

    .align 2
    .weak fast_irq_vectors
START_POINT(fast_irq_vectors)
    j   system_vectors
START_POINT_END(fast_irq_vectors)