19b1a3bbeSMarouene Boubakri/* SPDX-License-Identifier: BSD-2-Clause */ 29b1a3bbeSMarouene Boubakri/* 39b1a3bbeSMarouene Boubakri * Copyright 2022-2023 NXP 45e26ef8fSAlvin Chang * Copyright 2024 Andes Technology Corporation 59b1a3bbeSMarouene Boubakri */ 69b1a3bbeSMarouene Boubakri 79b1a3bbeSMarouene Boubakri#include <asm.S> 89b1a3bbeSMarouene Boubakri#include <generated/asm-defines.h> 99b1a3bbeSMarouene Boubakri#include <keep.h> 109b1a3bbeSMarouene Boubakri#include <kernel/thread.h> 119b1a3bbeSMarouene Boubakri#include <kernel/thread_private.h> 129b1a3bbeSMarouene Boubakri#include <mm/core_mmu.h> 139b1a3bbeSMarouene Boubakri#include <riscv.h> 149b1a3bbeSMarouene Boubakri#include <riscv_macros.S> 158d5bae1cSAlvin Chang#include <tee/optee_abi.h> 168d5bae1cSAlvin Chang#include <tee/teeabi_opteed.h> 178d5bae1cSAlvin Chang#include <tee/teeabi_opteed_macros.h> 189b1a3bbeSMarouene Boubakri 199b1a3bbeSMarouene Boubakri.macro get_thread_ctx res, tmp0 209b1a3bbeSMarouene Boubakri lw \tmp0, THREAD_CORE_LOCAL_CURR_THREAD(tp) 21*91d4649dSJens Wiklander.option push 22*91d4649dSJens Wiklander.option norelax 239b1a3bbeSMarouene Boubakri la \res, threads 24*91d4649dSJens Wiklander.option pop 25*91d4649dSJens Wiklander LDR \res, 0(\res) 269b1a3bbeSMarouene Boubakri1: 279b1a3bbeSMarouene Boubakri beqz \tmp0, 2f 289b1a3bbeSMarouene Boubakri addi \res, \res, THREAD_CTX_SIZE 299b1a3bbeSMarouene Boubakri addi \tmp0, \tmp0, -1 309b1a3bbeSMarouene Boubakri bnez \tmp0, 1b 319b1a3bbeSMarouene Boubakri2: 329b1a3bbeSMarouene Boubakri.endm 339b1a3bbeSMarouene Boubakri 3409653bcaSAlvin Chang.macro b_if_prev_priv_is_u reg, label 3509653bcaSAlvin Chang andi \reg, \reg, CSR_XSTATUS_SPP 3609653bcaSAlvin Chang beqz \reg, \label 3709653bcaSAlvin Chang.endm 3809653bcaSAlvin Chang 399b1a3bbeSMarouene Boubakri/* size_t __get_core_pos(void); */ 409b1a3bbeSMarouene BoubakriFUNC __get_core_pos , : , .identity_map 412e27ec6cSYu-Chien Peter Lin lw a0, THREAD_CORE_LOCAL_HART_INDEX(tp) 429b1a3bbeSMarouene Boubakri ret 439b1a3bbeSMarouene BoubakriEND_FUNC __get_core_pos 449b1a3bbeSMarouene Boubakri 459b1a3bbeSMarouene BoubakriFUNC thread_trap_vect , : 464fe3a3f7SAlvin Chang csrrw tp, CSR_XSCRATCH, tp 474fe3a3f7SAlvin Chang bnez tp, 0f 484fe3a3f7SAlvin Chang /* Read tp back */ 494fe3a3f7SAlvin Chang csrrw tp, CSR_XSCRATCH, tp 509b1a3bbeSMarouene Boubakri j trap_from_kernel 519b1a3bbeSMarouene Boubakri0: 524fe3a3f7SAlvin Chang /* Now tp is thread_core_local */ 539b1a3bbeSMarouene Boubakri j trap_from_user 549b1a3bbeSMarouene Boubakrithread_trap_vect_end: 559b1a3bbeSMarouene BoubakriEND_FUNC thread_trap_vect 569b1a3bbeSMarouene Boubakri 579b1a3bbeSMarouene BoubakriLOCAL_FUNC trap_from_kernel, : 585e26ef8fSAlvin Chang /* Save sp, a0, a1 into temporary spaces of thread_core_local */ 595e26ef8fSAlvin Chang store_xregs tp, THREAD_CORE_LOCAL_X0, REG_SP 605e26ef8fSAlvin Chang store_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 615e26ef8fSAlvin Chang 625e26ef8fSAlvin Chang csrr a0, CSR_XCAUSE 635e26ef8fSAlvin Chang /* MSB of cause differentiates between interrupts and exceptions */ 645e26ef8fSAlvin Chang bge a0, zero, exception_from_kernel 655e26ef8fSAlvin Chang 665e26ef8fSAlvin Changinterrupt_from_kernel: 675e26ef8fSAlvin Chang /* Get thread context as sp */ 685e26ef8fSAlvin Chang get_thread_ctx sp, a0 695e26ef8fSAlvin Chang 705e26ef8fSAlvin Chang /* Load and save kernel sp */ 715e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X0, REG_A0 725e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_SP, REG_A0 735e26ef8fSAlvin Chang 745e26ef8fSAlvin Chang /* Restore user a0, a1 which can be saved later */ 755e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 765e26ef8fSAlvin Chang 775e26ef8fSAlvin Chang /* Save all other GPRs */ 785e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_RA, REG_RA 795e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_GP, REG_GP 805e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_T0, REG_T0, REG_T2 815e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_S0, REG_S0, REG_S1 825e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_A0, REG_A0, REG_A7 835e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_S2, REG_S2, REG_S11 845e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_T3, REG_T3, REG_T6 855e26ef8fSAlvin Chang /* Save XIE */ 865e26ef8fSAlvin Chang csrr t0, CSR_XIE 875e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_IE, REG_T0 885e26ef8fSAlvin Chang /* Mask all interrupts */ 895e26ef8fSAlvin Chang csrw CSR_XIE, x0 905e26ef8fSAlvin Chang /* Save XSTATUS */ 915e26ef8fSAlvin Chang csrr t0, CSR_XSTATUS 925e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_STATUS, REG_T0 935e26ef8fSAlvin Chang /* Save XEPC */ 945e26ef8fSAlvin Chang csrr t0, CSR_XEPC 955e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_EPC, REG_T0 965e26ef8fSAlvin Chang 975e26ef8fSAlvin Chang /* 98ef00a923SAlvin Chang * a0 = struct thread_ctx_regs *regs 99ef00a923SAlvin Chang * a1 = cause 1005e26ef8fSAlvin Chang */ 101ef00a923SAlvin Chang mv a0, sp 102ef00a923SAlvin Chang csrr a1, CSR_XCAUSE 1035e26ef8fSAlvin Chang /* Load tmp_stack_va_end as current sp. */ 1045e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_TMP_STACK_VA_END, REG_SP 1055232a348SAlvin Chang 1065232a348SAlvin Chang /* 1075232a348SAlvin Chang * Get interrupt code from XCAUSE and build XIP. For example, if the 1085232a348SAlvin Chang * value of XCAUSE is 0x8000000000000005 (supervisor timer interrupt), 1095232a348SAlvin Chang * we build 0x20, which is (1 << 5) and indicates the sip.STIP signal. 1105232a348SAlvin Chang */ 1115232a348SAlvin Chang li a2, CSR_XCAUSE_INTR_FLAG 1125232a348SAlvin Chang sub a2, a1, a2 1135232a348SAlvin Chang li a3, 1 1145232a348SAlvin Chang sll a3, a3, a2 1155232a348SAlvin Chang /* 1165232a348SAlvin Chang * Compare built XIP with THREAD_EXCP_FOREIGN_INTR. If XIP is one of 1175232a348SAlvin Chang * THREAD_EXCP_FOREIGN_INTR, we call thread_foreign_interrupt_handler(). 1185232a348SAlvin Chang */ 1195232a348SAlvin Chang li a2, THREAD_EXCP_FOREIGN_INTR 1205232a348SAlvin Chang and a2, a3, a2 1215232a348SAlvin Chang beqz a2, native_interrupt_from_kernel 1225232a348SAlvin Chang 1235232a348SAlvin Changforeign_interrupt_from_kernel: 1245232a348SAlvin Chang /* 1255232a348SAlvin Chang * a0 = struct thread_ctx_regs *regs 1265232a348SAlvin Chang * Tail call thread_foreign_interrupt_handler(regs) since we will not 1275232a348SAlvin Chang * return to here. 1285232a348SAlvin Chang */ 1295232a348SAlvin Chang tail thread_foreign_interrupt_handler 1305232a348SAlvin Chang 1315232a348SAlvin Changnative_interrupt_from_kernel: 132ce1f8a72SAlvin Chang /* Update 32-bit core local flags */ 133ce1f8a72SAlvin Chang lw a2, THREAD_CORE_LOCAL_FLAGS(tp) 134ce1f8a72SAlvin Chang slli a2, a2, THREAD_CLF_SAVED_SHIFT 135ce1f8a72SAlvin Chang ori a2, a2, (THREAD_CLF_TMP | THREAD_CLF_IRQ) 136ce1f8a72SAlvin Chang sw a2, THREAD_CORE_LOCAL_FLAGS(tp) 137ce1f8a72SAlvin Chang 1385232a348SAlvin Chang /* 1395232a348SAlvin Chang * a0 = struct thread_ctx_regs *regs 1405232a348SAlvin Chang * a1 = cause 1415232a348SAlvin Chang * Call thread_native_interrupt_handler(regs, cause) 1425232a348SAlvin Chang */ 1435232a348SAlvin Chang call thread_native_interrupt_handler 1445e26ef8fSAlvin Chang 145ce1f8a72SAlvin Chang /* Update 32-bit core local flags */ 146ce1f8a72SAlvin Chang lw a2, THREAD_CORE_LOCAL_FLAGS(tp) 147ce1f8a72SAlvin Chang srli a2, a2, THREAD_CLF_SAVED_SHIFT 148ce1f8a72SAlvin Chang sw a2, THREAD_CORE_LOCAL_FLAGS(tp) 149ce1f8a72SAlvin Chang 1505e26ef8fSAlvin Chang /* Get thread context as sp */ 1515e26ef8fSAlvin Chang get_thread_ctx sp, t0 1525e26ef8fSAlvin Chang /* Restore XEPC */ 1535e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_EPC, REG_T0 1545e26ef8fSAlvin Chang csrw CSR_XEPC, t0 1555e26ef8fSAlvin Chang /* Restore XSTATUS */ 1565e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_STATUS, REG_T0 1575e26ef8fSAlvin Chang csrw CSR_XSTATUS, t0 1589f715794SAlvin Chang /* Restore XIE */ 1599f715794SAlvin Chang load_xregs sp, THREAD_CTX_REG_IE, REG_T0 1609f715794SAlvin Chang csrw CSR_XIE, t0 1614a2528f8SAlvin Chang /* We are going to XRET to kernel mode. Set XSCRATCH as 0 */ 1624a2528f8SAlvin Chang csrw CSR_XSCRATCH, 0 1635e26ef8fSAlvin Chang /* Restore all GPRs */ 1645e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_RA, REG_RA 1655e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_GP, REG_GP 1665e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_T0, REG_T0, REG_T2 1675e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_S0, REG_S0, REG_S1 1685e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_A0, REG_A0, REG_A7 1695e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_S2, REG_S2, REG_S11 1705e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_T3, REG_T3, REG_T6 1715e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_SP, REG_SP 1725e26ef8fSAlvin Chang XRET 1735e26ef8fSAlvin Chang 1745e26ef8fSAlvin Changexception_from_kernel: 1755e26ef8fSAlvin Chang /* 1765e26ef8fSAlvin Chang * Update core local flags. 1775e26ef8fSAlvin Chang * flags = (flags << THREAD_CLF_SAVED_SHIFT) | THREAD_CLF_ABORT; 1785e26ef8fSAlvin Chang */ 1795e26ef8fSAlvin Chang lw a0, THREAD_CORE_LOCAL_FLAGS(tp) 1805e26ef8fSAlvin Chang slli a0, a0, THREAD_CLF_SAVED_SHIFT 1815e26ef8fSAlvin Chang ori a0, a0, THREAD_CLF_ABORT 1825e26ef8fSAlvin Chang li a1, (THREAD_CLF_ABORT << THREAD_CLF_SAVED_SHIFT) 1835e26ef8fSAlvin Chang and a1, a0, a1 1845e26ef8fSAlvin Chang bnez a1, sel_tmp_sp 1855e26ef8fSAlvin Chang 1865e26ef8fSAlvin Chang /* Select abort stack */ 1875e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_ABT_STACK_VA_END, REG_A1 1885e26ef8fSAlvin Chang j set_sp 1895e26ef8fSAlvin Chang 1905e26ef8fSAlvin Changsel_tmp_sp: 1915e26ef8fSAlvin Chang /* We have an abort while using the abort stack, select tmp stack */ 1925e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_TMP_STACK_VA_END, REG_A1 1935e26ef8fSAlvin Chang ori a0, a0, THREAD_CLF_TMP /* flags |= THREAD_CLF_TMP; */ 1945e26ef8fSAlvin Chang 1955e26ef8fSAlvin Changset_sp: 1965e26ef8fSAlvin Chang mv sp, a1 1975e26ef8fSAlvin Chang sw a0, THREAD_CORE_LOCAL_FLAGS(tp) 1985e26ef8fSAlvin Chang 1995e26ef8fSAlvin Chang /* 2005e26ef8fSAlvin Chang * Save state on stack 2015e26ef8fSAlvin Chang */ 2025e26ef8fSAlvin Chang addi sp, sp, -THREAD_ABT_REGS_SIZE 2035e26ef8fSAlvin Chang 2045e26ef8fSAlvin Chang /* Save kernel sp */ 2055e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X0, REG_A0 2065e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_SP, REG_A0 2075e26ef8fSAlvin Chang 2085e26ef8fSAlvin Chang /* Restore kernel a0, a1 which can be saved later */ 2095e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 2105e26ef8fSAlvin Chang 2115e26ef8fSAlvin Chang /* Save all other GPRs */ 2125e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_RA, REG_RA 2135e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_GP, REG_GP 2145e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_TP, REG_TP 2155e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_T0, REG_T0, REG_T2 2165e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_S0, REG_S0, REG_S1 2175e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_A0, REG_A0, REG_A7 2185e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_S2, REG_S2, REG_S11 2195e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_T3, REG_T3, REG_T6 2205e26ef8fSAlvin Chang /* Save XIE */ 2215e26ef8fSAlvin Chang csrr t0, CSR_XIE 2225e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_IE, REG_T0 2235e26ef8fSAlvin Chang /* Mask all interrupts */ 2245e26ef8fSAlvin Chang csrw CSR_XIE, x0 2255e26ef8fSAlvin Chang /* Save XSTATUS */ 2265e26ef8fSAlvin Chang csrr t0, CSR_XSTATUS 2275e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_STATUS, REG_T0 2285e26ef8fSAlvin Chang /* Save XEPC */ 2295e26ef8fSAlvin Chang csrr t0, CSR_XEPC 2305e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_EPC, REG_T0 2315e26ef8fSAlvin Chang /* Save XTVAL */ 2325e26ef8fSAlvin Chang csrr t0, CSR_XTVAL 2335e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_TVAL, REG_T0 2345e26ef8fSAlvin Chang /* Save XCAUSE */ 2355e26ef8fSAlvin Chang csrr a0, CSR_XCAUSE 2365e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_CAUSE, REG_A0 2375e26ef8fSAlvin Chang 2385e26ef8fSAlvin Chang /* 2395e26ef8fSAlvin Chang * a0 = cause 2405e26ef8fSAlvin Chang * a1 = sp (struct thread_abort_regs *regs) 2415e26ef8fSAlvin Chang * Call abort_handler(cause, regs) 2425e26ef8fSAlvin Chang */ 2435e26ef8fSAlvin Chang mv a1, sp 2445e26ef8fSAlvin Chang call abort_handler 2455e26ef8fSAlvin Chang 2465e26ef8fSAlvin Chang /* 2475e26ef8fSAlvin Chang * Restore state from stack 2485e26ef8fSAlvin Chang */ 2495e26ef8fSAlvin Chang 2505e26ef8fSAlvin Chang /* Restore XEPC */ 2515e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_EPC, REG_T0 2525e26ef8fSAlvin Chang csrw CSR_XEPC, t0 2535e26ef8fSAlvin Chang /* Restore XSTATUS */ 2545e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_STATUS, REG_T0 2555e26ef8fSAlvin Chang csrw CSR_XSTATUS, t0 2569f715794SAlvin Chang /* Restore XIE */ 2579f715794SAlvin Chang load_xregs sp, THREAD_ABT_REG_IE, REG_T0 2589f715794SAlvin Chang csrw CSR_XIE, t0 2594a2528f8SAlvin Chang /* We are going to XRET to kernel mode. Set XSCRATCH as 0 */ 2604a2528f8SAlvin Chang csrw CSR_XSCRATCH, 0 2615e26ef8fSAlvin Chang 2625e26ef8fSAlvin Chang /* Update core local flags */ 2635e26ef8fSAlvin Chang lw a0, THREAD_CORE_LOCAL_FLAGS(tp) 2645e26ef8fSAlvin Chang srli a0, a0, THREAD_CLF_SAVED_SHIFT 2655e26ef8fSAlvin Chang sw a0, THREAD_CORE_LOCAL_FLAGS(tp) 2665e26ef8fSAlvin Chang 2675e26ef8fSAlvin Chang /* Restore all GPRs */ 2685e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_RA, REG_RA 2695e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_GP, REG_GP 2705e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_TP, REG_TP 2715e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_T0, REG_T0, REG_T2 2725e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_S0, REG_S0, REG_S1 2735e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_A0, REG_A0, REG_A7 2745e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_S2, REG_S2, REG_S11 2755e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_T3, REG_T3, REG_T6 2765e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_SP, REG_SP 2779b1a3bbeSMarouene Boubakri XRET 2789b1a3bbeSMarouene BoubakriEND_FUNC trap_from_kernel 2799b1a3bbeSMarouene Boubakri 2809b1a3bbeSMarouene BoubakriLOCAL_FUNC trap_from_user, : 2815e26ef8fSAlvin Chang /* Save user sp, a0, a1 into temporary spaces of thread_core_local */ 2825e26ef8fSAlvin Chang store_xregs tp, THREAD_CORE_LOCAL_X0, REG_SP 2835e26ef8fSAlvin Chang store_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 2845e26ef8fSAlvin Chang 2855e26ef8fSAlvin Chang csrr a0, CSR_XCAUSE 2865e26ef8fSAlvin Chang /* MSB of cause differentiates between interrupts and exceptions */ 2875e26ef8fSAlvin Chang bge a0, zero, exception_from_user 2885e26ef8fSAlvin Chang 2895e26ef8fSAlvin Changinterrupt_from_user: 2905e26ef8fSAlvin Chang /* Get thread context as sp */ 2915e26ef8fSAlvin Chang get_thread_ctx sp, a0 2925e26ef8fSAlvin Chang 2935e26ef8fSAlvin Chang /* Save user sp */ 2945e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X0, REG_A0 2955e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_SP, REG_A0 2965e26ef8fSAlvin Chang 2975e26ef8fSAlvin Chang /* Restore user a0, a1 which can be saved later */ 2985e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 2995e26ef8fSAlvin Chang 3005e26ef8fSAlvin Chang /* Save user gp */ 3015e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_GP, REG_GP 3025e26ef8fSAlvin Chang 3035e26ef8fSAlvin Chang /* 3045e26ef8fSAlvin Chang * Set the scratch register to 0 such in case of a recursive 3055e26ef8fSAlvin Chang * exception thread_trap_vect() knows that it is emitted from kernel. 3065e26ef8fSAlvin Chang */ 3075e26ef8fSAlvin Chang csrrw gp, CSR_XSCRATCH, zero 3085e26ef8fSAlvin Chang /* Save user tp we previously swapped into CSR_XSCRATCH */ 3095e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_TP, REG_GP 3105e26ef8fSAlvin Chang /* Set kernel gp */ 3115e26ef8fSAlvin Chang.option push 3125e26ef8fSAlvin Chang.option norelax 3135e26ef8fSAlvin Chang la gp, __global_pointer$ 3145e26ef8fSAlvin Chang.option pop 3155e26ef8fSAlvin Chang /* Save all other GPRs */ 3165e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_RA, REG_RA 3175e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_T0, REG_T0, REG_T2 3185e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_S0, REG_S0, REG_S1 3195e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_A0, REG_A0, REG_A7 3205e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_S2, REG_S2, REG_S11 3215e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_T3, REG_T3, REG_T6 3225e26ef8fSAlvin Chang /* Save XIE */ 3235e26ef8fSAlvin Chang csrr t0, CSR_XIE 3245e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_IE, REG_T0 3255e26ef8fSAlvin Chang /* Mask all interrupts */ 3265e26ef8fSAlvin Chang csrw CSR_XIE, x0 3275e26ef8fSAlvin Chang /* Save XSTATUS */ 3285e26ef8fSAlvin Chang csrr t0, CSR_XSTATUS 3295e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_STATUS, REG_T0 3305e26ef8fSAlvin Chang /* Save XEPC */ 3315e26ef8fSAlvin Chang csrr t0, CSR_XEPC 3325e26ef8fSAlvin Chang store_xregs sp, THREAD_CTX_REG_EPC, REG_T0 3335e26ef8fSAlvin Chang 3345e26ef8fSAlvin Chang /* 335ef00a923SAlvin Chang * a0 = struct thread_ctx_regs *regs 336ef00a923SAlvin Chang * a1 = cause 3375e26ef8fSAlvin Chang */ 338ef00a923SAlvin Chang mv a0, sp 339ef00a923SAlvin Chang csrr a1, CSR_XCAUSE 3405e26ef8fSAlvin Chang /* Load tmp_stack_va_end as current sp. */ 3415e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_TMP_STACK_VA_END, REG_SP 3425232a348SAlvin Chang 3435232a348SAlvin Chang /* 3445232a348SAlvin Chang * Get interrupt code from XCAUSE and build XIP. For example, if the 3455232a348SAlvin Chang * value of XCAUSE is 0x8000000000000005 (supervisor timer interrupt), 3465232a348SAlvin Chang * we build 0x20, which is (1 << 5) and indicates the sip.STIP signal. 3475232a348SAlvin Chang */ 3485232a348SAlvin Chang li a2, CSR_XCAUSE_INTR_FLAG 3495232a348SAlvin Chang sub a2, a1, a2 3505232a348SAlvin Chang li a3, 1 3515232a348SAlvin Chang sll a3, a3, a2 3525232a348SAlvin Chang /* 3535232a348SAlvin Chang * Compare built XIP with THREAD_EXCP_FOREIGN_INTR. If XIP is one of 3545232a348SAlvin Chang * THREAD_EXCP_FOREIGN_INTR, call thread_foreign_interrupt_handler(). 3555232a348SAlvin Chang */ 3565232a348SAlvin Chang li a2, THREAD_EXCP_FOREIGN_INTR 3575232a348SAlvin Chang and a2, a3, a2 3585232a348SAlvin Chang beqz a2, native_interrupt_from_user 3595232a348SAlvin Chang 3605232a348SAlvin Changforeign_interrupt_from_user: 3615232a348SAlvin Chang /* 3625232a348SAlvin Chang * a0 = struct thread_ctx_regs *regs 3635232a348SAlvin Chang * Tail call thread_foreign_interrupt_handler(regs) since we will not 3645232a348SAlvin Chang * return to here. 3655232a348SAlvin Chang */ 3665232a348SAlvin Chang tail thread_foreign_interrupt_handler 3675232a348SAlvin Chang 3685232a348SAlvin Changnative_interrupt_from_user: 369ce1f8a72SAlvin Chang /* Update 32-bit core local flags */ 370ce1f8a72SAlvin Chang lw a2, THREAD_CORE_LOCAL_FLAGS(tp) 371ce1f8a72SAlvin Chang slli a2, a2, THREAD_CLF_SAVED_SHIFT 372ce1f8a72SAlvin Chang ori a2, a2, (THREAD_CLF_TMP | THREAD_CLF_IRQ) 373ce1f8a72SAlvin Chang sw a2, THREAD_CORE_LOCAL_FLAGS(tp) 374ce1f8a72SAlvin Chang 3755232a348SAlvin Chang /* 3765232a348SAlvin Chang * a0 = struct thread_ctx_regs *regs 3775232a348SAlvin Chang * a1 = cause 3785232a348SAlvin Chang * Call thread_native_interrupt_handler(regs, cause) 3795232a348SAlvin Chang */ 3805232a348SAlvin Chang call thread_native_interrupt_handler 3815e26ef8fSAlvin Chang 382ce1f8a72SAlvin Chang /* Update 32-bit core local flags */ 383ce1f8a72SAlvin Chang lw a2, THREAD_CORE_LOCAL_FLAGS(tp) 384ce1f8a72SAlvin Chang srli a2, a2, THREAD_CLF_SAVED_SHIFT 385ce1f8a72SAlvin Chang sw a2, THREAD_CORE_LOCAL_FLAGS(tp) 386ce1f8a72SAlvin Chang 3875e26ef8fSAlvin Chang /* Get thread context as sp */ 3885e26ef8fSAlvin Chang get_thread_ctx sp, t0 3895e26ef8fSAlvin Chang /* Restore XEPC */ 3905e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_EPC, REG_T0 3915e26ef8fSAlvin Chang csrw CSR_XEPC, t0 3925e26ef8fSAlvin Chang /* Restore XSTATUS */ 3935e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_STATUS, REG_T0 3945e26ef8fSAlvin Chang csrw CSR_XSTATUS, t0 3959f715794SAlvin Chang /* Restore XIE */ 3969f715794SAlvin Chang load_xregs sp, THREAD_CTX_REG_IE, REG_T0 3979f715794SAlvin Chang csrw CSR_XIE, t0 3985e26ef8fSAlvin Chang /* Set scratch as thread_core_local */ 3995e26ef8fSAlvin Chang csrw CSR_XSCRATCH, tp 4005e26ef8fSAlvin Chang /* Restore all GPRs */ 4015e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_RA, REG_RA 4025e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_GP, REG_GP 4035e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_TP, REG_TP 4045e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_T0, REG_T0, REG_T2 4055e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_S0, REG_S0, REG_S1 4065e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_A0, REG_A0, REG_A7 4075e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_S2, REG_S2, REG_S11 4085e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_T3, REG_T3, REG_T6 4095e26ef8fSAlvin Chang load_xregs sp, THREAD_CTX_REG_SP, REG_SP 4105e26ef8fSAlvin Chang XRET 4115e26ef8fSAlvin Chang 4125e26ef8fSAlvin Changexception_from_user: 4135e26ef8fSAlvin Chang /* a0 is CSR_XCAUSE */ 4145e26ef8fSAlvin Chang li a1, CAUSE_USER_ECALL 4155e26ef8fSAlvin Chang bne a0, a1, abort_from_user 4165e26ef8fSAlvin Changecall_from_user: 4175e26ef8fSAlvin Chang /* Load and set kernel sp from thread context */ 4185e26ef8fSAlvin Chang get_thread_ctx a0, a1 4195e26ef8fSAlvin Chang load_xregs a0, THREAD_CTX_KERN_SP, REG_SP 4205e26ef8fSAlvin Chang 4215e26ef8fSAlvin Chang /* Now sp is kernel sp, create stack for struct thread_scall_regs */ 4225e26ef8fSAlvin Chang addi sp, sp, -THREAD_SCALL_REGS_SIZE 4235e26ef8fSAlvin Chang /* Save user sp */ 4245e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X0, REG_A0 4255e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_SP, REG_A0 4265e26ef8fSAlvin Chang 4275e26ef8fSAlvin Chang /* Restore user a0, a1 which can be saved later */ 4285e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 4295e26ef8fSAlvin Chang 4305e26ef8fSAlvin Chang /* Save user gp */ 4315e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_GP, REG_GP 4325e26ef8fSAlvin Chang /* 4335e26ef8fSAlvin Chang * Set the scratch register to 0 such in case of a recursive 4345e26ef8fSAlvin Chang * exception thread_trap_vect() knows that it is emitted from kernel. 4355e26ef8fSAlvin Chang */ 4365e26ef8fSAlvin Chang csrrw gp, CSR_XSCRATCH, zero 4375e26ef8fSAlvin Chang /* Save user tp we previously swapped into CSR_XSCRATCH */ 4385e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_TP, REG_GP 4395e26ef8fSAlvin Chang /* Set kernel gp */ 4405e26ef8fSAlvin Chang.option push 4415e26ef8fSAlvin Chang.option norelax 4425e26ef8fSAlvin Chang la gp, __global_pointer$ 4435e26ef8fSAlvin Chang.option pop 4445e26ef8fSAlvin Chang 4455e26ef8fSAlvin Chang /* Save other caller-saved registers */ 4465e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_RA, REG_RA 4475e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_T0, REG_T0, REG_T2 4485e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_A0, REG_A0, REG_A7 4495e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_T3, REG_T3, REG_T6 4505e26ef8fSAlvin Chang /* Save XIE */ 4515e26ef8fSAlvin Chang csrr a0, CSR_XIE 4525e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_IE, REG_A0 4535e26ef8fSAlvin Chang /* Mask all interrupts */ 4545e26ef8fSAlvin Chang csrw CSR_XIE, zero 4555e26ef8fSAlvin Chang /* Save XSTATUS */ 4565e26ef8fSAlvin Chang csrr a0, CSR_XSTATUS 4575e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_STATUS, REG_A0 4585e26ef8fSAlvin Chang /* Save XEPC */ 4595e26ef8fSAlvin Chang csrr a0, CSR_XEPC 4605e26ef8fSAlvin Chang store_xregs sp, THREAD_SCALL_REG_EPC, REG_A0 4615e26ef8fSAlvin Chang 4625e26ef8fSAlvin Chang /* 4635e26ef8fSAlvin Chang * a0 = struct thread_scall_regs *regs 4645e26ef8fSAlvin Chang * Call thread_scall_handler(regs) 4655e26ef8fSAlvin Chang */ 4665e26ef8fSAlvin Chang mv a0, sp 4675e26ef8fSAlvin Chang call thread_scall_handler 4685e26ef8fSAlvin Chang 4695e26ef8fSAlvin Chang /* 4705e26ef8fSAlvin Chang * Save kernel sp we'll had at the beginning of this function. 4715e26ef8fSAlvin Chang * This is when this TA has called another TA because 4725e26ef8fSAlvin Chang * __thread_enter_user_mode() also saves the stack pointer in this 4735e26ef8fSAlvin Chang * field. 4745e26ef8fSAlvin Chang */ 4755e26ef8fSAlvin Chang get_thread_ctx a0, a1 4765e26ef8fSAlvin Chang addi t0, sp, THREAD_SCALL_REGS_SIZE 4775e26ef8fSAlvin Chang store_xregs a0, THREAD_CTX_KERN_SP, REG_T0 4785e26ef8fSAlvin Chang 4795c718542SAlvin Chang /* Restore XEPC */ 4805e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_EPC, REG_T0 4815e26ef8fSAlvin Chang csrw CSR_XEPC, t0 4825e26ef8fSAlvin Chang /* Restore XSTATUS */ 4835e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_STATUS, REG_T0 4845e26ef8fSAlvin Chang csrw CSR_XSTATUS, t0 4859f715794SAlvin Chang /* Restore XIE */ 4869f715794SAlvin Chang load_xregs sp, THREAD_SCALL_REG_IE, REG_T0 4879f715794SAlvin Chang csrw CSR_XIE, t0 4885c718542SAlvin Chang /* Check previous privilege mode by status.SPP */ 4899f715794SAlvin Chang csrr t0, CSR_XSTATUS 4905c718542SAlvin Chang b_if_prev_priv_is_u t0, 1f 4915c718542SAlvin Chang /* 4925c718542SAlvin Chang * We are going to XRET to kernel mode. 4935c718542SAlvin Chang * XSCRATCH is already zero to indicate that we are in kernel mode. 4945c718542SAlvin Chang * We must keep kernel gp & tp, so skip restoring user gp & tp. 4955c718542SAlvin Chang */ 4965c718542SAlvin Chang j 2f 4975c718542SAlvin Chang1: 4985c718542SAlvin Chang /* 4995c718542SAlvin Chang * We are going to XRET to user mode. 5005c718542SAlvin Chang * XSCRATCH must be tp(thread_core_local) to be used in next trap. 5015c718542SAlvin Chang * We also need to restore user gp & tp 5025c718542SAlvin Chang */ 5035e26ef8fSAlvin Chang csrw CSR_XSCRATCH, tp 5045e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_GP, REG_GP 5055e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_TP, REG_TP 5065c718542SAlvin Chang2: 5075c718542SAlvin Chang /* Restore remaining caller-saved registers */ 5085c718542SAlvin Chang load_xregs sp, THREAD_SCALL_REG_RA, REG_RA 5095e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_T0, REG_T0, REG_T2 5105e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_A0, REG_A0, REG_A7 5115e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_T3, REG_T3, REG_T6 5125e26ef8fSAlvin Chang load_xregs sp, THREAD_SCALL_REG_SP, REG_SP 5135e26ef8fSAlvin Chang XRET 5145e26ef8fSAlvin Chang 5155e26ef8fSAlvin Changabort_from_user: 5165e26ef8fSAlvin Chang /* 5175e26ef8fSAlvin Chang * Update core local flags 5185e26ef8fSAlvin Chang */ 5195e26ef8fSAlvin Chang lw a0, THREAD_CORE_LOCAL_FLAGS(tp) 5205e26ef8fSAlvin Chang slli a0, a0, THREAD_CLF_SAVED_SHIFT 5215e26ef8fSAlvin Chang ori a0, a0, THREAD_CLF_ABORT 5225e26ef8fSAlvin Chang sw a0, THREAD_CORE_LOCAL_FLAGS(tp) 5235e26ef8fSAlvin Chang 5245e26ef8fSAlvin Chang /* 5255e26ef8fSAlvin Chang * Save state on stack 5265e26ef8fSAlvin Chang */ 5275e26ef8fSAlvin Chang 5285e26ef8fSAlvin Chang /* Load abt_stack_va_end and set it as sp */ 5295e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_ABT_STACK_VA_END, REG_SP 5305e26ef8fSAlvin Chang 5315e26ef8fSAlvin Chang /* Now sp is abort sp, create stack for struct thread_abort_regs */ 5325e26ef8fSAlvin Chang addi sp, sp, -THREAD_ABT_REGS_SIZE 5335e26ef8fSAlvin Chang 5345e26ef8fSAlvin Chang /* Save user sp */ 5355e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X0, REG_A0 5365e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_SP, REG_A0 5375e26ef8fSAlvin Chang 5385e26ef8fSAlvin Chang /* Restore user a0, a1 which can be saved later */ 5395e26ef8fSAlvin Chang load_xregs tp, THREAD_CORE_LOCAL_X1, REG_A0, REG_A1 5405e26ef8fSAlvin Chang 5415e26ef8fSAlvin Chang /* Save user gp */ 5425e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_GP, REG_GP 5435e26ef8fSAlvin Chang 5445e26ef8fSAlvin Chang /* 5455e26ef8fSAlvin Chang * Set the scratch register to 0 such in case of a recursive 5465e26ef8fSAlvin Chang * exception thread_trap_vect() knows that it is emitted from kernel. 5475e26ef8fSAlvin Chang */ 5485e26ef8fSAlvin Chang csrrw gp, CSR_XSCRATCH, zero 5495e26ef8fSAlvin Chang /* Save user tp we previously swapped into CSR_XSCRATCH */ 5505e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_TP, REG_GP 5515e26ef8fSAlvin Chang /* Set kernel gp */ 5525e26ef8fSAlvin Chang.option push 5535e26ef8fSAlvin Chang.option norelax 5545e26ef8fSAlvin Chang la gp, __global_pointer$ 5555e26ef8fSAlvin Chang.option pop 5565e26ef8fSAlvin Chang /* Save all other GPRs */ 5575e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_RA, REG_RA 5585e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_T0, REG_T0, REG_T2 5595e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_S0, REG_S0, REG_S1 5605e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_A0, REG_A0, REG_A7 5615e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_S2, REG_S2, REG_S11 5625e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_T3, REG_T3, REG_T6 5635e26ef8fSAlvin Chang /* Save XIE */ 5645e26ef8fSAlvin Chang csrr t0, CSR_XIE 5655e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_IE, REG_T0 5665e26ef8fSAlvin Chang /* Mask all interrupts */ 5675e26ef8fSAlvin Chang csrw CSR_XIE, x0 5685e26ef8fSAlvin Chang /* Save XSTATUS */ 5695e26ef8fSAlvin Chang csrr t0, CSR_XSTATUS 5705e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_STATUS, REG_T0 5715e26ef8fSAlvin Chang /* Save XEPC */ 5725e26ef8fSAlvin Chang csrr t0, CSR_XEPC 5735e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_EPC, REG_T0 5745e26ef8fSAlvin Chang /* Save XTVAL */ 5755e26ef8fSAlvin Chang csrr t0, CSR_XTVAL 5765e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_TVAL, REG_T0 5775e26ef8fSAlvin Chang /* Save XCAUSE */ 5785e26ef8fSAlvin Chang csrr a0, CSR_XCAUSE 5795e26ef8fSAlvin Chang store_xregs sp, THREAD_ABT_REG_CAUSE, REG_A0 5805e26ef8fSAlvin Chang 5815e26ef8fSAlvin Chang /* 5825e26ef8fSAlvin Chang * a0 = cause 5835e26ef8fSAlvin Chang * a1 = sp (struct thread_abort_regs *regs) 5845e26ef8fSAlvin Chang * Call abort_handler(cause, regs) 5855e26ef8fSAlvin Chang */ 5865e26ef8fSAlvin Chang mv a1, sp 5875e26ef8fSAlvin Chang call abort_handler 5885e26ef8fSAlvin Chang 5895e26ef8fSAlvin Chang /* 5905e26ef8fSAlvin Chang * Restore state from stack 5915e26ef8fSAlvin Chang */ 5925e26ef8fSAlvin Chang 5935e26ef8fSAlvin Chang /* Restore XEPC */ 5945e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_EPC, REG_T0 5955e26ef8fSAlvin Chang csrw CSR_XEPC, t0 5965e26ef8fSAlvin Chang /* Restore XSTATUS */ 5975e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_STATUS, REG_T0 5985e26ef8fSAlvin Chang csrw CSR_XSTATUS, t0 5999f715794SAlvin Chang /* Restore XIE */ 6009f715794SAlvin Chang load_xregs sp, THREAD_ABT_REG_IE, REG_T0 6019f715794SAlvin Chang csrw CSR_XIE, t0 6025e26ef8fSAlvin Chang 6035e26ef8fSAlvin Chang /* Update core local flags */ 6045e26ef8fSAlvin Chang lw a0, THREAD_CORE_LOCAL_FLAGS(tp) 6055e26ef8fSAlvin Chang srli a0, a0, THREAD_CLF_SAVED_SHIFT 6065e26ef8fSAlvin Chang sw a0, THREAD_CORE_LOCAL_FLAGS(tp) 6075e26ef8fSAlvin Chang 6085c718542SAlvin Chang /* Check previous privilege mode by status.SPP */ 6099f715794SAlvin Chang csrr t0, CSR_XSTATUS 6105c718542SAlvin Chang b_if_prev_priv_is_u t0, 1f 6115c718542SAlvin Chang /* 6125c718542SAlvin Chang * We are going to XRET to kernel mode. 6135c718542SAlvin Chang * XSCRATCH is already zero to indicate that we are in kernel mode. 6145c718542SAlvin Chang * We must keep kernel gp & tp, so skip restoring user gp & tp. 6155c718542SAlvin Chang */ 6165c718542SAlvin Chang j 2f 6175c718542SAlvin Chang1: 6185c718542SAlvin Chang /* 6195c718542SAlvin Chang * We are going to XRET to user mode. 6205c718542SAlvin Chang * XSCRATCH must be tp(thread_core_local) to be used in next trap. 6215c718542SAlvin Chang * We also need to restore user gp & tp 6225c718542SAlvin Chang */ 6235c718542SAlvin Chang csrw CSR_XSCRATCH, tp 6245e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_GP, REG_GP 6255e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_TP, REG_TP 6265c718542SAlvin Chang2: 6275c718542SAlvin Chang /* Restore remaining GPRs */ 6285c718542SAlvin Chang load_xregs sp, THREAD_ABT_REG_RA, REG_RA 6295e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_T0, REG_T0, REG_T2 6305e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_S0, REG_S0, REG_S1 6315e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_A0, REG_A0, REG_A7 6325e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_S2, REG_S2, REG_S11 6335e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_T3, REG_T3, REG_T6 6345e26ef8fSAlvin Chang load_xregs sp, THREAD_ABT_REG_SP, REG_SP 6359b1a3bbeSMarouene Boubakri XRET 6369b1a3bbeSMarouene BoubakriEND_FUNC trap_from_user 6379b1a3bbeSMarouene Boubakri 6389b1a3bbeSMarouene Boubakri/* 6399b1a3bbeSMarouene Boubakri * void thread_unwind_user_mode(uint32_t ret, uint32_t exit_status0, 6409b1a3bbeSMarouene Boubakri * uint32_t exit_status1); 6419b1a3bbeSMarouene Boubakri * See description in thread.h 6429b1a3bbeSMarouene Boubakri */ 6439b1a3bbeSMarouene BoubakriFUNC thread_unwind_user_mode , : 6449b1a3bbeSMarouene Boubakri /* Store the exit status */ 6459b1a3bbeSMarouene Boubakri load_xregs sp, THREAD_USER_MODE_REC_CTX_REGS_PTR, REG_A3, REG_A5 6469b1a3bbeSMarouene Boubakri sw a1, (a4) 6479b1a3bbeSMarouene Boubakri sw a2, (a5) 6489df67cd4SAlvin Chang /* Save user callee-saved regs */ 6499b1a3bbeSMarouene Boubakri store_xregs a3, THREAD_CTX_REG_S0, REG_S0, REG_S1 6509b1a3bbeSMarouene Boubakri store_xregs a3, THREAD_CTX_REG_S2, REG_S2, REG_S11 6519df67cd4SAlvin Chang /* Restore kernel ra(thread_enter_user_mode()) & callee-saved regs */ 6529df67cd4SAlvin Chang load_xregs sp, THREAD_USER_MODE_REC_RA, REG_RA 6539df67cd4SAlvin Chang load_xregs sp, THREAD_USER_MODE_REC_S0, REG_S0, REG_S1 6549df67cd4SAlvin Chang load_xregs sp, THREAD_USER_MODE_REC_S2, REG_S2, REG_S11 6559b1a3bbeSMarouene Boubakri add sp, sp, THREAD_USER_MODE_REC_SIZE 6569b1a3bbeSMarouene Boubakri /* Return from the call of thread_enter_user_mode() */ 6579b1a3bbeSMarouene Boubakri ret 6589b1a3bbeSMarouene BoubakriEND_FUNC thread_unwind_user_mode 6599b1a3bbeSMarouene Boubakri 6609b1a3bbeSMarouene Boubakri/* 6619b1a3bbeSMarouene Boubakri * uint32_t __thread_enter_user_mode(struct thread_ctx_regs *regs, 6629b1a3bbeSMarouene Boubakri * uint32_t *exit_status0, 6639b1a3bbeSMarouene Boubakri * uint32_t *exit_status1); 6649b1a3bbeSMarouene Boubakri */ 6659b1a3bbeSMarouene BoubakriFUNC __thread_enter_user_mode , : 6669b1a3bbeSMarouene Boubakri /* 6679b1a3bbeSMarouene Boubakri * Create and fill in the struct thread_user_mode_rec 6689b1a3bbeSMarouene Boubakri */ 6699b1a3bbeSMarouene Boubakri addi sp, sp, -THREAD_USER_MODE_REC_SIZE 6709b1a3bbeSMarouene Boubakri store_xregs sp, THREAD_USER_MODE_REC_CTX_REGS_PTR, REG_A0, REG_A2 6719df67cd4SAlvin Chang store_xregs sp, THREAD_USER_MODE_REC_RA, REG_RA 6729df67cd4SAlvin Chang store_xregs sp, THREAD_USER_MODE_REC_S0, REG_S0, REG_S1 6739df67cd4SAlvin Chang store_xregs sp, THREAD_USER_MODE_REC_S2, REG_S2, REG_S11 6749b1a3bbeSMarouene Boubakri 6759b1a3bbeSMarouene Boubakri /* 6769b1a3bbeSMarouene Boubakri * Save the kernel stack pointer in the thread context 6779b1a3bbeSMarouene Boubakri */ 6789b1a3bbeSMarouene Boubakri 6799b1a3bbeSMarouene Boubakri /* Get pointer to current thread context */ 6809b1a3bbeSMarouene Boubakri get_thread_ctx s0, s1 6819b1a3bbeSMarouene Boubakri 6829b1a3bbeSMarouene Boubakri /* 6839b1a3bbeSMarouene Boubakri * Save kernel stack pointer to ensure that 6845c718542SAlvin Chang * exception_from_user() uses correct stack pointer. 6859b1a3bbeSMarouene Boubakri */ 6869b1a3bbeSMarouene Boubakri 6879b1a3bbeSMarouene Boubakri store_xregs s0, THREAD_CTX_KERN_SP, REG_SP 6889b1a3bbeSMarouene Boubakri /* 689b5bb30b3SAlvin Chang * Save thread_core_local in xSCRATCH to ensure that thread_trap_vect() 690b5bb30b3SAlvin Chang * uses correct core local structure. 6919b1a3bbeSMarouene Boubakri */ 692b5bb30b3SAlvin Chang csrw CSR_XSCRATCH, tp 693b5bb30b3SAlvin Chang 6948a2c36cdSAlvin Chang /* Move struct thread_ctx_regs *regs to sp to reduce code size */ 6958a2c36cdSAlvin Chang mv sp, a0 6968a2c36cdSAlvin Chang 697dfa05b24SAlvin Chang /* Set exception return PC */ 6988a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_EPC, REG_S0 699dfa05b24SAlvin Chang csrw CSR_XEPC, s0 7009b1a3bbeSMarouene Boubakri /* Set user status */ 7018a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_STATUS, REG_S0 7029b1a3bbeSMarouene Boubakri csrw CSR_XSTATUS, s0 7039f715794SAlvin Chang /* Set user ie */ 7049f715794SAlvin Chang load_xregs sp, THREAD_CTX_REG_IE, REG_S0 7059f715794SAlvin Chang csrw CSR_XIE, s0 7069b1a3bbeSMarouene Boubakri /* Load the rest of the general purpose registers */ 7078a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_RA, REG_RA 7088a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_GP, REG_GP 7098a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_TP, REG_TP 7108a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_T0, REG_T0, REG_T2 7118a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_S0, REG_S0, REG_S1 7128a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_A0, REG_A0, REG_A7 7138a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_S2, REG_S2, REG_S11 7148a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_T3, REG_T3, REG_T6 7158a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_SP, REG_SP /* sp must be last one */ 7169b1a3bbeSMarouene Boubakri 7179b1a3bbeSMarouene Boubakri /* Jump into user mode */ 7189b1a3bbeSMarouene Boubakri XRET 7199b1a3bbeSMarouene BoubakriEND_FUNC __thread_enter_user_mode 7209b1a3bbeSMarouene Boubakri 7219b1a3bbeSMarouene Boubakri/* void thread_resume(struct thread_ctx_regs *regs) */ 7229b1a3bbeSMarouene BoubakriFUNC thread_resume , : 7238a2c36cdSAlvin Chang /* Move struct thread_ctx_regs *regs to sp to reduce code size */ 7248a2c36cdSAlvin Chang mv sp, a0 7258a2c36cdSAlvin Chang 72609653bcaSAlvin Chang /* Restore epc */ 7278a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_EPC, REG_T0 72809653bcaSAlvin Chang csrw CSR_XEPC, t0 72909653bcaSAlvin Chang /* Restore status */ 7308a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_STATUS, REG_T0 73109653bcaSAlvin Chang csrw CSR_XSTATUS, t0 7329f715794SAlvin Chang /* Restore ie */ 7339f715794SAlvin Chang load_xregs sp, THREAD_CTX_REG_IE, REG_T0 7349f715794SAlvin Chang csrw CSR_XIE, t0 73509653bcaSAlvin Chang 73609653bcaSAlvin Chang /* Check if previous privilege mode by status.SPP */ 7379f715794SAlvin Chang csrr t0, CSR_XSTATUS 73809653bcaSAlvin Chang b_if_prev_priv_is_u t0, 1f 73909653bcaSAlvin Chang /* Set scratch as zero to indicate that we are in kernel mode */ 74009653bcaSAlvin Chang csrw CSR_XSCRATCH, zero 74109653bcaSAlvin Chang j 2f 74209653bcaSAlvin Chang1: 74309653bcaSAlvin Chang /* Resume to U-mode, set scratch as tp to be used in the trap handler */ 74409653bcaSAlvin Chang csrw CSR_XSCRATCH, tp 74509653bcaSAlvin Chang2: 74609653bcaSAlvin Chang /* Restore all general-purpose registers */ 7478a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_RA, REG_RA 7488a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_GP, REG_GP 7498a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_TP, REG_TP 7508a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_T0, REG_T0, REG_T2 7518a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_S0, REG_S0, REG_S1 7528a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_A0, REG_A0, REG_A7 7538a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_S2, REG_S2, REG_S11 7548a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_T3, REG_T3, REG_T6 7558a2c36cdSAlvin Chang load_xregs sp, THREAD_CTX_REG_SP, REG_SP /* sp must be last one */ 75609653bcaSAlvin Chang 75709653bcaSAlvin Chang XRET 7589b1a3bbeSMarouene BoubakriEND_FUNC thread_resume 7598d5bae1cSAlvin Chang 7608d5bae1cSAlvin Chang/* void thread_foreign_interrupt_handler(struct thread_ctx_regs *regs) */ 7618d5bae1cSAlvin ChangFUNC thread_foreign_interrupt_handler , : 7628d5bae1cSAlvin Chang /* Update 32-bit core local flags */ 7638d5bae1cSAlvin Chang lw s1, THREAD_CORE_LOCAL_FLAGS(tp) 7648d5bae1cSAlvin Chang slli s1, s1, THREAD_CLF_SAVED_SHIFT 7658d5bae1cSAlvin Chang ori s1, s1, (THREAD_CLF_TMP | THREAD_CLF_FIQ) 7668d5bae1cSAlvin Chang sw s1, THREAD_CORE_LOCAL_FLAGS(tp) 7678d5bae1cSAlvin Chang 7688d5bae1cSAlvin Chang /* 7698d5bae1cSAlvin Chang * Mark current thread as suspended. 7708d5bae1cSAlvin Chang * a0 = THREAD_FLAGS_EXIT_ON_FOREIGN_INTR 7718d5bae1cSAlvin Chang * a1 = status 7728d5bae1cSAlvin Chang * a2 = epc 7738d5bae1cSAlvin Chang * thread_state_suspend(flags, status, pc) 7748d5bae1cSAlvin Chang */ 7758d5bae1cSAlvin Chang LDR a1, THREAD_CTX_REG_STATUS(a0) 7768d5bae1cSAlvin Chang LDR a2, THREAD_CTX_REG_EPC(a0) 7778d5bae1cSAlvin Chang li a0, THREAD_FLAGS_EXIT_ON_FOREIGN_INTR 7788d5bae1cSAlvin Chang call thread_state_suspend 7798d5bae1cSAlvin Chang /* Now return value a0 contains suspended thread ID. */ 7808d5bae1cSAlvin Chang 7818d5bae1cSAlvin Chang /* Update core local flags */ 7828d5bae1cSAlvin Chang lw s1, THREAD_CORE_LOCAL_FLAGS(tp) 7838d5bae1cSAlvin Chang srli s1, s1, THREAD_CLF_SAVED_SHIFT 7848d5bae1cSAlvin Chang ori s1, s1, THREAD_CLF_TMP 7858d5bae1cSAlvin Chang sw s1, THREAD_CORE_LOCAL_FLAGS(tp) 7868d5bae1cSAlvin Chang 7878d5bae1cSAlvin Chang /* Passing thread index in a0, and return to untrusted domain. */ 7888d5bae1cSAlvin Chang mv a4, a0 7898d5bae1cSAlvin Chang li a0, TEEABI_OPTEED_RETURN_CALL_DONE 7908d5bae1cSAlvin Chang li a1, OPTEE_ABI_RETURN_RPC_FOREIGN_INTR 7918d5bae1cSAlvin Chang li a2, 0 7928d5bae1cSAlvin Chang li a3, 0 7938d5bae1cSAlvin Chang li a5, 0 7948d5bae1cSAlvin Chang j thread_return_to_udomain 7958d5bae1cSAlvin ChangEND_FUNC thread_foreign_interrupt_handler 796