1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 * Copyright (c) 2016-2017, Linaro Limited 5 * Copyright (c) 2020-2021, Arm Limited 6 */ 7 8 #ifndef KERNEL_THREAD_H 9 #define KERNEL_THREAD_H 10 11 #ifndef __ASSEMBLER__ 12 #include <types_ext.h> 13 #include <compiler.h> 14 #include <mm/pgt_cache.h> 15 #endif 16 #include <util.h> 17 #include <kernel/thread_arch.h> 18 19 #define THREAD_FLAGS_COPY_ARGS_ON_RETURN BIT(0) 20 #define THREAD_FLAGS_FOREIGN_INTR_ENABLE BIT(1) 21 #define THREAD_FLAGS_EXIT_ON_FOREIGN_INTR BIT(2) 22 23 #define THREAD_ID_0 0 24 #define THREAD_ID_INVALID -1 25 26 #define THREAD_RPC_MAX_NUM_PARAMS U(4) 27 28 #ifndef __ASSEMBLER__ 29 30 struct thread_specific_data { 31 TAILQ_HEAD(, ts_session) sess_stack; 32 struct ts_ctx *ctx; 33 #ifdef CFG_CORE_FFA 34 uint32_t rpc_target_info; 35 #endif 36 uint32_t abort_type; 37 uint32_t abort_descr; 38 vaddr_t abort_va; 39 unsigned int abort_core; 40 struct thread_abort_regs abort_regs; 41 #ifdef CFG_CORE_DEBUG_CHECK_STACKS 42 bool stackcheck_recursion; 43 #endif 44 unsigned int syscall_recursion; 45 }; 46 47 void thread_init_canaries(void); 48 void thread_init_primary(void); 49 void thread_init_per_cpu(void); 50 51 struct thread_core_local *thread_get_core_local(void); 52 53 /* 54 * Sets the stacks to be used by the different threads. Use THREAD_ID_0 for 55 * first stack, THREAD_ID_0 + 1 for the next and so on. 56 * 57 * Returns true on success and false on errors. 58 */ 59 bool thread_init_stack(uint32_t stack_id, vaddr_t sp); 60 61 /* 62 * Initializes thread contexts. Called in thread_init_boot_thread() if 63 * virtualization is disabled. Virtualization subsystem calls it for 64 * every new guest otherwise. 65 */ 66 void thread_init_threads(void); 67 68 /* 69 * Called by the init CPU. Sets temporary stack mode for all CPUs 70 * (curr_thread = -1 and THREAD_CLF_TMP) and sets the temporary stack limit for 71 * the init CPU. 72 */ 73 void thread_init_thread_core_local(void); 74 void thread_init_core_local_stacks(void); 75 76 #if defined(CFG_CORE_PAUTH) 77 void thread_init_thread_pauth_keys(void); 78 void thread_init_core_local_pauth_keys(void); 79 #else 80 static inline void thread_init_thread_pauth_keys(void) { } 81 static inline void thread_init_core_local_pauth_keys(void) { } 82 #endif 83 84 /* 85 * Initializes a thread to be used during boot 86 */ 87 void thread_init_boot_thread(void); 88 89 /* 90 * Clears the current thread id 91 * Only supposed to be used during initialization. 92 */ 93 void thread_clr_boot_thread(void); 94 95 /* 96 * Returns current thread id. 97 */ 98 short int thread_get_id(void); 99 100 /* 101 * Returns current thread id, return -1 on failure. 102 */ 103 short int thread_get_id_may_fail(void); 104 105 /* Returns Thread Specific Data (TSD) pointer. */ 106 struct thread_specific_data *thread_get_tsd(void); 107 108 /* 109 * Sets foreign interrupts status for current thread, must only be called 110 * from an active thread context. 111 * 112 * enable == true -> enable foreign interrupts 113 * enable == false -> disable foreign interrupts 114 */ 115 void thread_set_foreign_intr(bool enable); 116 117 /* 118 * Restores the foreign interrupts status (in CPSR) for current thread, must 119 * only be called from an active thread context. 120 */ 121 void thread_restore_foreign_intr(void); 122 123 /* 124 * thread_get_exceptions() - return current exception mask 125 */ 126 uint32_t thread_get_exceptions(void); 127 128 /* 129 * thread_set_exceptions() - set exception mask 130 * @exceptions: exception mask to set 131 * 132 * Any previous exception mask is replaced by this exception mask, that is, 133 * old bits are cleared and replaced by these. 134 */ 135 void thread_set_exceptions(uint32_t exceptions); 136 137 /* 138 * thread_mask_exceptions() - Masks (disables) specified asynchronous exceptions 139 * @exceptions exceptions to mask 140 * @returns old exception state 141 */ 142 uint32_t thread_mask_exceptions(uint32_t exceptions); 143 144 /* 145 * thread_unmask_exceptions() - Unmasks asynchronous exceptions 146 * @state Old asynchronous exception state to restore (returned by 147 * thread_mask_exceptions()) 148 */ 149 void thread_unmask_exceptions(uint32_t state); 150 151 152 static inline bool __nostackcheck thread_foreign_intr_disabled(void) 153 { 154 return !!(thread_get_exceptions() & THREAD_EXCP_FOREIGN_INTR); 155 } 156 157 /* 158 * thread_enter_user_mode() - Enters user mode 159 * @a0: Passed in r/x0 for user_func 160 * @a1: Passed in r/x1 for user_func 161 * @a2: Passed in r/x2 for user_func 162 * @a3: Passed in r/x3 for user_func 163 * @user_sp: Assigned sp value in user mode 164 * @user_func: Function to execute in user mode 165 * @is_32bit: True if TA should execute in Aarch32, false if Aarch64 166 * @exit_status0: Pointer to opaque exit staus 0 167 * @exit_status1: Pointer to opaque exit staus 1 168 * 169 * This functions enters user mode with the argument described above, 170 * @exit_status0 and @exit_status1 are filled in by thread_unwind_user_mode() 171 * when returning back to the caller of this function through an exception 172 * handler. 173 * 174 * @Returns what's passed in "ret" to thread_unwind_user_mode() 175 */ 176 uint32_t thread_enter_user_mode(unsigned long a0, unsigned long a1, 177 unsigned long a2, unsigned long a3, unsigned long user_sp, 178 unsigned long entry_func, bool is_32bit, 179 uint32_t *exit_status0, uint32_t *exit_status1); 180 181 /* 182 * thread_unwind_user_mode() - Unwinds kernel stack from user entry 183 * @ret: Value to return from thread_enter_user_mode() 184 * @exit_status0: Exit status 0 185 * @exit_status1: Exit status 1 186 * 187 * This is the function that exception handlers can return into 188 * to resume execution in kernel mode instead of user mode. 189 * 190 * This function is closely coupled with thread_enter_user_mode() since it 191 * need to restore registers saved by thread_enter_user_mode() and when it 192 * returns make it look like thread_enter_user_mode() just returned. It is 193 * expected that the stack pointer is where thread_enter_user_mode() left 194 * it. The stack will be unwound and the function will return to where 195 * thread_enter_user_mode() was called from. Exit_status0 and exit_status1 196 * are filled in the corresponding pointers supplied to 197 * thread_enter_user_mode(). 198 */ 199 void thread_unwind_user_mode(uint32_t ret, uint32_t exit_status0, 200 uint32_t exit_status1); 201 202 /* 203 * Returns the start address (bottom) of the stack for the current thread, 204 * zero if there is no current thread. 205 */ 206 vaddr_t thread_stack_start(void); 207 208 209 /* Returns the stack size for the current thread */ 210 size_t thread_stack_size(void); 211 212 /* 213 * Returns the start (top, lowest address) and end (bottom, highest address) of 214 * the current stack (thread, temporary or abort stack). 215 * When CFG_CORE_DEBUG_CHECK_STACKS=y, the @hard parameter tells if the hard or 216 * soft limits are queried. The difference between soft and hard is that for the 217 * latter, the stack start includes some additional space to let any function 218 * overflow the soft limit and still be able to print a stack dump in this case. 219 */ 220 bool get_stack_limits(vaddr_t *start, vaddr_t *end, bool hard); 221 222 static inline bool __nostackcheck get_stack_soft_limits(vaddr_t *start, 223 vaddr_t *end) 224 { 225 return get_stack_limits(start, end, false); 226 } 227 228 static inline bool __nostackcheck get_stack_hard_limits(vaddr_t *start, 229 vaddr_t *end) 230 { 231 return get_stack_limits(start, end, true); 232 } 233 234 bool thread_is_in_normal_mode(void); 235 236 /* 237 * Returns true if previous exeception also was in abort mode. 238 * 239 * Note: it's only valid to call this function from an abort exception 240 * handler before interrupts has been re-enabled. 241 */ 242 bool thread_is_from_abort_mode(void); 243 244 /** 245 * Allocates data for payload buffers. 246 * 247 * @size: size in bytes of payload buffer 248 * 249 * @returns mobj that describes allocated buffer or NULL on error 250 */ 251 struct mobj *thread_rpc_alloc_payload(size_t size); 252 253 /** 254 * Free physical memory previously allocated with thread_rpc_alloc_payload() 255 * 256 * @mobj: mobj that describes the buffer 257 */ 258 void thread_rpc_free_payload(struct mobj *mobj); 259 260 /** 261 * Allocate data for payload buffers only shared with the non-secure kernel 262 * 263 * @size: size in bytes of payload buffer 264 * 265 * @returns mobj that describes allocated buffer or NULL on error 266 */ 267 struct mobj *thread_rpc_alloc_kernel_payload(size_t size); 268 269 /** 270 * Free physical memory previously allocated with 271 * thread_rpc_alloc_kernel_payload() 272 * 273 * @mobj: mobj that describes the buffer 274 */ 275 void thread_rpc_free_kernel_payload(struct mobj *mobj); 276 277 struct thread_param_memref { 278 size_t offs; 279 size_t size; 280 struct mobj *mobj; 281 }; 282 283 struct thread_param_value { 284 uint64_t a; 285 uint64_t b; 286 uint64_t c; 287 }; 288 289 /* 290 * Note that there's some arithmetics done on the value so it's important 291 * to keep in IN, OUT, INOUT order. 292 */ 293 enum thread_param_attr { 294 THREAD_PARAM_ATTR_NONE = 0, 295 THREAD_PARAM_ATTR_VALUE_IN, 296 THREAD_PARAM_ATTR_VALUE_OUT, 297 THREAD_PARAM_ATTR_VALUE_INOUT, 298 THREAD_PARAM_ATTR_MEMREF_IN, 299 THREAD_PARAM_ATTR_MEMREF_OUT, 300 THREAD_PARAM_ATTR_MEMREF_INOUT, 301 }; 302 303 struct thread_param { 304 enum thread_param_attr attr; 305 union { 306 struct thread_param_memref memref; 307 struct thread_param_value value; 308 } u; 309 }; 310 311 #define THREAD_PARAM_MEMREF(_direction, _mobj, _offs, _size) \ 312 (struct thread_param){ \ 313 .attr = THREAD_PARAM_ATTR_MEMREF_ ## _direction, .u.memref = { \ 314 .mobj = (_mobj), .offs = (_offs), .size = (_size) } \ 315 } 316 317 #define THREAD_PARAM_VALUE(_direction, _a, _b, _c) \ 318 (struct thread_param){ \ 319 .attr = THREAD_PARAM_ATTR_VALUE_ ## _direction, .u.value = { \ 320 .a = (_a), .b = (_b), .c = (_c) } \ 321 } 322 323 /** 324 * Does an RPC using a preallocated argument buffer 325 * @cmd: RPC cmd 326 * @num_params: number of parameters 327 * @params: RPC parameters 328 * @returns RPC return value 329 */ 330 uint32_t thread_rpc_cmd(uint32_t cmd, size_t num_params, 331 struct thread_param *params); 332 333 /** 334 * Allocate data for payload buffers. 335 * Buffer is exported to user mode applications. 336 * 337 * @size: size in bytes of payload buffer 338 * 339 * @returns mobj that describes allocated buffer or NULL on error 340 */ 341 struct mobj *thread_rpc_alloc_global_payload(size_t size); 342 343 /** 344 * Free physical memory previously allocated with 345 * thread_rpc_alloc_global_payload() 346 * 347 * @mobj: mobj that describes the buffer 348 */ 349 void thread_rpc_free_global_payload(struct mobj *mobj); 350 351 /* 352 * enum thread_shm_type - type of non-secure shared memory 353 * @THREAD_SHM_TYPE_APPLICATION - user space application shared memory 354 * @THREAD_SHM_TYPE_KERNEL_PRIVATE - kernel private shared memory 355 * @THREAD_SHM_TYPE_GLOBAL - user space and kernel shared memory 356 */ 357 enum thread_shm_type { 358 THREAD_SHM_TYPE_APPLICATION, 359 THREAD_SHM_TYPE_KERNEL_PRIVATE, 360 THREAD_SHM_TYPE_GLOBAL, 361 }; 362 363 /* 364 * enum thread_shm_cache_user - user of a cache allocation 365 * @THREAD_SHM_CACHE_USER_SOCKET - socket communication 366 * @THREAD_SHM_CACHE_USER_FS - filesystem access 367 * @THREAD_SHM_CACHE_USER_I2C - I2C communication 368 * 369 * To ensure that each user of the shared memory cache doesn't interfere 370 * with each other a unique ID per user is used. 371 */ 372 enum thread_shm_cache_user { 373 THREAD_SHM_CACHE_USER_SOCKET, 374 THREAD_SHM_CACHE_USER_FS, 375 THREAD_SHM_CACHE_USER_I2C, 376 }; 377 378 /* 379 * Returns a pointer to the cached RPC memory. Each thread and @user tuple 380 * has a unique cache. The pointer is guaranteed to point to a large enough 381 * area or to be NULL. 382 */ 383 void *thread_rpc_shm_cache_alloc(enum thread_shm_cache_user user, 384 enum thread_shm_type shm_type, 385 size_t size, struct mobj **mobj); 386 387 #endif /*__ASSEMBLER__*/ 388 389 #endif /*KERNEL_THREAD_H*/ 390