firmware: split ARM classic & Cortex-M thread implementations

The implementations diverge enough that it is too confusing
to support them in the same source file; split them so it
is easier to understand.

Change-Id: Ic2f91c75e8a9bb605241441f2caed841585f5b87
This commit is contained in:
Aidan MacDonald 2026-01-12 11:01:41 +00:00
parent 2db798ff6d
commit af4ff3e270
6 changed files with 138 additions and 36 deletions

View file

@ -29,11 +29,7 @@ static void __attribute__((naked)) USED_ATTR start_thread(void)
{ {
/* r0 = context */ /* r0 = context */
asm volatile ( asm volatile (
#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7
"ldr sp, [r0, #36] \n" /* Load initial sp */
#else
"ldr sp, [r0, #32] \n" /* Load initial sp */ "ldr sp, [r0, #32] \n" /* Load initial sp */
#endif
"ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */ "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */
"mov r1, #0 \n" /* Mark thread as running */ "mov r1, #0 \n" /* Mark thread as running */
"str r1, [r0, #40] \n" "str r1, [r0, #40] \n"
@ -65,12 +61,7 @@ static void __attribute__((naked)) USED_ATTR start_thread(void)
static inline void store_context(void* addr) static inline void store_context(void* addr)
{ {
asm volatile( asm volatile(
#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7
"stmia %0, { r4-r11, lr } \n"
"str sp, [%0, #36] \n"
#else
"stmia %0, { r4-r11, sp, lr } \n" "stmia %0, { r4-r11, sp, lr } \n"
#endif
: : "r" (addr) : : "r" (addr)
); );
} }
@ -94,16 +85,8 @@ static inline void load_context(const void* addr)
"ldmiane %0, { r0, pc } \n" "ldmiane %0, { r0, pc } \n"
#endif #endif
#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7
"mov r0, %0 \n"
"ldmia r0, { r4-r11, lr } \n"
"ldr sp, [r0, #36] \n"
#else
"ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */ "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */
#endif
END_ARM_ASM_SYNTAX_UNIFIED END_ARM_ASM_SYNTAX_UNIFIED
: : "r" (addr) : "r0" /* only! */ : : "r" (addr) : "r0" /* only! */
); );
} }

View file

@ -21,20 +21,6 @@
#include "config.h" #include "config.h"
#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7
/*
* Cortex-M cannot load/store SP with ldm/stm so we need to store it
* separately. This makes it slightly more efficient to store SP last
* so as not to split the register list.
*/
struct regs
{
uint32_t r[8]; /* 0-28 - Registers r4-r11 */
uint32_t lr; /* 32 - r14 (lr) */
uint32_t sp; /* 36 - Stack pointer (r13) */
uint32_t start; /* 40 - Thread start address, or NULL when started */
};
#else
struct regs struct regs
{ {
uint32_t r[8]; /* 0-28 - Registers r4-r11 */ uint32_t r[8]; /* 0-28 - Registers r4-r11 */
@ -42,7 +28,6 @@ struct regs
uint32_t lr; /* 36 - r14 (lr) */ uint32_t lr; /* 36 - r14 (lr) */
uint32_t start; /* 40 - Thread start address, or NULL when started */ uint32_t start; /* 40 - Thread start address, or NULL when started */
}; };
#endif
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
#include <errno.h> #include <errno.h>

View file

@ -0,0 +1,88 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Thom Johansen
* Copyright (C) 2026 by Aidan MacDonald
*
* Threading support for ARM Cortex-M targets
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/*---------------------------------------------------------------------------
* Start the thread running and terminate it if it returns
*---------------------------------------------------------------------------
*/
static void __attribute__((naked)) USED_ATTR start_thread(void)
{
/* r0 = context */
asm volatile (
"ldr sp, [r0, #36] \n" /* Load initial sp */
"ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */
"mov r1, #0 \n" /* Mark thread as running */
"str r1, [r0, #40] \n"
"mov lr, pc \n" /* Call thread function */
"bx r4 \n"
); /* No clobber list - new thread doesn't care */
thread_exit();
}
/* For startup, place context pointer in r4 slot, start_thread pointer in r5
* slot, and thread function pointer in context.start. See load_context for
* what happens when thread is initially going to run. */
#define THREAD_STARTUP_INIT(core, thread, function) \
({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \
(thread)->context.r[1] = (uint32_t)start_thread, \
(thread)->context.start = (uint32_t)function; })
/*---------------------------------------------------------------------------
* Store non-volatile context.
*---------------------------------------------------------------------------
*/
static inline void store_context(void* addr)
{
asm volatile(
"stmia %0, { r4-r11, lr } \n"
"str sp, [%0, #36] \n"
: : "r" (addr)
);
}
/*---------------------------------------------------------------------------
* Load non-volatile context.
*---------------------------------------------------------------------------
*/
static inline void load_context(const void* addr)
{
asm volatile(
BEGIN_ARM_ASM_SYNTAX_UNIFIED
"ldr r0, [%0, #40] \n" /* Load start pointer */
"cmp r0, #0 \n" /* Check for NULL */
/* If not already running, jump to start */
"ldmiane %0, { r0, pc } \n"
/* Load regs r4 to r14 from context */
"mov r0, %0 \n"
"ldmia r0, { r4-r11, lr } \n"
"ldr sp, [r0, #36] \n"
END_ARM_ASM_SYNTAX_UNIFIED
: : "r" (addr) : "r0" /* only! */
);
}

View file

@ -0,0 +1,42 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Ulf Ralberg
* Copyright (C) 2026 by Aidan MacDonald
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
/*
* Cortex-M cannot load/store SP with ldm/stm so we need to store it
* separately. This makes it slightly more efficient to store SP last
* so as not to split the register list.
*/
struct regs
{
uint32_t r[8]; /* 0-28 - Registers r4-r11 */
uint32_t lr; /* 32 - r14 (lr) */
uint32_t sp; /* 36 - Stack pointer (r13) */
uint32_t start; /* 40 - Thread start address, or NULL when started */
};
#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
# include <errno.h>
#else
# define DEFAULT_STACK_SIZE 0x400 /* Bytes */
#endif

View file

@ -5,8 +5,10 @@
#include "thread-unix.c" #include "thread-unix.c"
/* Now the CPU-specific implementations */ /* Now the CPU-specific implementations */
#elif defined(CPU_ARM) #elif defined(CPU_ARM_CLASSIC) || defined(CPU_ARM_APPLICATION)
#include "arm/thread.c" #include "arm/thread-classic.c"
#elif defined(CPU_ARM_MICRO)
#include "arm/thread-micro.c"
#elif defined(CPU_COLDFIRE) #elif defined(CPU_COLDFIRE)
#include "m68k/thread.c" #include "m68k/thread.c"
#elif defined(CPU_MIPS) #elif defined(CPU_MIPS)

View file

@ -59,8 +59,10 @@ struct regs
#elif defined(HAVE_WIN32_FIBER_THREADS) #elif defined(HAVE_WIN32_FIBER_THREADS)
#define DEFAULT_STACK_SIZE 0x1000 /* Bytes */ #define DEFAULT_STACK_SIZE 0x1000 /* Bytes */
#endif #endif
#elif defined(CPU_ARM) #elif defined(CPU_ARM_CLASSIC) || defined(CPU_ARM_APPLICATION)
#include "arm/thread.h" #include "arm/thread-classic.h"
#elif defined(CPU_ARM_MICRO)
#include "arm/thread-micro.h"
#elif defined(CPU_COLDFIRE) #elif defined(CPU_COLDFIRE)
#include "m68k/thread.h" #include "m68k/thread.h"
#elif defined(CPU_MIPS) #elif defined(CPU_MIPS)