LCOV - code coverage report
Current view: top level - arch/arm/core/aarch32 - thread.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 22 23 95.7 %
Date: 2022-08-18 11:36:24 Functions: 4 4 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           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 */

Generated by: LCOV version 1.14