1/* 2 * Copyright (c) 2018 Synopsys. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7#include <offsets_short.h> 8#include <zephyr/toolchain.h> 9#include <zephyr/linker/sections.h> 10#include <zephyr/kernel_structs.h> 11#include <zephyr/arch/cpu.h> 12#include <zephyr/syscall.h> 13#include <swap_macros.h> 14#include <v2/irq.h> 15 16.macro clear_scratch_regs 17 mov_s r1, 0 18 mov_s r2, 0 19 mov_s r3, 0 20 mov_s r4, 0 21 mov_s r5, 0 22 mov_s r6, 0 23 mov_s r7, 0 24 mov_s r8, 0 25 mov_s r9, 0 26 mov_s r10, 0 27 mov_s r11, 0 28 mov_s r12, 0 29.endm 30 31.macro clear_callee_regs 32 mov_s r25, 0 33 mov_s r24, 0 34 mov_s r23, 0 35 mov_s r22, 0 36 mov_s r21, 0 37 mov_s r20, 0 38 mov_s r19, 0 39 mov_s r18, 0 40 mov_s r17, 0 41 mov_s r16, 0 42 43 mov_s r15, 0 44 mov_s r14, 0 45 mov_s r13, 0 46.endm 47 48GTEXT(z_arc_userspace_enter) 49GTEXT(_arc_do_syscall) 50GTEXT(z_user_thread_entry_wrapper) 51GTEXT(arch_user_string_nlen) 52GTEXT(z_arc_user_string_nlen_fault_start) 53GTEXT(z_arc_user_string_nlen_fault_end) 54GTEXT(z_arc_user_string_nlen_fixup) 55 56/** 57 * @brief Wrapper for z_thread_entry in the case of user thread 58 * 59 * The init parameters are in privileged stack 60 */ 61SECTION_FUNC(TEXT, z_user_thread_entry_wrapper) 62 seti _ARC_V2_INIT_IRQ_LOCK_KEY 63 pop_s r3 64 pop_s r2 65 pop_s r1 66 pop_s r0 67/* the start of user sp is in r5 */ 68 pop r5 69/* start of privilege stack in blink */ 70 mov_s blink, sp 71 72 st.aw r0, [r5, -4] 73 st.aw r1, [r5, -4] 74 st.aw r2, [r5, -4] 75 st.aw r3, [r5, -4] 76 77/* 78 * when CONFIG_INIT_STACKS is enable, stack will be initialized 79 * in z_new_thread_init. 80 */ 81 j _arc_go_to_user_space 82 83/** 84 * 85 * User space entry function 86 * 87 * This function is the entry point to user mode from privileged execution. 88 * The conversion is one way, and threads which transition to user mode do 89 * not transition back later, unless they are doing system calls. 90 * 91 */ 92SECTION_FUNC(TEXT, z_arc_userspace_enter) 93 /* 94 * In ARCv2, the U bit can only be set through exception return 95 */ 96 /* disable stack checking as the stack should be initialized */ 97 _disable_stack_checking blink 98 99 /* the end of user stack in r5 */ 100 add r5, r4, r5 101 /* get start of privilege stack, r6 points to current thread */ 102 ld blink, [r6, _thread_offset_to_priv_stack_start] 103 add blink, blink, CONFIG_PRIVILEGED_STACK_SIZE 104 105 mov_s sp, r5 106 107 push_s r0 108 push_s r1 109 push_s r2 110 push_s r3 111 112 mov r5, sp /* skip r0, r1, r2, r3 */ 113 114/* to avoid the leakage of kernel info, the thread stack needs to be 115 * re-initialized 116 */ 117#ifdef CONFIG_INIT_STACKS 118 mov_s r0, 0xaaaaaaaa 119#else 120 mov_s r0, 0x0 121#endif 122_clear_user_stack: 123 st.ab r0, [r4, 4] 124 cmp r4, r5 125 jlt _clear_user_stack 126 127/* reload the stack checking regs as the original kernel stack 128 * becomes user stack 129 */ 130#ifdef CONFIG_ARC_STACK_CHECKING 131/* current thread in r6, SMP case is also considered */ 132 mov r2, r6 133 134 _load_stack_check_regs 135 136 _enable_stack_checking r0 137#endif 138 139/* the following codes are used to switch from kernel mode 140 * to user mode by fake exception, because U bit can only be set 141 * by exception 142 */ 143_arc_go_to_user_space: 144 lr r0, [_ARC_V2_STATUS32] 145 bset r0, r0, _ARC_V2_STATUS32_U_BIT 146 147 mov_s r1, z_thread_entry_wrapper1 148 149 sr r0, [_ARC_V2_ERSTATUS] 150 sr r1, [_ARC_V2_ERET] 151 152 /* fake exception return */ 153 lr r0, [_ARC_V2_STATUS32] 154 bset r0, r0, _ARC_V2_STATUS32_AE_BIT 155 kflag r0 156 157/* when exception returns from kernel to user, sp and _ARC_V2_USER_SP 158 * /_ARC_V2_SECU_SP will be switched 159 */ 160#if defined(CONFIG_ARC_HAS_SECURE) && defined(CONFIG_ARC_SECURE_FIRMWARE) 161 lr r0, [_ARC_V2_SEC_STAT] 162 /* the mode returns from exception return is secure mode */ 163 bset r0, r0, 31 164 sr r0, [_ARC_V2_ERSEC_STAT] 165 sr r5, [_ARC_V2_SEC_U_SP] 166#else 167 sr r5, [_ARC_V2_USER_SP] 168#endif 169 mov_s sp, blink 170 171 mov_s r0, 0 172 173 clear_callee_regs 174 175 clear_scratch_regs 176 177 mov fp, 0 178 mov r29, 0 179 mov r30, 0 180 mov blink, 0 181 182 rtie 183 184/** 185 * 186 * Userspace system call function 187 * 188 * This function is used to do system calls from unprivileged code. This 189 * function is responsible for the following: 190 * 1) Dispatching the system call 191 * 2) Restoring stack and calling back to the caller of the system call 192 * 193 */ 194SECTION_FUNC(TEXT, _arc_do_syscall) 195 /* 196 * r0-r5: arg1-arg6, r6 is call id which is already checked in 197 * trap_s handler, r7 is the system call stack frame pointer 198 * need to recover r0, r1, r2 because they will be modified in 199 * _create_irq_stack_frame. If a specific syscall frame (different 200 * with irq stack frame) is defined, the cover of r0, r1, r2 can be 201 * optimized. 202 */ 203 ld_s r0, [sp, ___isf_t_r0_OFFSET] 204 ld_s r1, [sp, ___isf_t_r1_OFFSET] 205 ld_s r2, [sp, ___isf_t_r2_OFFSET] 206 207 mov r7, sp 208 209 mov_s blink, _k_syscall_table 210 ld.as r6, [blink, r6] 211 212 jl [r6] 213 214 /* save return value */ 215 st_s r0, [sp, ___isf_t_r0_OFFSET] 216 217 mov r29, 0 218 mov r30, 0 219 220 /* through fake exception return, go back to the caller */ 221 lr r0, [_ARC_V2_STATUS32] 222 bset r0, r0, _ARC_V2_STATUS32_AE_BIT 223 kflag r0 224 225 226#ifdef CONFIG_ARC_SECURE_FIRMWARE 227 ld_s r0, [sp, ___isf_t_sec_stat_OFFSET] 228 sr r0,[_ARC_V2_ERSEC_STAT] 229#endif 230 ld_s r0, [sp, ___isf_t_status32_OFFSET] 231 sr r0,[_ARC_V2_ERSTATUS] 232 233 ld_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */ 234 sr r0,[_ARC_V2_ERET] 235 236 _pop_irq_stack_frame 237 238 rtie 239 240/* 241 * size_t arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg) 242 */ 243SECTION_FUNC(TEXT, arch_user_string_nlen) 244 /* int err; */ 245 sub_s sp,sp,0x4 246 247 /* Initial error value (-1 failure), store at [sp,0] */ 248 mov_s r3, -1 249 st_s r3, [sp, 0] 250 251 /* Loop setup. 252 * r12 (position locator) = s - 1 253 * r0 (length counter return value)) = 0 254 * lp_count = maxsize + 1 255 * */ 256 sub r12, r0, 0x1 257 mov_s r0, 0 258 add_s r1, r1, 1 259 mov lp_count, r1 260 261strlen_loop: 262z_arc_user_string_nlen_fault_start: 263 /* is the byte at ++r12 a NULL? if so, we're done. Might fault! */ 264 ldb.aw r1, [r12, 1] 265 266z_arc_user_string_nlen_fault_end: 267 brne_s r1, 0, not_null 268 269strlen_done: 270 /* Success, set err to 0 */ 271 mov_s r1, 0 272 st_s r1, [sp, 0] 273 274z_arc_user_string_nlen_fixup: 275 /* *err_arg = err; Pop stack and return */ 276 ld_s r1, [sp, 0] 277 add_s sp, sp, 4 278 j_s.d [blink] 279 st_s r1, [r2, 0] 280 281not_null: 282 /* check if we've hit the maximum, if so we're done. */ 283 brne.d.nt lp_count, 0x1, inc_len 284 sub lp_count, lp_count, 0x1 285 b_s strlen_done 286 287inc_len: 288 /* increment length measurement, loop again */ 289 add_s r0, r0, 1 290 b_s strlen_loop 291