diff --git a/arch/arm/core/swap_helper.S b/arch/arm/core/swap_helper.S index 1e5f2d94143..c21ca43bce0 100644 --- a/arch/arm/core/swap_helper.S +++ b/arch/arm/core/swap_helper.S @@ -190,14 +190,6 @@ _thread_irq_disabled: pop {r2, lr} #endif /* CONFIG_MPU_STACK_GUARD */ -#ifdef CONFIG_BUILTIN_STACK_GUARD - /* r2 contains k_thread */ - add r0, r2, #0 - push {r2, lr} - blx configure_builtin_stack_guard - pop {r2, lr} -#endif /* CONFIG_BUILTIN_STACK_GUARD */ - #ifdef CONFIG_USERSPACE /* restore mode */ ldr r0, [r2, #_thread_offset_to_mode] @@ -231,8 +223,24 @@ _thread_irq_disabled: #error Unknown ARM architecture #endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ +#ifdef CONFIG_BUILTIN_STACK_GUARD + /* clear stack pointer limit before setting the PSP */ + push {r3} + mov r3, #0 + msr PSPLIM, r3 + pop {r3} +#endif + msr PSP, ip +#ifdef CONFIG_BUILTIN_STACK_GUARD + /* r2 contains k_thread */ + add r0, r2, #0 + push {r2, lr} + blx configure_builtin_stack_guard + pop {r2, lr} +#endif /* CONFIG_BUILTIN_STACK_GUARD */ + #ifdef CONFIG_EXECUTION_BENCHMARKING stm sp!,{r0-r3} /* Save regs r0 to r4 on stack */ push {lr} diff --git a/arch/arm/core/thread.c b/arch/arm/core/thread.c index 330a698f8ef..f5c3470f0a0 100644 --- a/arch/arm/core/thread.c +++ b/arch/arm/core/thread.c @@ -142,12 +142,21 @@ FUNC_NORETURN void _arch_user_mode_enter(k_thread_entry_t user_entry, * * This function configures per thread stack guards by reprogramming * the built-in Process Stack Pointer Limit Register (PSPLIM). + * The functionality is meant to be used during context switch. * * @param thread thread info data structure. */ void configure_builtin_stack_guard(struct k_thread *thread) { #if defined(CONFIG_USERSPACE) + if (thread->arch.mode & CONTROL_nPRIV_Msk) { + /* Only configure stack limit for threads in privileged mode + * (i.e supervisor threads or user threads doing system call). + * User threads executing in user mode do not require a stack + * limit protection. + */ + return; + } u32_t guard_start = thread->arch.priv_stack_start ? (u32_t)thread->arch.priv_stack_start : (u32_t)thread->stack_obj; diff --git a/arch/arm/core/userspace.S b/arch/arm/core/userspace.S index d5f4e209882..530f2591807 100644 --- a/arch/arm/core/userspace.S +++ b/arch/arm/core/userspace.S @@ -56,9 +56,25 @@ SECTION_FUNC(TEXT,_arm_userspace_enter) ldr ip, =CONFIG_PRIVILEGED_STACK_SIZE add r0, r0, ip +#if defined(CONFIG_BUILTIN_STACK_GUARD) + /* clear stack pointer limit before setting the PSP */ + push {r3} + mov r3, #0 + msr PSPLIM, r3 + pop {r3} +#endif + mov ip, sp msr PSP, r0 +#if defined(CONFIG_BUILTIN_STACK_GUARD) + /* set stack pointer limit to the start of the priv stack */ + ldr r0, =_kernel + ldr r0, [r0, #_kernel_offset_to_current] + ldr r0, [r0, #_thread_offset_to_priv_stack_start] /* priv stack ptr */ + msr PSPLIM, r0 +#endif + /* load up stack info from user stack */ ldr r0, [ip] ldr ip, [ip, #4] @@ -96,6 +112,14 @@ SECTION_FUNC(TEXT,_arm_userspace_enter) /* r0 contains user stack start, ip contains user stack size */ add r0, r0, ip /* calculate top of stack */ +#if defined(CONFIG_BUILTIN_STACK_GUARD) + /* clear stack limit (stack protection not required in user mode) */ + push {r3} + mov r3, #0 + msr PSPLIM, r3 + pop {r3} +#endif + /* set stack to user stack */ msr PSP, r0 @@ -169,6 +193,16 @@ valid_syscall: /* switch to privileged stack */ msr PSP, ip +#if defined(CONFIG_BUILTIN_STACK_GUARD) + /* Set stack pointer limit (needed in privileged mode) */ + push {r6} + ldr r6, =_kernel + ldr r6, [r6, #_kernel_offset_to_current] + ldr r6, [r6, #_thread_offset_to_priv_stack_start] /* priv stack ptr */ + msr PSPLIM, r6 + pop {r6} +#endif + /* push args to complete stack frame */ push {r4,r5} @@ -183,6 +217,14 @@ dispatch_syscall: /* restore LR */ ldr lr, [sp,#12] +#if defined(CONFIG_BUILTIN_STACK_GUARD) + /* clear stack limit (stack protection not required in user mode) */ + push {r3} + mov r3, #0 + msr PSPLIM, r3 + pop {r3} +#endif + /* set stack back to unprivileged stack */ ldr ip, [sp,#8] msr PSP, ip