Skip to content

Commit 4936bd0

Browse files
xhackerustcfabiobaltieri
authored andcommitted
arch: arm64: Convert cpu_idle from ASM to C
ASM is notoriously harder to maintain than C and requires core specific adaptation which impairs even more the readability of the code. There's a bug in current arch_cpu_atomic_idle asm version: tst x0, #(DAIF_IRQ_BIT) //here Z := (DAIF_IRQ_BIT == 0) beq _irq_disabled //jump to _irq_disabled when Z is set msr daifclr, #(DAIFCLR_IRQ_BIT) _irq_disabled: ret As can be seen, the asm code jumps to _irq_disabled when Z is set, but per aarch64 architecture reference, DAIF_IRQ == 0 means the IRQ is unmasked, I.E enabled. So the asm logic here is wrong. I fixed this bug in C version. This shows the benefit of ASM -> C As for performance concern, except the bug fix above, there's no difference of generated code between ASM and C version. ASM version: <arch_cpu_idle>: d5033f9f dsb sy d503207f wfi d50342ff msr daifclr, #0x2 d65f03c0 ret arch_cpu_atomic_idle>: d50342df msr daifset, #0x2 d5033fdf isb d503205f wfe f279001f tst x0, #0x80 54000040 b.eq 1001d10 <_irq_disabled> // b.none d50342ff msr daifclr, #0x2 _irq_disabled>: d65f03c0 ret C version: <arch_cpu_idle>: d5033f9f dsb sy d503207f wfi d50342ff msr daifclr, #0x2 d65f03c0 ret <arch_cpu_atomic_idle>: d50342df msr daifset, #0x2 d5033fdf isb d503205f wfe 37380040 tbnz w0, #7, 1001d0c <arch_cpu_atomic_idle+0x14> d50342ff msr daifclr, #0x2 d65f03c0 ret And as can be seen, C version use the tbnz instruction to test bit and branch. Unlike TST, TBNZ does not affect the Z, N, C, or V flags in the processor state. So except the bug fix, C version looks a bit better than asm version. Other architectures such as x86, riscv, rx, xtensa, mips and even arm cortex_m also use c version for cpu_idle, it's safe for ASM -> C. Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
1 parent 327105f commit 4936bd0

File tree

3 files changed

+55
-58
lines changed

3 files changed

+55
-58
lines changed

arch/arm64/core/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
zephyr_library()
44

55
zephyr_library_sources(
6-
cpu_idle.S
6+
cpu_idle.c
77
early_mem_funcs.S
88
fatal.c
99
irq_init.c

arch/arm64/core/cpu_idle.S

Lines changed: 0 additions & 57 deletions
This file was deleted.

arch/arm64/core/cpu_idle.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2019 Carlo Caione <ccaione@baylibre.com>
3+
* Copyright (c) 2026 Synaptics Incorporated
4+
* Author: Jisheng Zhang <jszhang@kernel.org>
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
/*
10+
* ARM64 Cortex-A power management
11+
*/
12+
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/tracing/tracing.h>
15+
16+
#ifndef CONFIG_ARCH_HAS_CUSTOM_CPU_IDLE
17+
void arch_cpu_idle(void)
18+
{
19+
#if defined(CONFIG_TRACING)
20+
sys_trace_idle();
21+
#endif
22+
23+
__asm__ volatile("dsb sy" : : : "memory");
24+
wfi();
25+
26+
#if defined(CONFIG_TRACING)
27+
sys_trace_idle_exit();
28+
#endif
29+
30+
enable_irq();
31+
}
32+
#endif
33+
34+
#ifndef CONFIG_ARCH_HAS_CUSTOM_CPU_ATOMIC_IDLE
35+
void arch_cpu_atomic_idle(unsigned int key)
36+
{
37+
#if defined(CONFIG_TRACING)
38+
sys_trace_idle();
39+
#endif
40+
41+
disable_irq();
42+
43+
__asm__ volatile("isb" : : : "memory");
44+
wfe();
45+
46+
#if defined(CONFIG_TRACING)
47+
sys_trace_idle_exit();
48+
#endif
49+
50+
if (!(key & DAIF_IRQ_BIT)) {
51+
enable_irq();
52+
}
53+
}
54+
#endif

0 commit comments

Comments
 (0)