Re: [PATCH] arm64: archrandom: avoid trapping ID register read in __cpu_has_rng()
Will Deacon <[email protected]> Tue, 4 Aug 2026 15:56:17 +0100
| Newsgroups | gmane.linux.kernel,gmane.linux.ports.arm.kernel |
|---|---|
| Message-ID | <anH9kVWFN_dqA0c1@willie-the-truck> |
On Fri, Jul 31, 2026 at 06:26:44PM +0100, Aman Priyadarshi wrote: > > On 31 Jul 2026, at 15:43, Will Deacon <[email protected]> wrote: > > On Mon, Jul 20, 2026 at 03:06:15PM +0100, Aman Priyadarshi wrote: > >> diff --git a/arch/arm64/include/asm/archrandom.h b/arch/arm64/include/asm/archrandom.h > >> index 8babfbe31f95..8067e9a35641 100644 > >> --- a/arch/arm64/include/asm/archrandom.h > >> +++ b/arch/arm64/include/asm/archrandom.h > >> @@ -61,8 +61,22 @@ static inline bool __arm64_rndrrs(unsigned long *v) > >> > >> static __always_inline bool __cpu_has_rng(void) > >> { > >> - if (unlikely(!system_capabilities_finalized() && !preemptible())) > >> - return this_cpu_has_cap(ARM64_HAS_RNG); > >> + if (unlikely(!system_capabilities_finalized() && !preemptible())) { > >> + /* > >> + * Until the ARM64_HAS_RNG alternative is patched we can't use > >> + * the static-branch form, so consult the feature register > >> + * directly. Don't use this_cpu_has_cap() here: it reads > >> + * ID_AA64ISAR0_EL1 from hardware on every call, under > >> + * virtualization each ID register read traps to the hypervisor > >> + * (HCR_EL2.TID3) -- producing a storm of vmexits during boot. > >> + * The sanitised value is cached in memory. > >> + */ > >> + u64 isar0 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR0_EL1); > >> + > >> + return cpuid_feature_extract_unsigned_field(isar0, > >> + ID_AA64ISAR0_EL1_RNDR_SHIFT) >= > >> + ID_AA64ISAR0_EL1_RNDR_IMP; > >> + } > > > > You can probably rewrite this a little more cleanly along the lines of > > the (not even compile-tested) diff below. I was about to do that, but > > then I got a bit confused by the whole thing. The preemptible() check is > > presumably not needed if we're accessing the in-memory feature registers > > rather than the per-CPU id registers, but then how do you handle races > > with concurrent updates to the "safe value" made by CPUs concurrently > > coming online? > > I kept preemptible() check for this exact reason: the updates made by CPUs > concurrently coming online will always take the downgrade path (a secondary > CPU can clear RNDR, never set it), and therefore by taking the non-preemptible > branch I can guarantee that the pinned CPU supports the said feature. > I agree, this assumes that a secondary CPU folds its own ID registers into sys_val > before it can ever be a randomness consumer, but looking at the code that seems > the case, please feel free to correct me. > Besides, in my opinion, it's hard to argue correctness of this code without > preemptible() check. My point is that this change introduces a data race on 'reg->sys_val' for the ID_AA64ISAR0_EL1 entry in the arm64_ftr_regs array. Will