From 60cf099fe91d20585bc94303c123ca7001d7898b Mon Sep 17 00:00:00 2001 From: Axel Heider Date: Wed, 8 Nov 2023 20:45:32 +0100 Subject: [PATCH] implement idle thread in assembly The idle thread does not have any stack, thus implementing the function in assembler avoids convincing the compiler not to use any stack for a C function. Signed-off-by: Axel Heider --- include/arch/arm/armv/armv7-a/armv/machine.h | 1 - include/util.h | 5 ---- src/arch/arm/32/config.cmake | 1 - src/arch/arm/32/idle.c | 26 -------------------- src/arch/arm/64/config.cmake | 1 - src/arch/arm/64/idle.c | 15 ----------- src/arch/arm/config.cmake | 1 + src/arch/arm/idle.S | 20 +++++++++++++++ src/arch/riscv/config.cmake | 3 +-- src/arch/riscv/idle.S | 20 +++++++++++++++ src/arch/riscv/idle.c | 15 ----------- src/arch/x86/config.cmake | 3 +-- src/arch/x86/idle.S | 19 ++++++++++++++ src/arch/x86/idle.c | 25 ------------------- 14 files changed, 62 insertions(+), 93 deletions(-) delete mode 100644 src/arch/arm/32/idle.c delete mode 100644 src/arch/arm/64/idle.c create mode 100644 src/arch/arm/idle.S create mode 100644 src/arch/riscv/idle.S delete mode 100644 src/arch/riscv/idle.c create mode 100644 src/arch/x86/idle.S delete mode 100644 src/arch/x86/idle.c diff --git a/include/arch/arm/armv/armv7-a/armv/machine.h b/include/arch/arm/armv/armv7-a/armv/machine.h index 87ef3fefed..2bb577f8ff 100644 --- a/include/arch/arm/armv/armv7-a/armv/machine.h +++ b/include/arch/arm/armv/armv7-a/armv/machine.h @@ -8,7 +8,6 @@ #include -/* 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"); diff --git a/include/util.h b/include/util.h index 7d6e8e4f4b..602f1a8e3f 100644 --- a/include/util.h +++ b/include/util.h @@ -85,11 +85,6 @@ #define SECTION(sec) __attribute__((__section__(sec))) #define UNUSED __attribute__((unused)) #define USED __attribute__((used)) -#ifdef __clang__ -#define FORCE_O2 /* nothing */ -#else -#define FORCE_O2 __attribute__((optimize("O2"))) -#endif /** MODIFIES: */ void __builtin_unreachable(void); #define UNREACHABLE() __builtin_unreachable() diff --git a/src/arch/arm/32/config.cmake b/src/arch/arm/32/config.cmake index 917dcb8a94..5e1d63f2fd 100644 --- a/src/arch/arm/32/config.cmake +++ b/src/arch/arm/32/config.cmake @@ -16,7 +16,6 @@ add_sources( machine/fpu.c model/statedata.c c_traps.c - idle.c kernel/thread.c kernel/vspace.c ASMFILES head.S traps.S hyp_traps.S diff --git a/src/arch/arm/32/idle.c b/src/arch/arm/32/idle.c deleted file mode 100644 index 5c5d5efef8..0000000000 --- a/src/arch/arm/32/idle.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014, General Dynamics C4 Systems - * - * SPDX-License-Identifier: GPL-2.0-only - */ - -#include -#include -#include - -/* - * 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(); - } -} diff --git a/src/arch/arm/64/config.cmake b/src/arch/arm/64/config.cmake index 0784d593f4..d5a0ac34f2 100644 --- a/src/arch/arm/64/config.cmake +++ b/src/arch/arm/64/config.cmake @@ -16,7 +16,6 @@ add_sources( machine/fpu.c model/statedata.c c_traps.c - idle.c kernel/thread.c kernel/vspace.c ASMFILES head.S traps.S diff --git a/src/arch/arm/64/idle.c b/src/arch/arm/64/idle.c deleted file mode 100644 index 57d010a3fe..0000000000 --- a/src/arch/arm/64/idle.c +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) - * - * SPDX-License-Identifier: GPL-2.0-only - */ - -#include -#include - -void idle_thread(void) -{ - while (1) { - wfi(); - } -} diff --git a/src/arch/arm/config.cmake b/src/arch/arm/config.cmake index 03bff4def4..4c5655935a 100644 --- a/src/arch/arm/config.cmake +++ b/src/arch/arm/config.cmake @@ -265,6 +265,7 @@ add_sources( object/smmu.c object/smc.c smp/ipi.c + ASMFILES idle.S ) add_bf_source_old("KernelArchARM" "structures.bf" "include/arch/arm" "arch/object") diff --git a/src/arch/arm/idle.S b/src/arch/arm/idle.S new file mode 100644 index 0000000000..4c77113ad9 --- /dev/null +++ b/src/arch/arm/idle.S @@ -0,0 +1,20 @@ +/* + * Copyright 2014, General Dynamics C4 Systems + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * Copyright 2021, Axel Heider + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include + +/* The idle thread does not have any stack, thus its simple loop is implemented + * in assembly. That avoids having to find ways to convince the compiler not to + * ever generate any code that uses the stack. There seems no clean and portable + * way for this, and there is no guarantee any solution in C will always work. + */ +.section .text, "ax" +BEGIN_FUNC(idle_thread) +1: wfi + b 1b +END_FUNC(idle_thread) diff --git a/src/arch/riscv/config.cmake b/src/arch/riscv/config.cmake index ca2fdfc4f4..cd6d790da4 100644 --- a/src/arch/riscv/config.cmake +++ b/src/arch/riscv/config.cmake @@ -95,7 +95,6 @@ add_sources( PREFIX src/arch/riscv CFILES c_traps.c - idle.c api/faults.c api/benchmark.c kernel/boot.c @@ -111,7 +110,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") diff --git a/src/arch/riscv/idle.S b/src/arch/riscv/idle.S new file mode 100644 index 0000000000..9405a6f244 --- /dev/null +++ b/src/arch/riscv/idle.S @@ -0,0 +1,20 @@ +/* + * Copyright 2015, 2016 Hesham Almatary + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * Copyright 2021, Axel Heider + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include + +/* The idle thread does not have any stack, thus its simple loop is implemented + * in assembly. That avoids having to find ways to convince the compiler not to + * ever generate any code that uses the stack. There seems no clean and portable + * way for this, and there is no guarantee any solution in C will always work. + */ +.section .text, "ax" +BEGIN_FUNC(idle_thread) +1: wfi + j 1b +END_FUNC(idle_thread) diff --git a/src/arch/riscv/idle.c b/src/arch/riscv/idle.c deleted file mode 100644 index df64764b0c..0000000000 --- a/src/arch/riscv/idle.c +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) - * Copyright 2015, 2016 Hesham Almatary - * - * SPDX-License-Identifier: GPL-2.0-only - */ - -#include - -void idle_thread(void) -{ - while (1) { - asm volatile("wfi"); - } -} diff --git a/src/arch/x86/config.cmake b/src/arch/x86/config.cmake index 2c170bd091..dadd9f904e 100644 --- a/src/arch/x86/config.cmake +++ b/src/arch/x86/config.cmake @@ -365,7 +365,6 @@ add_sources( PREFIX src/arch/x86 CFILES c_traps.c - idle.c api/faults.c object/interrupt.c object/ioport.c @@ -392,7 +391,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") diff --git a/src/arch/x86/idle.S b/src/arch/x86/idle.S new file mode 100644 index 0000000000..26b171fe78 --- /dev/null +++ b/src/arch/x86/idle.S @@ -0,0 +1,19 @@ +/* + * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) + * Copyright 2021, Axel Heider + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include + +/* The idle thread does not have any stack, thus its simple loop is implemented + * in assembly. That avoids having to find ways to convince the compiler not to + * ever generate any code that uses the stack. There seems no clean and portable + * way for this, and there is no guarantee any solution in C will always work. + */ +.section .text, "ax" +BEGIN_FUNC(idle_thread) +1: hlt + jmp 1b +END_FUNC(idle_thread) diff --git a/src/arch/x86/idle.c b/src/arch/x86/idle.c deleted file mode 100644 index 9b980bcd2d..0000000000 --- a/src/arch/x86/idle.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) - * - * SPDX-License-Identifier: GPL-2.0-only - */ - -#include -#include - -/* - * 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" - ); -}