xref: /optee_os/core/include/kernel/thread.h (revision 039e02df2716a0ed886b56e1e07b7ac1d8597228)
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