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