From 827ce94e0897a70241abf810b1d3d7d083053a39 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Mon, 27 Apr 2026 15:01:26 +0100 Subject: [PATCH 1/7] arm64/daifflags: Make local_daif_*() helpers __always_inline Make sure those helpers are always inlined and instrumentation safe. Suggested-by: Mark Rutland Signed-off-by: Leonardo Bras Signed-off-by: Will Deacon --- arch/arm64/include/asm/daifflags.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h index 5fca48009043..795b35128467 100644 --- a/arch/arm64/include/asm/daifflags.h +++ b/arch/arm64/include/asm/daifflags.h @@ -19,7 +19,7 @@ /* mask/save/unmask/restore all exceptions, including interrupts. */ -static inline void local_daif_mask(void) +static __always_inline void local_daif_mask(void) { WARN_ON(system_has_prio_mask_debugging() && (read_sysreg_s(SYS_ICC_PMR_EL1) == (GIC_PRIO_IRQOFF | @@ -38,7 +38,7 @@ static inline void local_daif_mask(void) trace_hardirqs_off(); } -static inline unsigned long local_daif_save_flags(void) +static __always_inline unsigned long local_daif_save_flags(void) { unsigned long flags; @@ -53,7 +53,7 @@ static inline unsigned long local_daif_save_flags(void) return flags; } -static inline unsigned long local_daif_save(void) +static __always_inline unsigned long local_daif_save(void) { unsigned long flags; @@ -64,7 +64,7 @@ static inline unsigned long local_daif_save(void) return flags; } -static inline void local_daif_restore(unsigned long flags) +static __always_inline void local_daif_restore(unsigned long flags) { bool irq_disabled = flags & PSR_I_BIT; @@ -124,7 +124,7 @@ static inline void local_daif_restore(unsigned long flags) * Called by synchronous exception handlers to restore the DAIF bits that were * modified by taking an exception. */ -static inline void local_daif_inherit(struct pt_regs *regs) +static __always_inline void local_daif_inherit(struct pt_regs *regs) { unsigned long flags = regs->pstate & DAIF_MASK; From e7cec385d2c6726e692d057f91f20b08c2981af3 Mon Sep 17 00:00:00 2001 From: Pengjie Zhang Date: Wed, 6 May 2026 17:08:51 +0800 Subject: [PATCH 2/7] arm64: smp: Do not mark secondary CPUs possible under nosmp Under nosmp (maxcpus=0), arm64 never brings up secondary CPUs. smp_prepare_cpus() already treats this as a UP-mandated boot and returns before marking secondary CPUs present. However, smp_init_cpus() may still enumerate firmware-described secondary CPUs and mark them possible before that point. Avoid marking secondary CPUs possible when nosmp/maxcpus=0 is in effect, so that cpu_possible_mask reflects the nosmp boot policy for this boot. Suggested-by: Catalin Marinas Reviewed-by: Catalin Marinas Signed-off-by: Pengjie Zhang Signed-off-by: Will Deacon --- arch/arm64/kernel/smp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 1aa324104afb..1b63846f646a 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -745,15 +745,21 @@ void __init smp_init_cpus(void) else acpi_parse_and_init_cpus(); - if (cpu_count > nr_cpu_ids) - pr_warn("Number of cores (%d) exceeds configured maximum of %u - clipping\n", - cpu_count, nr_cpu_ids); - if (!bootcpu_valid) { pr_err("missing boot CPU MPIDR, not enabling secondaries\n"); return; } + /* + * For the nosmp/maxcpus=0 case, do not mark the secondary CPUs + * possible. + */ + if (!setup_max_cpus) + return; + + if (cpu_count > nr_cpu_ids) + pr_warn("Number of cores (%d) exceeds configured maximum of %u - clipping\n", + cpu_count, nr_cpu_ids); /* * We need to set the cpu_logical_map entries before enabling * the cpus so that cpu processor description entries (DT cpu nodes From 7dc6922f7fdd3496de4e7d8fb99284fc08f98003 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Thu, 26 Mar 2026 23:57:52 +0100 Subject: [PATCH 3/7] arm64: panic from init_IRQ if IRQ handler stacks cannot be allocated init_irq_stacks() and init_irq_scs() may fail when arch_alloc_vmap_stack or scs_alloc return NULL. Return -ENOMEM from both and call panic() once from init_IRQ(), covering per-CPU IRQ stacks and shadow IRQ stacks consistently. Signed-off-by: Osama Abdelkader Signed-off-by: Will Deacon --- arch/arm64/kernel/irq.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 15dedb385b9e..9fafd826002b 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -10,6 +10,7 @@ * Copyright (C) 2012 ARM Ltd. */ +#include #include #include #include @@ -32,34 +33,43 @@ DEFINE_PER_CPU(struct nmi_ctx, nmi_contexts); DEFINE_PER_CPU(unsigned long *, irq_stack_ptr); - DECLARE_PER_CPU(unsigned long *, irq_shadow_call_stack_ptr); #ifdef CONFIG_SHADOW_CALL_STACK DEFINE_PER_CPU(unsigned long *, irq_shadow_call_stack_ptr); #endif -static void init_irq_scs(void) +static int __init init_irq_scs(void) { int cpu; + void *s; if (!scs_is_enabled()) - return; + return 0; - for_each_possible_cpu(cpu) - per_cpu(irq_shadow_call_stack_ptr, cpu) = - scs_alloc(early_cpu_to_node(cpu)); + for_each_possible_cpu(cpu) { + s = scs_alloc(early_cpu_to_node(cpu)); + if (!s) + return -ENOMEM; + per_cpu(irq_shadow_call_stack_ptr, cpu) = s; + } + + return 0; } -static void __init init_irq_stacks(void) +static int __init init_irq_stacks(void) { int cpu; unsigned long *p; for_each_possible_cpu(cpu) { p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, early_cpu_to_node(cpu)); + if (!p) + return -ENOMEM; per_cpu(irq_stack_ptr, cpu) = p; } + + return 0; } #ifdef CONFIG_SOFTIRQ_ON_OWN_STACK @@ -109,8 +119,9 @@ int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *)) void __init init_IRQ(void) { - init_irq_stacks(); - init_irq_scs(); + if (init_irq_stacks() || init_irq_scs()) + panic("Failed to allocate IRQ stack resources\n"); + irqchip_init(); if (system_uses_irq_prio_masking()) { From d54e4fde9de2b8670788fd3bb4daf31cf1cb1622 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 11 May 2026 22:16:59 +0200 Subject: [PATCH 4/7] arm64: Implement _THIS_IP_ using inline asm Both GCC [1] and Clang [2] consider the generic version of _THIS_IP_ to be broken: #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) In particular, the address of a label is only expected to be used with a computed goto. While the generic version more or less works today, it is known to be brittle and may break with current and future optimizations. For example, Clang -O2 always returns 1 when this function is inlined: static inline unsigned long get_ip(void) { return ({ __label__ __here; __here: (unsigned long)&&__here; }); } Fix it by overriding _THIS_IP_ in (which is included by ) using an architecture-specific inline asm version. Additionally, avoiding taking the address of a label prevents compilers from emitting spurious indirect branch targets (e.g. ENDBR or BTI) under control-flow integrity schemes. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120071 [1] Link: https://github.com/llvm/llvm-project/issues/138272 [2] Signed-off-by: Marco Elver Signed-off-by: Will Deacon --- arch/arm64/include/asm/linkage.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/linkage.h b/arch/arm64/include/asm/linkage.h index 40bd17add539..73eabc82a6bb 100644 --- a/arch/arm64/include/asm/linkage.h +++ b/arch/arm64/include/asm/linkage.h @@ -43,4 +43,6 @@ SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \ bti c ; +#define _THIS_IP_ ({ unsigned long __ip; asm volatile("adr %0, ." : "=r" (__ip)); __ip; }) + #endif From 32e4c96d6a7121cb378ebf9ce2167bb1918eeaa5 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sat, 16 May 2026 19:53:42 -0700 Subject: [PATCH 5/7] ARM64: remove unnecessary architecture-specific arch/arm64/include/asm/device.h is identical to include/asm-generic/device.h, and therefore the ARM64-specific version is unnecessary. Remove it. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Will Deacon --- arch/arm64/include/asm/device.h | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 arch/arm64/include/asm/device.h diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h deleted file mode 100644 index 996498751318..000000000000 --- a/arch/arm64/include/asm/device.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2012 ARM Ltd. - */ -#ifndef __ASM_DEVICE_H -#define __ASM_DEVICE_H - -struct dev_archdata { -}; - -struct pdev_archdata { -}; - -#endif From 6c2ccb4979b2c8aa83cbea827a714a74db7d2398 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 1 Jun 2026 00:08:16 +0200 Subject: [PATCH 6/7] arm64: patching: replace min_t with min in __text_poke Use the simpler min() macro since both values are unsigned and compatible. Signed-off-by: Thorsten Blum Signed-off-by: Will Deacon --- arch/arm64/kernel/patching.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/kernel/patching.c b/arch/arm64/kernel/patching.c index 1041bc67a3ee..09f019c6547a 100644 --- a/arch/arm64/kernel/patching.c +++ b/arch/arm64/kernel/patching.c @@ -116,8 +116,7 @@ static void *__text_poke(text_poke_f func, void *addr, void *src, size_t len) while (patched < len) { ptr = addr + patched; - size = min_t(size_t, PAGE_SIZE - offset_in_page(ptr), - len - patched); + size = min(PAGE_SIZE - offset_in_page(ptr), len - patched); waddr = patch_map(ptr, FIX_TEXT_POKE0); func(waddr, src, patched, size); From 11c33ffb3a4e65e775e9bd814eb71df06ea7c847 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Sat, 23 May 2026 12:59:26 -0400 Subject: [PATCH 7/7] arm64: arch_timer: reuse arch_timer_read_cnt{p,v}ct_el0() helpers __arch_counter_get_cntpct() and __arch_counter_get_cntvct() open-code the same ECV-aware ALTERNATIVE block that arch_timer_read_cntpct_el0() and arch_timer_read_cntvct_el0() already provide in the same header. The two pairs are byte-for-byte identical except for the trailing arch_counter_enforce_ordering() the __arch_counter_get_* variants add. Replace the duplicated inline assembly in __arch_counter_get_cntpct() and __arch_counter_get_cntvct() with calls to the corresponding helpers. This mirrors commit 00b39d150986 ("arm64: vdso: Use __arch_counter_get_cntvct()"), which removed similar duplication from the vDSO, and keeps the system-counter read sequence in a single place, reducing assembly code in the kernell No functional change: the resulting inline assembly, alternatives, and clobbers are unchanged; only the source-level expression of the read moves into the existing helper. Verified by rebuilding the consumers of these helpers before and after the change and comparing the resulting disassembly: - arch/arm64/kernel/vdso/vdso.so (final linked vDSO): bit-identical (same sha256 across rebuilds) - arch/arm64/kernel/vdso/vgettimeofday.o: identical disassembly - arch/arm64/lib/delay.o: identical disassembly - drivers/clocksource/arm_arch_timer.o: same 50 functions with byte-identical instruction streams; only difference is function ordering inside .text and NOP padding, with no opcodes added or removed. Signed-off-by: Breno Leitao Signed-off-by: Will Deacon --- arch/arm64/include/asm/arch_timer.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index f5794d50f51d..6717209df05b 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -178,12 +178,8 @@ static __always_inline u64 __arch_counter_get_cntpct_stable(void) static __always_inline u64 __arch_counter_get_cntpct(void) { - u64 cnt; + u64 cnt = arch_timer_read_cntpct_el0(); - asm volatile(ALTERNATIVE("isb\n mrs %0, cntpct_el0", - "nop\n" __mrs_s("%0", SYS_CNTPCTSS_EL0), - ARM64_HAS_ECV) - : "=r" (cnt)); arch_counter_enforce_ordering(cnt); return cnt; } @@ -199,12 +195,8 @@ static __always_inline u64 __arch_counter_get_cntvct_stable(void) static __always_inline u64 __arch_counter_get_cntvct(void) { - u64 cnt; + u64 cnt = arch_timer_read_cntvct_el0(); - asm volatile(ALTERNATIVE("isb\n mrs %0, cntvct_el0", - "nop\n" __mrs_s("%0", SYS_CNTVCTSS_EL0), - ARM64_HAS_ECV) - : "=r" (cnt)); arch_counter_enforce_ordering(cnt); return cnt; }