summaryrefslogtreecommitdiff
path: root/components/lwp/arch/risc-v/rv64/lwp_gcc.S
blob: b74abe5da12e9b1cd69999111be1986266c8e2c3 (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-12-10     Jesven       first version
 * 2021-02-03     lizhirui     port to riscv64
 * 2021-02-19     lizhirui     port to new version of rt-smart
 * 2022-11-08     Wangxiaoyao  Cleanup codes;
 *                             Support new context switch
 * 2023-07-16     Shell        Move part of the codes to C from asm in signal handling
 */

#include "rtconfig.h"

#ifndef __ASSEMBLY__
#define __ASSEMBLY__
#endif /* __ASSEMBLY__ */

#ifdef RT_USING_RISCV_NEW_COMMON
#include "asm.h"
#include "csr.h"

#define LOAD                REG_L
#define STORE               REG_S
#define REGBYTES            SZREG
#define CTX_REG_NR          CTX_ALL_REG_NR
#define FRAME_OFF_SSTATUS   FRAME_OFF_XSTATUS
#define SSTATUS_SPP         SR_PP
#define SSTATUS_SIE         SR_IE
#define SSTATUS_SPIE        SR_PIE
#define sstatus             CSR_STATUS
#define sscratch            CSR_SCRATCH
#define sepc                CSR_EPC
#else
#include "cpuport.h"
#include "encoding.h"
#include "stackframe.h"
#include "asm-generic.h"
#endif

.section      .text.lwp

/*
 * void arch_start_umode(args, text, ustack, kstack);
 */
.global arch_start_umode
.type arch_start_umode, % function
arch_start_umode:
    // load kstack for user process
    csrw sscratch, a3
    li t0, SSTATUS_SPP | SSTATUS_SIE    // set as user mode, close interrupt
    csrc sstatus, t0
    li t0, SSTATUS_SPIE // enable interrupt when return to user mode
    csrs sstatus, t0

    csrw sepc, a1
    mv sp, a2
    sret//enter user mode

/*
 * void arch_crt_start_umode(args, text, ustack, kstack);
 */
.global arch_crt_start_umode
.type arch_crt_start_umode, % function
arch_crt_start_umode:
    li t0, SSTATUS_SPP | SSTATUS_SIE    // set as user mode, close interrupt
    csrc sstatus, t0
    li t0, SSTATUS_SPIE // enable interrupt when return to user mode
    csrs sstatus, t0

    csrw sepc, a1
    mv s0, a0
    mv s1, a1
    mv s2, a2
    mv s3, a3
    mv a0, s2
    call lwp_copy_return_code_to_user_stack
    mv a0, s2
    call lwp_fix_sp
    mv sp, a0//user_sp
    mv ra, a0//return address
    mv a0, s0//args

    csrw sscratch, s3
    sret//enter user mode

/**
 * Unify exit point from kernel mode to enter user space
 * we handle following things here:
 * 1. restoring user mode debug state (not support yet)
 * 2. handling thread's exit request
 * 3. handling POSIX signal (skipped for signal quit path)
 * 4. restoring user context
 * 5. jump to user mode
 */
.global arch_ret_to_user
arch_ret_to_user:
    li s0, 1   // flag=1 (normal path)
    j arch_ret_to_user_impl

.global arch_signal_quit_ret_to_user
arch_signal_quit_ret_to_user:
    li s0, 0   // flag=0 (signal quit path)

arch_ret_to_user_impl:
    // TODO: we don't support kernel gdb server in risc-v yet
    // so we don't check debug state here and handle debugging bussiness

    call lwp_check_exit_request
    beqz a0, 1f
    mv a0, x0
    call sys_exit

1:
    // Skip signal handling if coming from arch_signal_quit
    beqz s0, ret_to_user_exit
    mv a0, sp
    call lwp_thread_signal_catch

ret_to_user_exit:
    RESTORE_ALL
    // `RESTORE_ALL` also reset sp to user sp, and setup sscratch
    sret

/**
 * Restore user context from exception frame stroraged in ustack
 * And handle pending signals;
 */
arch_signal_quit:
    LOAD a0, FRAME_OFF_SP(sp)
    call arch_signal_ucontext_restore

    /* reset kernel sp to the stack */
    addi sp, sp, CTX_REG_NR * REGBYTES
    STORE sp, FRAME_OFF_SP(a0)
    /* return value is user sp */
    mv sp, a0

    /* restore user sp before enter trap */
    addi a0, sp, CTX_REG_NR * REGBYTES
    csrw sscratch, a0


    RESTORE_ALL
    SAVE_ALL
    j arch_signal_quit_ret_to_user

/**
 * rt_noreturn
 * void arch_thread_signal_enter(
 *      int signo,                      -> a0
 *      siginfo_t *psiginfo,            -> a1
 *      void *exp_frame,                -> a2
 *      void *entry_uaddr,              -> a3
 *      lwp_sigset_t *save_sig_mask,    -> a4
 *      )
 */
.global arch_thread_signal_enter
arch_thread_signal_enter:
    mv s3, a2
    mv s2, a0
    mv s1, a3

    LOAD t0, FRAME_OFF_SP(a2)
    mv a3, t0
    call arch_signal_ucontext_save

    /** restore kernel sp */
    addi sp, s3, CTX_REG_NR * REGBYTES

    /**
     * set regiter RA to user signal handler
     * set sp to user sp & save kernel sp in sscratch
     */
    mv ra, a0
    csrw sscratch, sp
    mv sp, a0

    /**
     * s1 is signal_handler,
     * s1 = !s1 ? lwp_sigreturn : s1;
     */
    bnez s1, 1f
    mv s1, ra

1:
    /* enter user mode and enable interrupt when return to user mode */
    li t0, SSTATUS_SPP
    csrc sstatus, t0
    li t0, SSTATUS_SPIE
    csrs sstatus, t0

    /* sepc <- signal_handler */
    csrw sepc, s1
    /* a0 <- signal id */
    mv a0, s2
    /* a1 <- siginfo */
    add a1, sp, 16
    /* dummy a2 */
    mv a2, a1

    /* restore user GP */
    LOAD gp, FRAME_OFF_GP(s3)

    /* restore user TP */
    LOAD tp, FRAME_OFF_TP(s3)

    /**
     * handler(signo, psi, ucontext);
     */
    sret

.align 3
lwp_debugreturn:
    li a7, 0xff
    ecall

.align 3
.global lwp_sigreturn
lwp_sigreturn:
    li a7, 0xfe
    ecall

.align 3
lwp_sigreturn_end:

.align 3
.global lwp_thread_return
lwp_thread_return:
    li a0, 0
    li a7, 1
    ecall

.align 3
.global lwp_thread_return_end
lwp_thread_return_end:

.globl arch_get_tidr
arch_get_tidr:
    mv a0, tp
    ret

.global arch_set_thread_area
arch_set_thread_area:
.globl arch_set_tidr
arch_set_tidr:
    mv tp, a0
    ret

.global arch_clone_exit
.global arch_fork_exit
arch_fork_exit:
arch_clone_exit:
    j arch_syscall_exit

START_POINT(syscall_entry)
#ifndef ARCH_USING_NEW_CTX_SWITCH
    //swap to thread kernel stack
    csrr t0, sstatus
    andi t0, t0, 0x100
    beqz t0, __restore_sp_from_tcb

__restore_sp_from_sscratch: // from kernel
    csrr t0, sscratch
    j __move_stack_context

__restore_sp_from_tcb: // from user
    jal rt_thread_self
    jal get_thread_kernel_stack_top
    mv t0, a0

__move_stack_context:
    mv t1, sp//src
    mv sp, t0//switch stack
    addi sp, sp, -CTX_REG_NR * REGBYTES
    //copy context
    li s0, CTX_REG_NR//cnt
    mv t2, sp//dst

copy_context_loop:
    LOAD t0, 0(t1)
    STORE t0, 0(t2)
    addi s0, s0, -1
    addi t1, t1, REGBYTES
    addi t2, t2, REGBYTES
    bnez s0, copy_context_loop
#endif /* ARCH_USING_NEW_CTX_SWITCH */

    /* fetch SYSCALL ID */
    LOAD a7, FRAME_OFF_A7(sp)
    addi a7, a7, -0xfe
    beqz a7, arch_signal_quit

#ifdef ARCH_MM_MMU
    /* save setting when syscall enter */
    call  rt_thread_self
    call  lwp_user_setting_save
#endif

    mv a0, sp
    OPEN_INTERRUPT
    call syscall_handler
    j arch_syscall_exit
START_POINT_END(syscall_entry)

.global arch_syscall_exit
arch_syscall_exit:
    CLOSE_INTERRUPT

    #if defined(ARCH_MM_MMU)
        LOAD s0, FRAME_OFF_SSTATUS(sp)
        andi s0, s0, 0x100
        bnez s0, dont_ret_to_user
        j arch_ret_to_user
    #endif
dont_ret_to_user:

#ifdef ARCH_MM_MMU
    /* restore setting when syscall exit */
    call  rt_thread_self
    call  lwp_user_setting_restore

    /* after restore the reg `tp`, need modify context */
    STORE tp, FRAME_OFF_TP(sp)
#endif

    //restore context
    RESTORE_ALL
    csrw sscratch, zero
    sret