1/* 2 * Copyright (c) 2006-2020, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2018-12-10 Jesven first version 9 * 2021-02-03 lizhirui port to riscv64 10 * 2021-02-19 lizhirui port to new version of rt-smart 11 * 2022-11-08 Wangxiaoyao Cleanup codes; 12 * Support new context switch 13 * 2023-07-16 Shell Move part of the codes to C from asm in signal handling 14 */ 15 16#include "rtconfig.h" 17 18#ifndef __ASSEMBLY__ 19#define __ASSEMBLY__ 20#endif /* __ASSEMBLY__ */ 21 22#include "cpuport.h" 23#include "encoding.h" 24#include "stackframe.h" 25#include "asm-generic.h" 26 27.section .text.lwp 28 29/* 30 * void arch_start_umode(args, text, ustack, kstack); 31 */ 32.global arch_start_umode 33.type arch_start_umode, % function 34arch_start_umode: 35 // load kstack for user process 36 csrw sscratch, a3 37 li t0, SSTATUS_SPP | SSTATUS_SIE // set as user mode, close interrupt 38 csrc sstatus, t0 39 li t0, SSTATUS_SPIE // enable interrupt when return to user mode 40 csrs sstatus, t0 41 42 csrw sepc, a1 43 mv sp, a2 44 sret//enter user mode 45 46/* 47 * void arch_crt_start_umode(args, text, ustack, kstack); 48 */ 49.global arch_crt_start_umode 50.type arch_crt_start_umode, % function 51arch_crt_start_umode: 52 li t0, SSTATUS_SPP | SSTATUS_SIE // set as user mode, close interrupt 53 csrc sstatus, t0 54 li t0, SSTATUS_SPIE // enable interrupt when return to user mode 55 csrs sstatus, t0 56 57 csrw sepc, a1 58 mv s0, a0 59 mv s1, a1 60 mv s2, a2 61 mv s3, a3 62 mv a0, s2 63 call lwp_copy_return_code_to_user_stack 64 mv a0, s2 65 call lwp_fix_sp 66 mv sp, a0//user_sp 67 mv ra, a0//return address 68 mv a0, s0//args 69 70 csrw sscratch, s3 71 sret//enter user mode 72 73/** 74 * Unify exit point from kernel mode to enter user space 75 * we handle following things here: 76 * 1. restoring user mode debug state (not support yet) 77 * 2. handling thread's exit request 78 * 3. handling POSIX signal (skipped for signal quit path) 79 * 4. restoring user context 80 * 5. jump to user mode 81 */ 82.global arch_ret_to_user 83arch_ret_to_user: 84 li s0, 1 // flag=1 (normal path) 85 j arch_ret_to_user_impl 86 87.global arch_signal_quit_ret_to_user 88arch_signal_quit_ret_to_user: 89 li s0, 0 // flag=0 (signal quit path) 90 91arch_ret_to_user_impl: 92 // TODO: we don't support kernel gdb server in risc-v yet 93 // so we don't check debug state here and handle debugging bussiness 94 95 call lwp_check_exit_request 96 beqz a0, 1f 97 mv a0, x0 98 call sys_exit 99 1001: 101 // Skip signal handling if coming from arch_signal_quit 102 beqz s0, ret_to_user_exit 103 mv a0, sp 104 call lwp_thread_signal_catch 105 106ret_to_user_exit: 107 RESTORE_ALL 108 // `RESTORE_ALL` also reset sp to user sp, and setup sscratch 109 sret 110 111/** 112 * Restore user context from exception frame stroraged in ustack 113 * And handle pending signals; 114 */ 115arch_signal_quit: 116 LOAD a0, FRAME_OFF_SP(sp) 117 call arch_signal_ucontext_restore 118 119 /* reset kernel sp to the stack */ 120 addi sp, sp, CTX_REG_NR * REGBYTES 121 STORE sp, FRAME_OFF_SP(a0) 122 /* return value is user sp */ 123 mv sp, a0 124 125 /* restore user sp before enter trap */ 126 addi a0, sp, CTX_REG_NR * REGBYTES 127 csrw sscratch, a0 128 129 130 RESTORE_ALL 131 SAVE_ALL 132 j arch_signal_quit_ret_to_user 133 134/** 135 * rt_noreturn 136 * void arch_thread_signal_enter( 137 * int signo, -> a0 138 * siginfo_t *psiginfo, -> a1 139 * void *exp_frame, -> a2 140 * void *entry_uaddr, -> a3 141 * lwp_sigset_t *save_sig_mask, -> a4 142 * ) 143 */ 144.global arch_thread_signal_enter 145arch_thread_signal_enter: 146 mv s3, a2 147 mv s2, a0 148 mv s1, a3 149 150 LOAD t0, FRAME_OFF_SP(a2) 151 mv a3, t0 152 call arch_signal_ucontext_save 153 154 /** restore kernel sp */ 155 addi sp, s3, CTX_REG_NR * REGBYTES 156 157 /** 158 * set regiter RA to user signal handler 159 * set sp to user sp & save kernel sp in sscratch 160 */ 161 mv ra, a0 162 csrw sscratch, sp 163 mv sp, a0 164 165 /** 166 * s1 is signal_handler, 167 * s1 = !s1 ? lwp_sigreturn : s1; 168 */ 169 bnez s1, 1f 170 mv s1, ra 171 1721: 173 /* enter user mode and enable interrupt when return to user mode */ 174 li t0, SSTATUS_SPP 175 csrc sstatus, t0 176 li t0, SSTATUS_SPIE 177 csrs sstatus, t0 178 179 /* sepc <- signal_handler */ 180 csrw sepc, s1 181 /* a0 <- signal id */ 182 mv a0, s2 183 /* a1 <- siginfo */ 184 add a1, sp, 16 185 /* dummy a2 */ 186 mv a2, a1 187 188 /* restore user GP */ 189 LOAD gp, FRAME_OFF_GP(s3) 190 191 /* restore user TP */ 192 LOAD tp, FRAME_OFF_TP(s3) 193 194 /** 195 * handler(signo, psi, ucontext); 196 */ 197 sret 198 199.align 3 200lwp_debugreturn: 201 li a7, 0xff 202 ecall 203 204.align 3 205.global lwp_sigreturn 206lwp_sigreturn: 207 li a7, 0xfe 208 ecall 209 210.align 3 211lwp_sigreturn_end: 212 213.align 3 214.global lwp_thread_return 215lwp_thread_return: 216 li a0, 0 217 li a7, 1 218 ecall 219 220.align 3 221.global lwp_thread_return_end 222lwp_thread_return_end: 223 224.globl arch_get_tidr 225arch_get_tidr: 226 mv a0, tp 227 ret 228 229.global arch_set_thread_area 230arch_set_thread_area: 231.globl arch_set_tidr 232arch_set_tidr: 233 mv tp, a0 234 ret 235 236.global arch_clone_exit 237.global arch_fork_exit 238arch_fork_exit: 239arch_clone_exit: 240 j arch_syscall_exit 241 242START_POINT(syscall_entry) 243#ifndef ARCH_USING_NEW_CTX_SWITCH 244 //swap to thread kernel stack 245 csrr t0, sstatus 246 andi t0, t0, 0x100 247 beqz t0, __restore_sp_from_tcb 248 249__restore_sp_from_sscratch: // from kernel 250 csrr t0, sscratch 251 j __move_stack_context 252 253__restore_sp_from_tcb: // from user 254 jal rt_thread_self 255 jal get_thread_kernel_stack_top 256 mv t0, a0 257 258__move_stack_context: 259 mv t1, sp//src 260 mv sp, t0//switch stack 261 addi sp, sp, -CTX_REG_NR * REGBYTES 262 //copy context 263 li s0, CTX_REG_NR//cnt 264 mv t2, sp//dst 265 266copy_context_loop: 267 LOAD t0, 0(t1) 268 STORE t0, 0(t2) 269 addi s0, s0, -1 270 addi t1, t1, 8 271 addi t2, t2, 8 272 bnez s0, copy_context_loop 273#endif /* ARCH_USING_NEW_CTX_SWITCH */ 274 275 /* fetch SYSCALL ID */ 276 LOAD a7, 17 * REGBYTES(sp) 277 addi a7, a7, -0xfe 278 beqz a7, arch_signal_quit 279 280#ifdef ARCH_MM_MMU 281 /* save setting when syscall enter */ 282 call rt_thread_self 283 call lwp_user_setting_save 284#endif 285 286 mv a0, sp 287 OPEN_INTERRUPT 288 call syscall_handler 289 j arch_syscall_exit 290START_POINT_END(syscall_entry) 291 292.global arch_syscall_exit 293arch_syscall_exit: 294 CLOSE_INTERRUPT 295 296 #if defined(ARCH_MM_MMU) 297 LOAD s0, FRAME_OFF_SSTATUS(sp) 298 andi s0, s0, 0x100 299 bnez s0, dont_ret_to_user 300 j arch_ret_to_user 301 #endif 302dont_ret_to_user: 303 304#ifdef ARCH_MM_MMU 305 /* restore setting when syscall exit */ 306 call rt_thread_self 307 call lwp_user_setting_restore 308 309 /* after restore the reg `tp`, need modify context */ 310 STORE tp, 4 * REGBYTES(sp) 311#endif 312 313 //restore context 314 RESTORE_ALL 315 csrw sscratch, zero 316 sret 317