1/* SPDX-License-Identifier: BSD-2-Clause */ 2/* 3 * Copyright 2022-2023 NXP 4 */ 5 6#include <asm.S> 7#include <generated/asm-defines.h> 8#include <keep.h> 9#include <kernel/thread.h> 10#include <kernel/thread_private.h> 11#include <mm/core_mmu.h> 12#include <riscv.h> 13#include <riscv_macros.S> 14 15.macro get_thread_ctx res, tmp0 16 lw \tmp0, THREAD_CORE_LOCAL_CURR_THREAD(tp) 17 la \res, threads 181: 19 beqz \tmp0, 2f 20 addi \res, \res, THREAD_CTX_SIZE 21 addi \tmp0, \tmp0, -1 22 bnez \tmp0, 1b 232: 24.endm 25 26.macro save_regs, mode 27 addi sp, sp, -THREAD_TRAP_REGS_SIZE 28.if \mode == TRAP_MODE_USER 29 30 /* Save user thread pointer and load kernel thread pointer */ 31 store_xregs sp, THREAD_TRAP_REG_TP, REG_TP 32 addi tp, sp, THREAD_TRAP_REGS_SIZE 33 /* Now tp is at struct thread_user_mode_rec, which has kernel tp */ 34 load_xregs tp, THREAD_USER_MODE_REC_X4, REG_TP 35 36 store_xregs sp, THREAD_TRAP_REG_GP, REG_GP 37 38 /* 39 * Set the scratch register to 0 such in case of a recursive 40 * exception thread_trap_vect() knows that it is emitted from kernel. 41 */ 42 csrrw gp, CSR_XSCRATCH, zero 43 store_xregs sp, THREAD_TRAP_REG_SP, REG_GP 44.option push 45.option norelax 46 la gp, __global_pointer$ 47.option pop 48.endif 49 store_xregs sp, THREAD_TRAP_REG_T3, REG_T3, REG_T6 50 store_xregs sp, THREAD_TRAP_REG_T0, REG_T0, REG_T2 51 store_xregs sp, THREAD_TRAP_REG_A0, REG_A0, REG_A7 52 store_xregs sp, THREAD_TRAP_REG_RA, REG_RA 53#if defined(CFG_UNWIND) 54 /* To unwind stack we need s0, which is frame pointer. */ 55 store_xregs sp, THREAD_TRAP_REG_S0, REG_S0 56#endif 57 58 csrr t0, CSR_XSTATUS 59 store_xregs sp, THREAD_TRAP_REG_STATUS, REG_T0 60 61 csrr a0, CSR_XCAUSE 62 csrr a1, CSR_XEPC 63 64 store_xregs sp, THREAD_TRAP_REG_EPC, REG_A1 65 66 mv a2, sp 67 68 /* a0 = cause 69 * a1 = epc 70 * a2 = sp 71 * a3 = user 72 * thread_trap_handler(cause, epc, sp, user) 73 */ 74.endm 75 76.macro restore_regs, mode 77 load_xregs sp, THREAD_TRAP_REG_EPC, REG_T0 78 csrw CSR_XEPC, t0 79 80 load_xregs sp, THREAD_TRAP_REG_STATUS, REG_T0 81 csrw CSR_XSTATUS, t0 82 83 load_xregs sp, THREAD_TRAP_REG_RA, REG_RA 84 load_xregs sp, THREAD_TRAP_REG_A0, REG_A0, REG_A7 85 load_xregs sp, THREAD_TRAP_REG_T0, REG_T0, REG_T2 86 load_xregs sp, THREAD_TRAP_REG_T3, REG_T3, REG_T6 87#if defined(CFG_UNWIND) 88 /* To unwind stack we need s0, which is frame pointer. */ 89 load_xregs sp, THREAD_TRAP_REG_S0, REG_S0 90#endif 91 92.if \mode == TRAP_MODE_USER 93 addi gp, sp, THREAD_TRAP_REGS_SIZE 94 csrw CSR_XSCRATCH, gp 95 96 load_xregs sp, THREAD_TRAP_REG_TP, REG_TP 97 load_xregs sp, THREAD_TRAP_REG_GP, REG_GP 98 load_xregs sp, THREAD_TRAP_REG_SP, REG_SP 99 100.else 101 addi sp, sp, THREAD_TRAP_REGS_SIZE 102.endif 103.endm 104 105/* size_t __get_core_pos(void); */ 106FUNC __get_core_pos , : , .identity_map 107 lw a0, THREAD_CORE_LOCAL_HART_ID(tp) 108 ret 109END_FUNC __get_core_pos 110 111FUNC thread_trap_vect , : 112 csrrw sp, CSR_XSCRATCH, sp 113 bnez sp, 0f 114 csrrw sp, CSR_XSCRATCH, sp 115 j trap_from_kernel 1160: 117 j trap_from_user 118thread_trap_vect_end: 119END_FUNC thread_trap_vect 120 121LOCAL_FUNC trap_from_kernel, : 122 save_regs TRAP_MODE_KERNEL 123 li a3, 0 124 jal thread_trap_handler 125 restore_regs TRAP_MODE_KERNEL 126 XRET 127END_FUNC trap_from_kernel 128 129LOCAL_FUNC trap_from_user, : 130 save_regs TRAP_MODE_USER 131 li a3, 1 132 jal thread_trap_handler 133 restore_regs TRAP_MODE_USER 134 XRET 135END_FUNC trap_from_user 136 137/* 138 * void thread_unwind_user_mode(uint32_t ret, uint32_t exit_status0, 139 * uint32_t exit_status1); 140 * See description in thread.h 141 */ 142FUNC thread_unwind_user_mode , : 143 144 /* Store the exit status */ 145 load_xregs sp, THREAD_USER_MODE_REC_CTX_REGS_PTR, REG_A3, REG_A5 146 sw a1, (a4) 147 sw a2, (a5) 148 149 /* Save user callee regs */ 150 store_xregs a3, THREAD_CTX_REG_S0, REG_S0, REG_S1 151 store_xregs a3, THREAD_CTX_REG_S2, REG_S2, REG_S11 152 store_xregs a3, THREAD_CTX_REG_SP, REG_SP, REG_TP 153 154 /* Restore kernel callee regs */ 155 mv a1, sp 156 157 load_xregs a1, THREAD_USER_MODE_REC_X1, REG_RA, REG_TP 158 load_xregs a1, THREAD_USER_MODE_REC_X8, REG_S0, REG_S1 159 load_xregs a1, THREAD_USER_MODE_REC_X18, REG_S2, REG_S11 160 161 add sp, sp, THREAD_USER_MODE_REC_SIZE 162 163 /* 164 * Zeroize xSCRATCH to indicate to thread_trap_vect() 165 * that we are executing in kernel. 166 */ 167 csrw CSR_XSCRATCH, zero 168 169 /* Return from the call of thread_enter_user_mode() */ 170 ret 171END_FUNC thread_unwind_user_mode 172 173/* 174 * void thread_exit_user_mode(unsigned long a0, unsigned long a1, 175 * unsigned long a2, unsigned long a3, 176 * unsigned long sp, unsigned long pc, 177 * unsigned long status); 178 */ 179FUNC thread_exit_user_mode , : 180 /* Set kernel stack pointer */ 181 mv sp, a4 182 183 /* Set xSTATUS */ 184 csrw CSR_XSTATUS, a6 185 186 /* Set return address thread_unwind_user_mode() */ 187 mv ra, a5 188 ret 189END_FUNC thread_exit_user_mode 190 191/* 192 * uint32_t __thread_enter_user_mode(struct thread_ctx_regs *regs, 193 * uint32_t *exit_status0, 194 * uint32_t *exit_status1); 195 */ 196FUNC __thread_enter_user_mode , : 197 /* 198 * Create and fill in the struct thread_user_mode_rec 199 */ 200 addi sp, sp, -THREAD_USER_MODE_REC_SIZE 201 store_xregs sp, THREAD_USER_MODE_REC_CTX_REGS_PTR, REG_A0, REG_A2 202 store_xregs sp, THREAD_USER_MODE_REC_X1, REG_RA, REG_TP 203 store_xregs sp, THREAD_USER_MODE_REC_X8, REG_S0, REG_S1 204 store_xregs sp, THREAD_USER_MODE_REC_X18, REG_S2, REG_S11 205 206 /* 207 * Save the kernel stack pointer in the thread context 208 */ 209 210 /* Get pointer to current thread context */ 211 get_thread_ctx s0, s1 212 213 /* 214 * Save kernel stack pointer to ensure that 215 * thread_exit_user_mode() uses correct stack pointer. 216 */ 217 218 store_xregs s0, THREAD_CTX_KERN_SP, REG_SP 219 /* 220 * Save kernel stack pointer in xSCRATCH to ensure that 221 * thread_trap_vect() uses correct stack pointer. 222 */ 223 csrw CSR_XSCRATCH, sp 224 225 /* Set user status */ 226 load_xregs a0, THREAD_CTX_REG_STATUS, REG_S0 227 csrw CSR_XSTATUS, s0 228 229 /* 230 * Save the values for a1 and a2 in struct thread_core_local to be 231 * restored later just before the xRET. 232 */ 233 store_xregs tp, THREAD_CORE_LOCAL_X10, REG_A1, REG_A2 234 235 /* Load the rest of the general purpose registers */ 236 load_xregs a0, THREAD_CTX_REG_RA, REG_RA, REG_TP 237 load_xregs a0, THREAD_CTX_REG_T0, REG_T0, REG_T2 238 load_xregs a0, THREAD_CTX_REG_S0, REG_S0, REG_S1 239 load_xregs a0, THREAD_CTX_REG_S2, REG_S2, REG_S11 240 load_xregs a0, THREAD_CTX_REG_T3, REG_T3, REG_T6 241 load_xregs a0, THREAD_CTX_REG_A0, REG_A0, REG_A7 242 243 /* Set exception program counter */ 244 csrw CSR_XEPC, ra 245 246 /* Jump into user mode */ 247 XRET 248END_FUNC __thread_enter_user_mode 249 250/* void thread_resume(struct thread_ctx_regs *regs) */ 251FUNC thread_resume , : 252 /* 253 * Restore all registers assuming that GP 254 * and TP were not changed. 255 */ 256 load_xregs a0, THREAD_CTX_REG_RA, REG_RA, REG_SP 257 load_xregs a0, THREAD_CTX_REG_T0, REG_T0, REG_T2 258 load_xregs a0, THREAD_CTX_REG_S0, REG_S0, REG_S1 259 load_xregs a0, THREAD_CTX_REG_S2, REG_S2, REG_S11 260 load_xregs a0, THREAD_CTX_REG_T3, REG_T3, REG_T6 261 load_xregs a0, THREAD_CTX_REG_A0, REG_A0, REG_A7 262 store_xregs tp, THREAD_CORE_LOCAL_X10, REG_A0, REG_A1 263 ret 264END_FUNC thread_resume 265