Re: [PATCH] arm64: Defer the GMID_EL1 read to {init,update}_cpu_features()

From: Fuad Tabba

Date: Sun Aug 23 2026 - 09:09:51 EST


Hi Marc,

On Sat, 22 Aug 2026 at 10:13, Marc Zyngier <maz@xxxxxxxxxx> wrote:
>
> On Wed, 19 Aug 2026 15:25:58 +0100,
> Fuad Tabba <fuad.tabba@xxxxxxxxx> wrote:
> >
> > __cpuinfo_store_cpu() gates the GMID_EL1 read on the raw
> > ID_AA64PFR1_EL1, so it reads the register on MTE hardware even when the
> > kernel has disabled MTE (CONFIG_ARM64_MTE=n or arm64.nomte). KVM sets
> > HCR_EL2.TID5 in that case, which traps the read to EL2 and injects an
> > UNDEF:
> >
> > Internal error: Oops - Undefined instruction: 0000000002000000 [#1]
> > pc : __cpuinfo_store_cpu+0xf4/0x264
> > Call trace:
> > __cpuinfo_store_cpu+0xf4/0x264 (P)
> > secondary_start_kernel+0xc8/0x1d0
> > __secondary_switched+0xc0/0xc4
> > Kernel panic - not syncing: Attempted to kill the idle task!
> >
> > Only pKVM is affected, and only for a CPU onlined after KVM init: its
>
> Is that for a CPU that has gone through a an offline/online cycle?
> Because otherwise, such a CPU wouldn't be able to boot at all (we have
> a strong requirement that pKVM sees all CPUs at boot time).
>
> If that's the case, some clarification would be good. Otherwise, some
> clarification is absolutely required! ;-)

Yes, an offline/online cycle: every CPU's first bring-up happens
before KVM's initcall, so hotplug is the only way to reach
cpuinfo_store_cpu() with TID5 set. I'll say so in v2, along with a
note on the reproducer (offline then online CPU1 with arm64.nomte, on
QEMU with MTE enabled).

As a side note, to answer a question Will asked me offlist, it's not
an issue in any of the Android versions: Android 17 (and earlier)
never gets the trap. The Android commit that disables MTE there does
the HCR_ATA hunks only, and there is no handle_host_mte() either, so
the read is untrapped.

> > PSCI CPU_ON relay sets the host HCR before the CPU enters EL1, whereas
> > plain nVHE sets it at CPUHP_AP_KVM_ONLINE, after cpuinfo_store_cpu().
> >
> > Defer the read to {init,update}_cpu_features() and gate it on the
> > sanitised ID register, as MPAM already does. system_supports_mte()
> > cannot serve as the gate, as update_cpu_features() also runs during
> > initial SMP bring-up, before smp_cpus_done() calls
> > setup_system_features(). The init path gains the CONFIG_ARM64_MTE test
> > the update path already had, leaving SYS_GMID_EL1 uninitialised when
> > MTE is compiled out, where its only other user (lib/mte.S) is not
> > built.
>
> I'm starting to wonder whether having CPUs to go through a feature
> collection process during an offline/online cycle is a good idea. The
> data should still be there, and is not expected to change.
>
> Is it just that we don't have the correct tracking information?

I think you're right. Nothing on the arm64 side tells a re-online from
a first boot, so secondary_start_kernel() collects everything again.
The tracking is there I think: notify_cpu_starting() sets
cpus_booted_once_mask, and it runs right after cpuinfo_store_cpu(), so
the mask is usable at that point. Gating cpuinfo_store_cpu() on it
would skip the collection and the cross-check against the boot CPU on
a re-online, and leave the verification in
check_local_cpu_capabilities() as is.

That changes what hotplug does on every arm64 system, so I'll send
this other patch after the merge window, and keep the current one as
the narrow fix for stable (the trap is in 7.0 onwards). Does that
work?

Cheers,
/fuad

> Thanks,
>
> M.
>
> --
> Without deviation from the norm, progress is not possible.