* [PATCH 0/4] ARM: allocate the cacheinfo early to fix the PREEMPT_RT boot warning
@ 2026-09-12 19:55 Karl Mehltretter
2026-09-12 19:55 ` [PATCH 1/4] ARM: cacheinfo: avoid out-of-bounds write in populate_cache_leaves() Karl Mehltretter
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Karl Mehltretter @ 2026-09-12 19:55 UTC (permalink / raw)
To: Russell King, Dmitry Baryshkov, Sudeep Holla
Cc: Karl Mehltretter, Pierre Gondois, Linus Walleij, Radu Rendec,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-arm-kernel, linux-rt-devel, linux-kernel, stable
This series moves ARM cacheinfo allocation to the boot CPU to avoid
sleeping-lock warnings during PREEMPT_RT secondary-CPU startup. It is
based on 5225b8eec4c9 (7.3-rc2 plus one day).
Patches 1-3 prepare for early allocation: bound cache-leaf writes,
include external caches in the allocation size, and guard CLIDR reads
on older CPUs. Patch 4 enables early allocation. Please take all four
patches together for stable.
Tested on QEMU virt (Cortex-A15), vexpress-a9 (Cortex-A9 with PL310),
and realview-eb-mpcore (ARM11 MPCore) with PREEMPT_RT, plus non-RT
virt and vexpress-a9 builds. Cache sysfs output is unchanged for the
normal platform DTs, and CPU hotplug passes where supported. Additional
checks cover DT leaf undercounting with KASAN and ARM11 DT cache
descriptions.
The full series also passes on a Raspberry Pi 400 with a 32-bit
PREEMPT_RT 7.2.6-rc1 kernel: the boot warning is absent and all 12 cache
sysfs entries match the baseline. CPU hotplug is unavailable there.
The series applies unchanged to 7.2.6-rc1 and v6.18.
Karl Mehltretter (4):
ARM: cacheinfo: avoid out-of-bounds write in populate_cache_leaves()
ARM: cacheinfo: count external caches in early_cache_level()
ARM: cacheinfo: guard the CLIDR read in populate_cache_leaves()
ARM: topology: allocate the cacheinfo early on the boot CPU
arch/arm/kernel/cacheinfo.c | 49 +++++++++++++++++++------------------
arch/arm/kernel/topology.c | 13 ++++++++++
2 files changed, 38 insertions(+), 24 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] ARM: cacheinfo: avoid out-of-bounds write in populate_cache_leaves()
2026-09-12 19:55 [PATCH 0/4] ARM: allocate the cacheinfo early to fix the PREEMPT_RT boot warning Karl Mehltretter
@ 2026-09-12 19:55 ` Karl Mehltretter
2026-09-12 19:55 ` [PATCH 2/4] ARM: cacheinfo: count external caches in early_cache_level() Karl Mehltretter
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Karl Mehltretter @ 2026-09-12 19:55 UTC (permalink / raw)
To: Russell King, Dmitry Baryshkov, Sudeep Holla
Cc: Karl Mehltretter, Pierre Gondois, Linus Walleij, Radu Rendec,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-arm-kernel, linux-rt-devel, linux-kernel, stable
populate_cache_leaves() advances its bounds-checking index once per
cache level, but split instruction/data caches consume two entries.
CLIDR-based allocation supplies enough entries. Early allocation from
the device tree can supply fewer and expose an out-of-bounds write.
Count each written leaf and stop before a split level that does not
fit. This prepares ARM for DT-based early allocation and matches
commit 875d742cf532 ("arm64: cacheinfo: Avoid out-of-bounds write to
cacheinfo array").
Fixes: a9ff94477836 ("ARM: 9433/2: implement cacheinfo support")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
The overrun was reproduced with KASAN on QEMU virt, cortex-a15, using
a device tree whose cpu nodes carry only d-cache-size, so one leaf.
With patch 4 alone the boot reports a slab-out-of-bounds write in
populate_cache_leaves(). With this patch the boot is clean.
arch/arm/kernel/cacheinfo.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
index e1469b641780..860eeb03cfe5 100644
--- a/arch/arm/kernel/cacheinfo.c
+++ b/arch/arm/kernel/cacheinfo.c
@@ -151,7 +151,7 @@ int populate_cache_leaves(unsigned int cpu)
unsigned int level, idx;
enum cache_type type;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
- struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+ struct cacheinfo *infos = this_cpu_ci->info_list;
unsigned int arch = cpu_architecture();
/* CLIDR is not present before ARMv7/v7m */
@@ -159,13 +159,15 @@ int populate_cache_leaves(unsigned int cpu)
return -EOPNOTSUPP;
for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
- idx < this_cpu_ci->num_leaves; idx++, level++) {
+ idx < this_cpu_ci->num_leaves; level++) {
type = get_cache_type(level);
if (type == CACHE_TYPE_SEPARATE) {
- ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
- ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
+ if (idx + 1 >= this_cpu_ci->num_leaves)
+ break;
+ ci_leaf_init(&infos[idx++], CACHE_TYPE_DATA, level);
+ ci_leaf_init(&infos[idx++], CACHE_TYPE_INST, level);
} else {
- ci_leaf_init(this_leaf++, type, level);
+ ci_leaf_init(&infos[idx++], type, level);
}
}
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/4] ARM: cacheinfo: count external caches in early_cache_level()
2026-09-12 19:55 [PATCH 0/4] ARM: allocate the cacheinfo early to fix the PREEMPT_RT boot warning Karl Mehltretter
2026-09-12 19:55 ` [PATCH 1/4] ARM: cacheinfo: avoid out-of-bounds write in populate_cache_leaves() Karl Mehltretter
@ 2026-09-12 19:55 ` Karl Mehltretter
2026-09-12 20:09 ` sashiko-bot
2026-09-12 19:55 ` [PATCH 3/4] ARM: cacheinfo: guard the CLIDR read in populate_cache_leaves() Karl Mehltretter
2026-09-12 19:55 ` [PATCH 4/4] ARM: topology: allocate the cacheinfo early on the boot CPU Karl Mehltretter
3 siblings, 1 reply; 6+ messages in thread
From: Karl Mehltretter @ 2026-09-12 19:55 UTC (permalink / raw)
To: Russell King, Dmitry Baryshkov, Sudeep Holla
Cc: Karl Mehltretter, Pierre Gondois, Linus Walleij, Radu Rendec,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-arm-kernel, linux-rt-devel, linux-kernel, stable
early_cache_level() counts only caches described by CLIDR. An external
PL310 is absent from CLIDR, and its arm,pl310-cache compatible is not
accepted by init_of_cache_level(), so early allocation falls back to
an incomplete count. init_cache_level() later adds the DT-described
L2, forcing reallocation on the secondary CPU with interrupts disabled.
This defeats early allocation on PREEMPT_RT.
Use init_cache_level() for early sizing too, so the initial allocation
includes external caches described by the device tree.
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
Without this patch, patch 4 keeps the warning on QEMU vexpress-a9
(4 Cortex-A9, PL310): the early size is 2 leaves, init_cache_level()
wants 3, and init_level_allocate_ci() reallocates on the secondary
CPU. With it the warning is gone and the cache sysfs tree is unchanged
(L1 data, L1 instruction, L2 unified shared by all CPUs).
arch/arm/kernel/cacheinfo.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
index 860eeb03cfe5..31591c947254 100644
--- a/arch/arm/kernel/cacheinfo.c
+++ b/arch/arm/kernel/cacheinfo.c
@@ -111,13 +111,6 @@ static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p)
return 0;
}
-int early_cache_level(unsigned int cpu)
-{
- struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
-
- return detect_cache_level(&this_cpu_ci->num_levels, &this_cpu_ci->num_leaves);
-}
-
int init_cache_level(unsigned int cpu)
{
unsigned int level, leaves;
@@ -146,6 +139,11 @@ int init_cache_level(unsigned int cpu)
return 0;
}
+int early_cache_level(unsigned int cpu)
+{
+ return init_cache_level(cpu);
+}
+
int populate_cache_leaves(unsigned int cpu)
{
unsigned int level, idx;
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/4] ARM: cacheinfo: guard the CLIDR read in populate_cache_leaves()
2026-09-12 19:55 [PATCH 0/4] ARM: allocate the cacheinfo early to fix the PREEMPT_RT boot warning Karl Mehltretter
2026-09-12 19:55 ` [PATCH 1/4] ARM: cacheinfo: avoid out-of-bounds write in populate_cache_leaves() Karl Mehltretter
2026-09-12 19:55 ` [PATCH 2/4] ARM: cacheinfo: count external caches in early_cache_level() Karl Mehltretter
@ 2026-09-12 19:55 ` Karl Mehltretter
2026-09-12 19:55 ` [PATCH 4/4] ARM: topology: allocate the cacheinfo early on the boot CPU Karl Mehltretter
3 siblings, 0 replies; 6+ messages in thread
From: Karl Mehltretter @ 2026-09-12 19:55 UTC (permalink / raw)
To: Russell King, Dmitry Baryshkov, Sudeep Holla
Cc: Karl Mehltretter, Pierre Gondois, Linus Walleij, Radu Rendec,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-arm-kernel, linux-rt-devel, linux-kernel, stable
ARM1176 and ARM11 MPCore can be reported as ARMv7 by
cpu_architecture() even though they lack CLIDR. populate_cache_leaves()
therefore needs the CTR-format check used by detect_cache_level().
DT-based early allocation bypasses init_cache_level(), so its check
no longer protects populate_cache_leaves(). A combined ARMv6/ARMv7
SMP kernel can reach this path on BCM2835, whose DT describes its
caches.
Share the CLIDR capability check between detection and population.
Return -ENOENT from population when CLIDR is unavailable, preserving
the existing absence of cacheinfo and avoiding a new topology warning.
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
Reproduced on QEMU realview-eb-mpcore (ARM11 MPCore, reported as ARMv7
by cpu_architecture()) with a device tree carrying i-cache-size and
d-cache-size on the cpu nodes like bcm2835.dtsi: with patch 4 and
without this patch populate_cache_leaves() reads CLIDR, which QEMU
returns as zero, so every leaf becomes CACHE_TYPE_NOCACHE. Real ARM11
does not implement the register. With this patch the read is skipped,
the boot is silent and cacheinfo stays absent as before the series.
arch/arm/kernel/cacheinfo.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
index 31591c947254..993c8a134786 100644
--- a/arch/arm/kernel/cacheinfo.c
+++ b/arch/arm/kernel/cacheinfo.c
@@ -80,19 +80,21 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
this_leaf->type = type;
}
-static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p)
+static bool clidr_present(void)
{
- unsigned int ctype, level, leaves;
- u32 ctr, format;
-
/* CLIDR is not present before ARMv7/v7m */
if (cpu_architecture() < CPU_ARCH_ARMv7)
- return -EOPNOTSUPP;
+ return false;
/* Don't try reading CLIDR if CTR declares old format */
- ctr = read_cpuid_cachetype();
- format = FIELD_GET(CTR_FORMAT_MASK, ctr);
- if (format != CTR_FORMAT_ARMV7)
+ return FIELD_GET(CTR_FORMAT_MASK, read_cpuid_cachetype()) == CTR_FORMAT_ARMV7;
+}
+
+static int detect_cache_level(unsigned int *level_p, unsigned int *leaves_p)
+{
+ unsigned int ctype, level, leaves;
+
+ if (!clidr_present())
return -EOPNOTSUPP;
for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
@@ -150,11 +152,10 @@ int populate_cache_leaves(unsigned int cpu)
enum cache_type type;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *infos = this_cpu_ci->info_list;
- unsigned int arch = cpu_architecture();
- /* CLIDR is not present before ARMv7/v7m */
- if (arch < CPU_ARCH_ARMv7)
- return -EOPNOTSUPP;
+ /* The device tree can describe caches CLIDR cannot fill in. */
+ if (!clidr_present())
+ return -ENOENT;
for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
idx < this_cpu_ci->num_leaves; level++) {
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 4/4] ARM: topology: allocate the cacheinfo early on the boot CPU
2026-09-12 19:55 [PATCH 0/4] ARM: allocate the cacheinfo early to fix the PREEMPT_RT boot warning Karl Mehltretter
` (2 preceding siblings ...)
2026-09-12 19:55 ` [PATCH 3/4] ARM: cacheinfo: guard the CLIDR read in populate_cache_leaves() Karl Mehltretter
@ 2026-09-12 19:55 ` Karl Mehltretter
3 siblings, 0 replies; 6+ messages in thread
From: Karl Mehltretter @ 2026-09-12 19:55 UTC (permalink / raw)
To: Russell King, Dmitry Baryshkov, Sudeep Holla
Cc: Karl Mehltretter, Pierre Gondois, Linus Walleij, Radu Rendec,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-arm-kernel, linux-rt-devel, linux-kernel, stable
ARM secondary CPUs allocate cacheinfo in detect_cache_attributes(),
called from secondary_start_kernel() with interrupts disabled. With
PREEMPT_RT, the allocation takes a sleeping lock and triggers
"BUG: sleeping function called from invalid context".
Call fetch_cache_info() for each possible CPU from init_cpu_topology()
on the boot CPU, following commit 5944ce092b97 ("arch_topology: Build
cacheinfo from primary CPU"). This supplies the arrays before secondary
CPUs populate them. Suppress -ENOENT and -EOPNOTSUPP, which leave cache
detection to the existing late path.
The CLIDR fallback uses the boot CPU's cache geometry. A secondary CPU
with more cache leaves can still require late reallocation and trigger
the warning.
Fixes: a9ff94477836 ("ARM: 9433/2: implement cacheinfo support")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
Full warning on QEMU virt, cortex-a15, 7.3-rc2, PREEMPT_RT:
BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 0, name: swapper/1
Call trace:
rt_spin_lock from ___slab_alloc+0x68/0x728
...
__kmalloc_noprof from detect_cache_attributes+0xe4/0x734
detect_cache_attributes from update_siblings_masks+0x10/0x174
update_siblings_masks from secondary_start_kernel+0xec/0x120
PREEMPT_RT became selectable on ARM in 7.1 with commit c6e61c06d606
("ARM: 9463/1: Allow to enable RT"). The PREEMPT_RT patch queues carry
that change for 6.18 and later, so 6.18.y is affected as well.
QEMU virt, cortex-a15, PREEMPT_RT, 2 and 4 CPUs: the warning is gone,
the cacheinfo sysfs tree is identical before and after, CPU 1 survives
an offline/online cycle. Same on a non-RT build.
QEMU realview-eb-mpcore, ARM11 MPCore, 4 CPUs, ARMv6 plus ARMv7 SMP
kernel with PREEMPT_RT: fetch_cache_info() returns -EOPNOTSUPP through
the CTR format check, no message, no cacheinfo before or after, CPU
hotplug works, kernel messages otherwise identical.
Raspberry Pi 400, four Cortex-A72 CPUs, 32-bit PREEMPT_RT 7.2.6-rc1,
full series: the boot warning is absent and all 12 cache sysfs entries
match the unpatched baseline and earlier topology-only run. The live
DT describes the shared L2, exercising DT-based early allocation.
CPU hotplug is unavailable on this platform.
arch/arm/kernel/topology.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 2336ee2aa44a..e6b50cd43ce5 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -12,6 +12,7 @@
*/
#include <linux/arch_topology.h>
+#include <linux/cacheinfo.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
@@ -238,8 +239,20 @@ void store_cpu_topology(unsigned int cpuid)
*/
void __init init_cpu_topology(void)
{
+ int cpu, ret;
+
reset_cpu_topology();
smp_wmb();
parse_dt_topology();
+
+ for_each_possible_cpu(cpu) {
+ ret = fetch_cache_info(cpu);
+ if (!ret)
+ continue;
+ /* CPUs without a usable CLIDR return -EOPNOTSUPP. */
+ if (ret != -ENOENT && ret != -EOPNOTSUPP)
+ pr_err("Early cacheinfo failed, ret = %d\n", ret);
+ return;
+ }
}
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] ARM: cacheinfo: count external caches in early_cache_level()
2026-09-12 19:55 ` [PATCH 2/4] ARM: cacheinfo: count external caches in early_cache_level() Karl Mehltretter
@ 2026-09-12 20:09 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-09-12 20:09 UTC (permalink / raw)
To: Karl Mehltretter; +Cc: linux-rt-devel, linux-kernel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Reallocation of cacheinfo memory via kzalloc_objs(..., GFP_ATOMIC) is called with interrupts disabled on secondary CPUs in big.LITTLE systems, which crashes on PREEMPT_RT.
--
commit 19c5ea8e9a4a8fc2bc601139e06e4ead6e749ab2
Author: Karl Mehltretter <kmehltretter@gmail.com>
ARM: cacheinfo: count external caches in early_cache_level()
This commit alters early_cache_level() to directly invoke
init_cache_level(). This includes device tree-described external
caches in the early allocation size, attempting to avoid late cacheinfo
reallocation on secondary CPUs which causes issues on PREEMPT_RT.
> diff --git a/arch/arm/kernel/cacheinfo.c b/arch/arm/kernel/cacheinfo.c
> index 860eeb03cfe5d..31591c9472548 100644
> --- a/arch/arm/kernel/cacheinfo.c
> +++ b/arch/arm/kernel/cacheinfo.c
[ ... ]
> @@ -146,6 +139,11 @@ int init_cache_level(unsigned int cpu)
> return 0;
> }
>
> +int early_cache_level(unsigned int cpu)
> +{
> + return init_cache_level(cpu);
> +}
[Severity: High]
This is a pre-existing issue, but does this CLIDR fallback path still leave
the kernel vulnerable to a panic on PREEMPT_RT if a secondary CPU happens to
have more cache leaves than the boot CPU?
On big.LITTLE ARM systems, if a secondary CPU has more cache leaves and no
device-tree cache specification is used, early_leaves will be smaller than
the required size. This forces a reallocation while interrupts are disabled
on the secondary CPU:
arch/arm/kernel/smp.c:secondary_start_kernel() {
...
trace_hardirqs_off();
...
update_siblings_masks(cpu);
}
drivers/base/arch_topology.c:update_siblings_masks() {
...
ret = detect_cache_attributes(cpuid);
}
drivers/base/cacheinfo.c:init_level_allocate_ci() {
...
if (cache_leaves(cpu) <= early_leaves && per_cpu_cacheinfo(cpu))
return 0;
kfree(per_cpu_cacheinfo(cpu));
return allocate_cache_info(cpu);
}
drivers/base/cacheinfo.c:allocate_cache_info() {
...
per_cpu_cacheinfo(cpu) = kzalloc_objs(struct cacheinfo,
cache_leaves(cpu), GFP_ATOMIC);
}
On PREEMPT_RT, memory allocation with GFP_ATOMIC relies on a sleepable
slab rt_mutex. Calling this with interrupts disabled results in a BUG
("sleeping function called from invalid context") and a system panic
during boot.
Could this reallocation path be avoided or deferred to a context where
interrupts are enabled for secondary CPUs?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260912195552.76673-1-kmehltretter@gmail.com?part=2
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-12 20:09 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-12 19:55 [PATCH 0/4] ARM: allocate the cacheinfo early to fix the PREEMPT_RT boot warning Karl Mehltretter
2026-09-12 19:55 ` [PATCH 1/4] ARM: cacheinfo: avoid out-of-bounds write in populate_cache_leaves() Karl Mehltretter
2026-09-12 19:55 ` [PATCH 2/4] ARM: cacheinfo: count external caches in early_cache_level() Karl Mehltretter
2026-09-12 20:09 ` sashiko-bot
2026-09-12 19:55 ` [PATCH 3/4] ARM: cacheinfo: guard the CLIDR read in populate_cache_leaves() Karl Mehltretter
2026-09-12 19:55 ` [PATCH 4/4] ARM: topology: allocate the cacheinfo early on the boot CPU Karl Mehltretter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®