Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2013-2014 Wind River Systems, Inc.
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : /**
8 : : * @file
9 : : * @brief New thread creation for ARM Cortex-A, Cortex-M and Cortex-R
10 : : *
11 : : * Core thread related primitives for the ARM Cortex-A, Cortex-M and
12 : : * Cortex-R processor architecture.
13 : : */
14 : :
15 : : #include <kernel.h>
16 : : #include <ksched.h>
17 : : #include <wait_q.h>
18 : :
19 : : #if (MPU_GUARD_ALIGN_AND_SIZE_FLOAT > MPU_GUARD_ALIGN_AND_SIZE)
20 : : #define FP_GUARD_EXTRA_SIZE (MPU_GUARD_ALIGN_AND_SIZE_FLOAT - \
21 : : MPU_GUARD_ALIGN_AND_SIZE)
22 : : #else
23 : : #define FP_GUARD_EXTRA_SIZE 0
24 : : #endif
25 : :
26 : : #ifndef EXC_RETURN_FTYPE
27 : : /* bit [4] allocate stack for floating-point context: 0=done 1=skipped */
28 : : #define EXC_RETURN_FTYPE (0x00000010UL)
29 : : #endif
30 : :
31 : : /* Default last octet of EXC_RETURN, for threads that have not run yet.
32 : : * The full EXC_RETURN value will be e.g. 0xFFFFFFBC.
33 : : */
34 : : #if defined(CONFIG_ARM_NONSECURE_FIRMWARE)
35 : : #define DEFAULT_EXC_RETURN 0xBC;
36 : : #else
37 : : #define DEFAULT_EXC_RETURN 0xFD;
38 : : #endif
39 : :
40 : : #if !defined(CONFIG_MULTITHREADING) && defined(CONFIG_CPU_CORTEX_M)
41 : : extern K_THREAD_STACK_DEFINE(z_main_stack, CONFIG_MAIN_STACK_SIZE);
42 : : #endif
43 : :
44 : : /* An initial context, to be "restored" by z_arm_pendsv(), is put at the other
45 : : * end of the stack, and thus reusable by the stack when not needed anymore.
46 : : *
47 : : * The initial context is an exception stack frame (ESF) since exiting the
48 : : * PendSV exception will want to pop an ESF. Interestingly, even if the lsb of
49 : : * an instruction address to jump to must always be set since the CPU always
50 : : * runs in thumb mode, the ESF expects the real address of the instruction,
51 : : * with the lsb *not* set (instructions are always aligned on 16 bit
52 : : * halfwords). Since the compiler automatically sets the lsb of function
53 : : * addresses, we have to unset it manually before storing it in the 'pc' field
54 : : * of the ESF.
55 : : */
56 : 3 : void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
57 : : char *stack_ptr, k_thread_entry_t entry,
58 : : void *p1, void *p2, void *p3)
59 : : {
60 : : struct __basic_sf *iframe;
61 : :
62 : : #ifdef CONFIG_MPU_STACK_GUARD
63 : : #if defined(CONFIG_USERSPACE)
64 : : if (z_stack_is_user_capable(stack)) {
65 : : /* Guard area is carved-out of the buffer instead of reserved
66 : : * for stacks that can host user threads
67 : : */
68 : : thread->stack_info.start += MPU_GUARD_ALIGN_AND_SIZE;
69 : : thread->stack_info.size -= MPU_GUARD_ALIGN_AND_SIZE;
70 : : }
71 : : #endif /* CONFIG_USERSPACE */
72 : : #if FP_GUARD_EXTRA_SIZE > 0
73 : : if ((thread->base.user_options & K_FP_REGS) != 0) {
74 : : /* Larger guard needed due to lazy stacking of FP regs may
75 : : * overshoot the guard area without writing anything. We
76 : : * carve it out of the stack buffer as-needed instead of
77 : : * unconditionally reserving it.
78 : : */
79 : : thread->stack_info.start += FP_GUARD_EXTRA_SIZE;
80 : : thread->stack_info.size -= FP_GUARD_EXTRA_SIZE;
81 : : }
82 : : #endif /* FP_GUARD_EXTRA_SIZE */
83 : : #endif /* CONFIG_MPU_STACK_GUARD */
84 : :
85 : 3 : iframe = Z_STACK_PTR_TO_FRAME(struct __basic_sf, stack_ptr);
86 : : #if defined(CONFIG_USERSPACE)
87 : : if ((thread->base.user_options & K_USER) != 0) {
88 : : iframe->pc = (uint32_t)arch_user_mode_enter;
89 : : } else {
90 : : iframe->pc = (uint32_t)z_thread_entry;
91 : : }
92 : : #else
93 : 3 : iframe->pc = (uint32_t)z_thread_entry;
94 : : #endif
95 : :
96 : : #if defined(CONFIG_CPU_CORTEX_M)
97 : : /* force ARM mode by clearing LSB of address */
98 : 3 : iframe->pc &= 0xfffffffe;
99 : : #endif
100 : 3 : iframe->a1 = (uint32_t)entry;
101 : 3 : iframe->a2 = (uint32_t)p1;
102 : 3 : iframe->a3 = (uint32_t)p2;
103 : 3 : iframe->a4 = (uint32_t)p3;
104 : :
105 : : #if defined(CONFIG_CPU_CORTEX_M)
106 : 3 : iframe->xpsr =
107 : : 0x01000000UL; /* clear all, thumb bit is 1, even if RO */
108 : : #else
109 : : iframe->xpsr = A_BIT | MODE_SYS;
110 : : #if defined(CONFIG_COMPILER_ISA_THUMB2)
111 : : iframe->xpsr |= T_BIT;
112 : : #endif /* CONFIG_COMPILER_ISA_THUMB2 */
113 : : #endif /* CONFIG_CPU_CORTEX_M */
114 : :
115 : 3 : thread->callee_saved.psp = (uint32_t)iframe;
116 : 3 : thread->arch.basepri = 0;
117 : :
118 : : #if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE)
119 : : thread->arch.mode = 0;
120 : : #if defined(CONFIG_ARM_STORE_EXC_RETURN)
121 : : thread->arch.mode_exc_return = DEFAULT_EXC_RETURN;
122 : : #endif
123 : : #if FP_GUARD_EXTRA_SIZE > 0
124 : : if ((thread->base.user_options & K_FP_REGS) != 0) {
125 : : thread->arch.mode |= Z_ARM_MODE_MPU_GUARD_FLOAT_Msk;
126 : : }
127 : : #endif
128 : : #if defined(CONFIG_USERSPACE)
129 : : thread->arch.priv_stack_start = 0;
130 : : #endif
131 : : #endif
132 : : /*
133 : : * initial values in all other registers/thread entries are
134 : : * irrelevant.
135 : : */
136 : 3 : }
137 : :
138 : : #if defined(CONFIG_MPU_STACK_GUARD) && defined(CONFIG_FPU) \
139 : : && defined(CONFIG_FPU_SHARING)
140 : :
141 : : static inline void z_arm_thread_stack_info_adjust(struct k_thread *thread,
142 : : bool use_large_guard)
143 : : {
144 : : if (use_large_guard) {
145 : : /* Switch to use a large MPU guard if not already. */
146 : : if ((thread->arch.mode &
147 : : Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) == 0) {
148 : : /* Default guard size is used. Update required. */
149 : : thread->arch.mode |= Z_ARM_MODE_MPU_GUARD_FLOAT_Msk;
150 : : #if defined(CONFIG_USERSPACE)
151 : : if (thread->arch.priv_stack_start) {
152 : : /* User thread */
153 : : thread->arch.priv_stack_start +=
154 : : FP_GUARD_EXTRA_SIZE;
155 : : } else
156 : : #endif /* CONFIG_USERSPACE */
157 : : {
158 : : /* Privileged thread */
159 : : thread->stack_info.start +=
160 : : FP_GUARD_EXTRA_SIZE;
161 : : thread->stack_info.size -=
162 : : FP_GUARD_EXTRA_SIZE;
163 : : }
164 : : }
165 : : } else {
166 : : /* Switch to use the default MPU guard size if not already. */
167 : : if ((thread->arch.mode &
168 : : Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) {
169 : : /* Large guard size is used. Update required. */
170 : : thread->arch.mode &= ~Z_ARM_MODE_MPU_GUARD_FLOAT_Msk;
171 : : #if defined(CONFIG_USERSPACE)
172 : : if (thread->arch.priv_stack_start) {
173 : : /* User thread */
174 : : thread->arch.priv_stack_start -=
175 : : FP_GUARD_EXTRA_SIZE;
176 : : } else
177 : : #endif /* CONFIG_USERSPACE */
178 : : {
179 : : /* Privileged thread */
180 : : thread->stack_info.start -=
181 : : FP_GUARD_EXTRA_SIZE;
182 : : thread->stack_info.size +=
183 : : FP_GUARD_EXTRA_SIZE;
184 : : }
185 : : }
186 : : }
187 : : }
188 : :
189 : : /*
190 : : * Adjust the MPU stack guard size together with the FPU
191 : : * policy and the stack_info values for the thread that is
192 : : * being switched in.
193 : : */
194 : : uint32_t z_arm_mpu_stack_guard_and_fpu_adjust(struct k_thread *thread)
195 : : {
196 : : if (((thread->base.user_options & K_FP_REGS) != 0) ||
197 : : ((thread->arch.mode_exc_return & EXC_RETURN_FTYPE) == 0)) {
198 : : /* The thread has been pre-tagged (at creation or later) with
199 : : * K_FP_REGS, i.e. it is expected to be using the FPU registers
200 : : * (if not already). Activate lazy stacking and program a large
201 : : * MPU guard to safely detect privilege thread stack overflows.
202 : : *
203 : : * OR
204 : : * The thread is not pre-tagged with K_FP_REGS, but it has
205 : : * generated an FP context. Activate lazy stacking and
206 : : * program a large MPU guard to detect privilege thread
207 : : * stack overflows.
208 : : */
209 : : FPU->FPCCR |= FPU_FPCCR_LSPEN_Msk;
210 : :
211 : : z_arm_thread_stack_info_adjust(thread, true);
212 : :
213 : : /* Tag the thread with K_FP_REGS */
214 : : thread->base.user_options |= K_FP_REGS;
215 : :
216 : : return MPU_GUARD_ALIGN_AND_SIZE_FLOAT;
217 : : }
218 : :
219 : : /* Thread is not pre-tagged with K_FP_REGS, and it has
220 : : * not been using the FPU. Since there is no active FPU
221 : : * context, de-activate lazy stacking and program the
222 : : * default MPU guard size.
223 : : */
224 : : FPU->FPCCR &= (~FPU_FPCCR_LSPEN_Msk);
225 : :
226 : : z_arm_thread_stack_info_adjust(thread, false);
227 : :
228 : : return MPU_GUARD_ALIGN_AND_SIZE;
229 : : }
230 : : #endif
231 : :
232 : : #ifdef CONFIG_USERSPACE
233 : : FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry,
234 : : void *p1, void *p2, void *p3)
235 : : {
236 : :
237 : : /* Set up privileged stack before entering user mode */
238 : : _current->arch.priv_stack_start =
239 : : (uint32_t)z_priv_stack_find(_current->stack_obj);
240 : : #if defined(CONFIG_MPU_STACK_GUARD)
241 : : #if defined(CONFIG_THREAD_STACK_INFO)
242 : : /* We're dropping to user mode which means the guard area is no
243 : : * longer used here, it instead is moved to the privilege stack
244 : : * to catch stack overflows there. Un-do the calculations done
245 : : * which accounted for memory borrowed from the thread stack.
246 : : */
247 : : #if FP_GUARD_EXTRA_SIZE > 0
248 : : if ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) {
249 : : _current->stack_info.start -= FP_GUARD_EXTRA_SIZE;
250 : : _current->stack_info.size += FP_GUARD_EXTRA_SIZE;
251 : : }
252 : : #endif /* FP_GUARD_EXTRA_SIZE */
253 : : _current->stack_info.start -= MPU_GUARD_ALIGN_AND_SIZE;
254 : : _current->stack_info.size += MPU_GUARD_ALIGN_AND_SIZE;
255 : : #endif /* CONFIG_THREAD_STACK_INFO */
256 : :
257 : : /* Stack guard area reserved at the bottom of the thread's
258 : : * privileged stack. Adjust the available (writable) stack
259 : : * buffer area accordingly.
260 : : */
261 : : #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
262 : : _current->arch.priv_stack_start +=
263 : : ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) ?
264 : : MPU_GUARD_ALIGN_AND_SIZE_FLOAT : MPU_GUARD_ALIGN_AND_SIZE;
265 : : #else
266 : : _current->arch.priv_stack_start += MPU_GUARD_ALIGN_AND_SIZE;
267 : : #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
268 : : #endif /* CONFIG_MPU_STACK_GUARD */
269 : :
270 : : #if defined(CONFIG_CPU_AARCH32_CORTEX_R)
271 : : _current->arch.priv_stack_end =
272 : : _current->arch.priv_stack_start + CONFIG_PRIVILEGED_STACK_SIZE;
273 : : #endif
274 : :
275 : : z_arm_userspace_enter(user_entry, p1, p2, p3,
276 : : (uint32_t)_current->stack_info.start,
277 : : _current->stack_info.size -
278 : : _current->stack_info.delta);
279 : : CODE_UNREACHABLE;
280 : : }
281 : :
282 : : #endif
283 : :
284 : : #if defined(CONFIG_BUILTIN_STACK_GUARD)
285 : : /*
286 : : * @brief Configure ARM built-in stack guard
287 : : *
288 : : * This function configures per thread stack guards by reprogramming
289 : : * the built-in Process Stack Pointer Limit Register (PSPLIM).
290 : : * The functionality is meant to be used during context switch.
291 : : *
292 : : * @param thread thread info data structure.
293 : : */
294 : 3 : void configure_builtin_stack_guard(struct k_thread *thread)
295 : : {
296 : : #if defined(CONFIG_USERSPACE)
297 : : if ((thread->arch.mode & CONTROL_nPRIV_Msk) != 0) {
298 : : /* Only configure stack limit for threads in privileged mode
299 : : * (i.e supervisor threads or user threads doing system call).
300 : : * User threads executing in user mode do not require a stack
301 : : * limit protection.
302 : : */
303 : : __set_PSPLIM(0);
304 : : return;
305 : : }
306 : : /* Only configure PSPLIM to guard the privileged stack area, if
307 : : * the thread is currently using it, otherwise guard the default
308 : : * thread stack. Note that the conditional check relies on the
309 : : * thread privileged stack being allocated in higher memory area
310 : : * than the default thread stack (ensured by design).
311 : : */
312 : : uint32_t guard_start =
313 : : ((thread->arch.priv_stack_start) &&
314 : : (__get_PSP() >= thread->arch.priv_stack_start)) ?
315 : : (uint32_t)thread->arch.priv_stack_start :
316 : : (uint32_t)thread->stack_obj;
317 : :
318 : : __ASSERT(thread->stack_info.start == ((uint32_t)thread->stack_obj),
319 : : "stack_info.start does not point to the start of the"
320 : : "thread allocated area.");
321 : : #else
322 : 3 : uint32_t guard_start = thread->stack_info.start;
323 : : #endif
324 : : #if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM)
325 : : __set_PSPLIM(guard_start);
326 : : #else
327 : : #error "Built-in PSP limit checks not supported by HW"
328 : : #endif
329 : 3 : }
330 : : #endif /* CONFIG_BUILTIN_STACK_GUARD */
331 : :
332 : : #if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE)
333 : :
334 : : #define IS_MPU_GUARD_VIOLATION(guard_start, guard_len, fault_addr, stack_ptr) \
335 : : ((fault_addr != -EINVAL) ? \
336 : : ((fault_addr >= guard_start) && \
337 : : (fault_addr < (guard_start + guard_len)) && \
338 : : (stack_ptr < (guard_start + guard_len))) \
339 : : : \
340 : : (stack_ptr < (guard_start + guard_len)))
341 : :
342 : : /**
343 : : * @brief Assess occurrence of current thread's stack corruption
344 : : *
345 : : * This function performs an assessment whether a memory fault (on a
346 : : * given memory address) is the result of stack memory corruption of
347 : : * the current thread.
348 : : *
349 : : * Thread stack corruption for supervisor threads or user threads in
350 : : * privilege mode (when User Space is supported) is reported upon an
351 : : * attempt to access the stack guard area (if MPU Stack Guard feature
352 : : * is supported). Additionally the current PSP (process stack pointer)
353 : : * must be pointing inside or below the guard area.
354 : : *
355 : : * Thread stack corruption for user threads in user mode is reported,
356 : : * if the current PSP is pointing below the start of the current
357 : : * thread's stack.
358 : : *
359 : : * Notes:
360 : : * - we assume a fully descending stack,
361 : : * - we assume a stacking error has occurred,
362 : : * - the function shall be called when handling MemManage and Bus fault,
363 : : * and only if a Stacking error has been reported.
364 : : *
365 : : * If stack corruption is detected, the function returns the lowest
366 : : * allowed address where the Stack Pointer can safely point to, to
367 : : * prevent from errors when un-stacking the corrupted stack frame
368 : : * upon exception return.
369 : : *
370 : : * @param fault_addr memory address on which memory access violation
371 : : * has been reported. It can be invalid (-EINVAL),
372 : : * if only Stacking error has been reported.
373 : : * @param psp current address the PSP points to
374 : : *
375 : : * @return The lowest allowed stack frame pointer, if error is a
376 : : * thread stack corruption, otherwise return 0.
377 : : */
378 : : uint32_t z_check_thread_stack_fail(const uint32_t fault_addr, const uint32_t psp)
379 : : {
380 : : #if defined(CONFIG_MULTITHREADING)
381 : : const struct k_thread *thread = _current;
382 : :
383 : : if (thread == NULL) {
384 : : return 0;
385 : : }
386 : : #endif
387 : :
388 : : #if (defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)) && \
389 : : defined(CONFIG_MPU_STACK_GUARD)
390 : : uint32_t guard_len =
391 : : ((_current->arch.mode & Z_ARM_MODE_MPU_GUARD_FLOAT_Msk) != 0) ?
392 : : MPU_GUARD_ALIGN_AND_SIZE_FLOAT : MPU_GUARD_ALIGN_AND_SIZE;
393 : : #else
394 : : /* If MPU_STACK_GUARD is not enabled, the guard length is
395 : : * effectively zero. Stack overflows may be detected only
396 : : * for user threads in nPRIV mode.
397 : : */
398 : : uint32_t guard_len = MPU_GUARD_ALIGN_AND_SIZE;
399 : : #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
400 : :
401 : : #if defined(CONFIG_USERSPACE)
402 : : if (thread->arch.priv_stack_start) {
403 : : /* User thread */
404 : : if (z_arm_thread_is_in_user_mode() == false) {
405 : : /* User thread in privilege mode */
406 : : if (IS_MPU_GUARD_VIOLATION(
407 : : thread->arch.priv_stack_start - guard_len,
408 : : guard_len,
409 : : fault_addr, psp)) {
410 : : /* Thread's privilege stack corruption */
411 : : return thread->arch.priv_stack_start;
412 : : }
413 : : } else {
414 : : if (psp < (uint32_t)thread->stack_obj) {
415 : : /* Thread's user stack corruption */
416 : : return (uint32_t)thread->stack_obj;
417 : : }
418 : : }
419 : : } else {
420 : : /* Supervisor thread */
421 : : if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start -
422 : : guard_len,
423 : : guard_len,
424 : : fault_addr, psp)) {
425 : : /* Supervisor thread stack corruption */
426 : : return thread->stack_info.start;
427 : : }
428 : : }
429 : : #else /* CONFIG_USERSPACE */
430 : : #if defined(CONFIG_MULTITHREADING)
431 : : if (IS_MPU_GUARD_VIOLATION(thread->stack_info.start - guard_len,
432 : : guard_len,
433 : : fault_addr, psp)) {
434 : : /* Thread stack corruption */
435 : : return thread->stack_info.start;
436 : : }
437 : : #else
438 : : if (IS_MPU_GUARD_VIOLATION((uint32_t)z_main_stack,
439 : : guard_len,
440 : : fault_addr, psp)) {
441 : : /* Thread stack corruption */
442 : : return (uint32_t)Z_THREAD_STACK_BUFFER(z_main_stack);
443 : : }
444 : : #endif
445 : : #endif /* CONFIG_USERSPACE */
446 : :
447 : : return 0;
448 : : }
449 : : #endif /* CONFIG_MPU_STACK_GUARD || CONFIG_USERSPACE */
450 : :
451 : : #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
452 : : int arch_float_disable(struct k_thread *thread)
453 : : {
454 : : if (thread != _current) {
455 : : return -EINVAL;
456 : : }
457 : :
458 : : if (arch_is_in_isr()) {
459 : : return -EINVAL;
460 : : }
461 : :
462 : : /* Disable all floating point capabilities for the thread */
463 : :
464 : : /* K_FP_REG flag is used in SWAP and stack check fail. Locking
465 : : * interrupts here prevents a possible context-switch or MPU
466 : : * fault to take an outdated thread user_options flag into
467 : : * account.
468 : : */
469 : : int key = arch_irq_lock();
470 : :
471 : : thread->base.user_options &= ~K_FP_REGS;
472 : :
473 : : __set_CONTROL(__get_CONTROL() & (~CONTROL_FPCA_Msk));
474 : :
475 : : /* No need to add an ISB barrier after setting the CONTROL
476 : : * register; arch_irq_unlock() already adds one.
477 : : */
478 : :
479 : : arch_irq_unlock(key);
480 : :
481 : : return 0;
482 : : }
483 : :
484 : : int arch_float_enable(struct k_thread *thread, unsigned int options)
485 : : {
486 : : /* This is not supported in Cortex-M and Cortex-R does not have FPU */
487 : : return -ENOTSUP;
488 : : }
489 : : #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
490 : :
491 : : /* Internal function for Cortex-M initialization,
492 : : * applicable to either case of running Zephyr
493 : : * with or without multi-threading support.
494 : : */
495 : 1 : static void z_arm_prepare_switch_to_main(void)
496 : : {
497 : : #if defined(CONFIG_FPU)
498 : : /* Initialize the Floating Point Status and Control Register when in
499 : : * Unshared FP Registers mode (In Shared FP Registers mode, FPSCR is
500 : : * initialized at thread creation for threads that make use of the FP).
501 : : */
502 : : #if defined(CONFIG_ARMV8_1_M_MAINLINE)
503 : : /*
504 : : * For ARMv8.1-M with FPU, the FPSCR[18:16] LTPSIZE field must be set
505 : : * to 0b100 for "Tail predication not applied" as it's reset value
506 : : */
507 : : __set_FPSCR(4 << FPU_FPDSCR_LTPSIZE_Pos);
508 : : #else
509 : : __set_FPSCR(0);
510 : : #endif
511 : : #if defined(CONFIG_FPU_SHARING)
512 : : /* In Sharing mode clearing FPSCR may set the CONTROL.FPCA flag. */
513 : : __set_CONTROL(__get_CONTROL() & (~(CONTROL_FPCA_Msk)));
514 : : __ISB();
515 : : #endif /* CONFIG_FPU_SHARING */
516 : : #endif /* CONFIG_FPU */
517 : 1 : }
518 : :
519 : 1 : void arch_switch_to_main_thread(struct k_thread *main_thread, char *stack_ptr,
520 : : k_thread_entry_t _main)
521 : : {
522 : 1 : z_arm_prepare_switch_to_main();
523 : :
524 : 1 : _current = main_thread;
525 : :
526 : : #if defined(CONFIG_THREAD_LOCAL_STORAGE) && defined(CONFIG_CPU_CORTEX_M)
527 : : /* On Cortex-M, TLS uses a global variable as pointer to
528 : : * the thread local storage area. So this needs to point
529 : : * to the main thread's TLS area before switching to any
530 : : * thread for the first time, as the pointer is only set
531 : : * during context switching.
532 : : */
533 : : extern uintptr_t z_arm_tls_ptr;
534 : :
535 : : z_arm_tls_ptr = main_thread->tls;
536 : : #endif
537 : :
538 : : #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
539 : : z_thread_mark_switched_in();
540 : : #endif
541 : :
542 : : /* the ready queue cache already contains the main thread */
543 : :
544 : : #if defined(CONFIG_MPU_STACK_GUARD) || defined(CONFIG_USERSPACE)
545 : : /*
546 : : * If stack protection is enabled, make sure to set it
547 : : * before jumping to thread entry function
548 : : */
549 : : z_arm_configure_dynamic_mpu_regions(main_thread);
550 : : #endif
551 : :
552 : : #if defined(CONFIG_BUILTIN_STACK_GUARD)
553 : : /* Set PSPLIM register for built-in stack guarding of main thread. */
554 : : #if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM)
555 : 1 : __set_PSPLIM(main_thread->stack_info.start);
556 : : #else
557 : : #error "Built-in PSP limit checks not supported by HW"
558 : : #endif
559 : : #endif /* CONFIG_BUILTIN_STACK_GUARD */
560 : :
561 : : /*
562 : : * Set PSP to the highest address of the main stack
563 : : * before enabling interrupts and jumping to main.
564 : : */
565 : 1 : __asm__ volatile (
566 : : "mov r0, %0\n\t" /* Store _main in R0 */
567 : : #if defined(CONFIG_CPU_CORTEX_M)
568 : : "msr PSP, %1\n\t" /* __set_PSP(stack_ptr) */
569 : : #endif
570 : :
571 : : "movs r1, #0\n\t"
572 : : #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \
573 : : || defined(CONFIG_ARMV7_R) \
574 : : || defined(CONFIG_AARCH32_ARMV8_R) \
575 : : || defined(CONFIG_ARMV7_A)
576 : : "cpsie i\n\t" /* __enable_irq() */
577 : : #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
578 : : "cpsie if\n\t" /* __enable_irq(); __enable_fault_irq() */
579 : : "msr BASEPRI, r1\n\t" /* __set_BASEPRI(0) */
580 : : #else
581 : : #error Unknown ARM architecture
582 : : #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
583 : : "isb\n\t"
584 : : "movs r2, #0\n\t"
585 : : "movs r3, #0\n\t"
586 : : "bl z_thread_entry\n\t" /* z_thread_entry(_main, 0, 0, 0); */
587 : : :
588 : : : "r" (_main), "r" (stack_ptr)
589 : : : "r0" /* not to be overwritten by msr PSP, %1 */
590 : : );
591 : :
592 : 0 : CODE_UNREACHABLE;
593 : : }
594 : :
595 : : #if !defined(CONFIG_MULTITHREADING) && defined(CONFIG_CPU_CORTEX_M)
596 : :
597 : : FUNC_NORETURN void z_arm_switch_to_main_no_multithreading(
598 : : k_thread_entry_t main_entry, void *p1, void *p2, void *p3)
599 : : {
600 : : z_arm_prepare_switch_to_main();
601 : :
602 : : /* Set PSP to the highest address of the main stack. */
603 : : char *psp = Z_THREAD_STACK_BUFFER(z_main_stack) +
604 : : K_THREAD_STACK_SIZEOF(z_main_stack);
605 : :
606 : : #if defined(CONFIG_BUILTIN_STACK_GUARD)
607 : : char *psplim = (Z_THREAD_STACK_BUFFER(z_main_stack));
608 : : /* Clear PSPLIM before setting it to guard the main stack area. */
609 : : __set_PSPLIM(0);
610 : : #endif
611 : :
612 : : /* Store all required input in registers, to be accesible
613 : : * after stack pointer change. The function is not going
614 : : * to return, so callee-saved registers do not need to be
615 : : * stacked.
616 : : */
617 : : register void *p1_inreg __asm__("r0") = p1;
618 : : register void *p2_inreg __asm__("r1") = p2;
619 : : register void *p3_inreg __asm__("r2") = p3;
620 : :
621 : : __asm__ volatile (
622 : : #ifdef CONFIG_BUILTIN_STACK_GUARD
623 : : "msr PSPLIM, %[_psplim]\n\t"
624 : : #endif
625 : : "msr PSP, %[_psp]\n\t" /* __set_PSP(psp) */
626 : : #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
627 : : "cpsie i\n\t" /* enable_irq() */
628 : : #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
629 : : "cpsie if\n\t" /* __enable_irq(); __enable_fault_irq() */
630 : : "mov r3, #0\n\t"
631 : : "msr BASEPRI, r3\n\t" /* __set_BASEPRI(0) */
632 : : #endif
633 : : "isb\n\t"
634 : : "blx %[_main_entry]\n\t" /* main_entry(p1, p2, p3) */
635 : : #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
636 : : "cpsid i\n\t" /* disable_irq() */
637 : : #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
638 : : "msr BASEPRI, %[basepri]\n\t"/* __set_BASEPRI(_EXC_IRQ_DEFAULT_PRIO) */
639 : : "isb\n\t"
640 : : #endif
641 : : "loop: b loop\n\t" /* while (true); */
642 : : :
643 : : : "r" (p1_inreg), "r" (p2_inreg), "r" (p3_inreg),
644 : : [_psp]"r" (psp), [_main_entry]"r" (main_entry)
645 : : #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
646 : : , [basepri] "r" (_EXC_IRQ_DEFAULT_PRIO)
647 : : #endif
648 : : #ifdef CONFIG_BUILTIN_STACK_GUARD
649 : : , [_psplim]"r" (psplim)
650 : : #endif
651 : : :
652 : : );
653 : :
654 : : CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
655 : : }
656 : : #endif /* !CONFIG_MULTITHREADING && CONFIG_CPU_CORTEX_M */
|