arm,riscv: eliminate idle_thread function prologue

Similar to #510 but for all other platforms. The idle_thread runs
without a stack and so cannot handle the stack prologue. This should
hopefully make the kernel rely less on FORCE_INLINE for this as well.

We create idle.S assembly files for each platform, as GCC does not
support `__attribute__((naked))` on AArch64 (GCC 13.2.0) and bails out.

Signed-off-by: julia <git.ts@trainwit.ch>
This commit is contained in:
julia 2025-05-21 12:50:30 +10:00 committed by Gerwin Klein
parent dfaef4b712
commit 5de930983b
15 changed files with 63 additions and 66 deletions

View file

@ -8,12 +8,6 @@
#include <util.h>
/* See idle_thread for an explanation as to why FORCE_INLINE is required here. */
static inline void FORCE_INLINE wfi(void)
{
asm volatile("wfi" ::: "memory");
}
static inline void dsb(void)
{
asm volatile("dsb" ::: "memory");

View file

@ -6,11 +6,6 @@
#pragma once
static inline void wfi(void)
{
asm volatile("wfi" ::: "memory");
}
static inline void dsb(void)
{
asm volatile("dsb sy" ::: "memory");
@ -42,4 +37,3 @@ static inline void isb(void)
#define SYSTEM_READ_WORD(reg, v) MRS(reg, v)
#define SYSTEM_WRITE_64(reg, v) MSR(reg, v)
#define SYSTEM_READ_64(reg, v) MRS(reg, v)

View file

@ -165,7 +165,7 @@ void Arch_switchToIdleThread(void);
void Arch_configureIdleThread(tcb_t *tcb);
void Arch_activateIdleThread(tcb_t *tcb);
void idle_thread(void);
void NORETURN idle_thread(void);
void configureIdleThread(tcb_t *tcb);
void activateThread(void);
@ -316,4 +316,3 @@ static inline void setThreadStateBlockedOnReply(tcb_t *tptr, reply_t *reply)
scheduleTCB(tptr);
}
#endif

View file

@ -20,5 +20,5 @@ add_sources(
idle.c
kernel/thread.c
kernel/vspace.c
ASMFILES head.S traps.S hyp_traps.S
ASMFILES head.S traps.S hyp_traps.S idle.S
)

15
src/arch/arm/32/idle.S Normal file
View file

@ -0,0 +1,15 @@
/*
* Copyright 2025, UNSW
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <machine/assembler.h>
.code 32
.section .text, "ax"
BEGIN_FUNC(idle_thread)
1: wfi
b 1b
END_FUNC(idle_thread)

View file

@ -8,23 +8,6 @@
#include <mode/machine.h>
#include <api/debug.h>
/*
* The idle thread currently does not receive a stack pointer and so we rely on
* optimisations for correctness here. More specifically, we assume:
* - Ordinary prologue/epilogue stack operations are optimised out
* - All nested function calls are inlined
* Note that GCC does not correctly implement optimisation annotations on nested
* functions, so FORCE_INLINE is required on the wfi declaration in this case.
* Note that Clang doesn't obey FORCE_O2 and relies on the kernel being compiled
* with optimisations enabled.
*/
void FORCE_O2 idle_thread(void)
{
while (1) {
wfi();
}
}
/** DONT_TRANSLATE */
void NORETURN NO_INLINE VISIBLE halt(void)
{

View file

@ -20,5 +20,5 @@ add_sources(
idle.c
kernel/thread.c
kernel/vspace.c
ASMFILES head.S traps.S
ASMFILES head.S traps.S idle.S
)

14
src/arch/arm/64/idle.S Normal file
View file

@ -0,0 +1,14 @@
/*
* Copyright 2025, UNSW
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <machine/assembler.h>
.section .text, "ax"
BEGIN_FUNC(idle_thread)
1: wfi
b 1b
END_FUNC(idle_thread)

View file

@ -8,13 +8,6 @@
#include <mode/machine.h>
#include <api/debug.h>
void idle_thread(void)
{
while (1) {
wfi();
}
}
/** DONT_TRANSLATE */
void NORETURN NO_INLINE VISIBLE halt(void)
{

View file

@ -122,7 +122,7 @@ add_sources(
object/objecttype.c
object/tcb.c
smp/ipi.c
ASMFILES head.S traps.S
ASMFILES head.S traps.S idle.S
)
add_bf_source_old("KernelArchRiscV" "structures.bf" "include/arch/riscv" "arch/object")

14
src/arch/riscv/idle.S Normal file
View file

@ -0,0 +1,14 @@
/*
* Copyright 2025, UNSW
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <machine/assembler.h>
.section .text, "ax"
BEGIN_FUNC(idle_thread)
1: wfi
j 1b
END_FUNC(idle_thread)

View file

@ -8,13 +8,6 @@
#include <config.h>
#include <arch/sbi.h>
void idle_thread(void)
{
while (1) {
asm volatile("wfi");
}
}
/** DONT_TRANSLATE */
void VISIBLE NO_INLINE halt(void)
{

View file

@ -419,7 +419,7 @@ add_sources(
machine/registerset.c
benchmark/benchmark.c
smp/ipi.c
ASMFILES multiboot.S
ASMFILES multiboot.S idle.S
)
add_bf_source_old("KernelArchX86" "structures.bf" "include/arch/x86" "arch/object")

15
src/arch/x86/idle.S Normal file
View file

@ -0,0 +1,15 @@
/*
* Copyright 2025, UNSW
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <machine/assembler.h>
.section .text, "ax"
.code32
BEGIN_FUNC(idle_thread)
1: hlt
jmp 1b
END_FUNC(idle_thread)

View file

@ -7,23 +7,6 @@
#include <config.h>
#include <api/debug.h>
/*
* The idle thread does not have a dedicated stack and runs in
* the context of the idle thread TCB. Make sure that the compiler
* always eliminates the function prologue by declaring the
* idle_thread with the naked attribute.
*/
__attribute__((naked)) NORETURN void idle_thread(void)
{
/* We cannot use for-loop or while-loop here because they may
* involve stack manipulations (the compiler will not allow
* them in a naked function anyway). */
asm volatile(
"1: hlt\n"
"jmp 1b"
);
}
/** DONT_TRANSLATE */
void VISIBLE halt(void)
{