diff --git a/arch/arm/core/offsets/offsets.c b/arch/arm/core/offsets/offsets.c index 69b7471f468..b91a5c95cfc 100644 --- a/arch/arm/core/offsets/offsets.c +++ b/arch/arm/core/offsets/offsets.c @@ -38,6 +38,7 @@ #include GEN_OFFSET_SYM(_thread_arch_t, basepri); +GEN_OFFSET_SYM(_thread_arch_t, swap_return_value); #ifdef CONFIG_FLOAT GEN_OFFSET_SYM(_thread_arch_t, preempt_float); diff --git a/arch/arm/core/swap.S b/arch/arm/core/swap.S index b1f0aecfe0b..d7648742f67 100644 --- a/arch/arm/core/swap.S +++ b/arch/arm/core/swap.S @@ -234,16 +234,6 @@ SECTION_FUNC(TEXT, __svc) _context_switch: #endif - /* - * Set _Swap()'s default return code to -EAGAIN. This eliminates the - * need for the timeout code to invoke fiberRtnValueSet(). - */ - - mrs r2, PSP /* thread mode, stack frame is on PSP */ - ldr r3, =_k_neg_eagain - ldr r3, [r3, #0] - str r3, [r2, #___esf_t_a1_OFFSET] - /* * Unlock interrupts: * - in a SVC call, so protected against context switches @@ -305,17 +295,21 @@ SECTION_FUNC(TEXT, _Swap) ldr r2, [r1, #_kernel_offset_to_current] str r0, [r2, #_thread_offset_to_basepri] + /* + * Set _Swap()'s default return code to -EAGAIN. This eliminates the need + * for the timeout code to set it itself. + */ + ldr r1, =_k_neg_eagain + ldr r1, [r1] + str r1, [r2, #_thread_offset_to_swap_return_value] + #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) /* No priority-based interrupt masking on M0/M0+, * pending PendSV is used instead of svc */ ldr r1, =_SCS_ICSR - ldr r2, =_SCS_ICSR_PENDSV - str r2, [r1, #0] - - /* load -EAGAIN as the default return value */ - ldr r0, =_k_neg_eagain - ldr r0, [r0] + ldr r3, =_SCS_ICSR_PENDSV + str r3, [r1, #0] /* Unlock interrupts to allow PendSV, since it's running at prio 0xff * @@ -323,12 +317,10 @@ SECTION_FUNC(TEXT, _Swap) * of a higher priority pending. */ cpsie i - - /* PC stored in stack frame by the hw */ - bx lr #else /* CONFIG_CPU_CORTEX_M3_M4 */ svc #0 - - /* r0 contains the return value if needed */ - bx lr #endif + + /* coming back from exception, r2 still holds the pointer to _current */ + ldr r0, [r2, #_thread_offset_to_swap_return_value] + bx lr diff --git a/arch/arm/core/thread.c b/arch/arm/core/thread.c index 485897bdb6f..6d56edfcd63 100644 --- a/arch/arm/core/thread.c +++ b/arch/arm/core/thread.c @@ -140,6 +140,8 @@ void _new_thread(char *pStackMem, unsigned stackSize, tcs->callee_saved.psp = (uint32_t)pInitCtx; tcs->arch.basepri = 0; + /* swap_return_value can contain garbage */ + _nano_timeout_thread_init(tcs); /* initial values in all other registers/TCS entries are irrelevant */ diff --git a/arch/arm/include/kernel_arch_data.h b/arch/arm/include/kernel_arch_data.h index 3fe0b868383..967092ff1a4 100644 --- a/arch/arm/include/kernel_arch_data.h +++ b/arch/arm/include/kernel_arch_data.h @@ -142,6 +142,9 @@ struct _thread_arch { /* interrupt locking key */ uint32_t basepri; + /* r0 in stack frame cannot be written to reliably */ + uint32_t swap_return_value; + #ifdef CONFIG_FLOAT /* * No cooperative floating point register set structure exists for diff --git a/arch/arm/include/kernel_arch_func.h b/arch/arm/include/kernel_arch_func.h index f298a0cdacd..4a254174b6c 100644 --- a/arch/arm/include/kernel_arch_func.h +++ b/arch/arm/include/kernel_arch_func.h @@ -47,25 +47,10 @@ static ALWAYS_INLINE void nanoArchInit(void) _CpuIdleInit(); } -/** - * - * @brief Set the return value for the specified fiber (inline) - * - * The register used to store the return value from a function call invocation - * to . It is assumed that the specified is pending, and thus - * the fiber's thread is stored in its struct tcs structure. - * - * @param fiber pointer to the fiber - * @param value is the value to set as a return value - * - * @return N/A - */ static ALWAYS_INLINE void _set_thread_return_value(struct k_thread *thread, unsigned int value) { - struct __esf *esf = (struct __esf *)thread->callee_saved.psp; - - esf->a1 = value; + thread->arch.swap_return_value = value; } extern void nano_cpu_atomic_idle(unsigned int); diff --git a/arch/arm/include/offsets_short_arch.h b/arch/arm/include/offsets_short_arch.h index a568737247a..983d0693805 100644 --- a/arch/arm/include/offsets_short_arch.h +++ b/arch/arm/include/offsets_short_arch.h @@ -30,6 +30,9 @@ #define _thread_offset_to_basepri \ (___thread_t_arch_OFFSET + ___thread_arch_t_basepri_OFFSET) +#define _thread_offset_to_swap_return_value \ + (___thread_t_arch_OFFSET + ___thread_arch_t_swap_return_value_OFFSET) + #define _thread_offset_to_preempt_float \ (___thread_t_arch_OFFSET + ___thread_arch_t_preempt_float_OFFSET)