From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A543402B8A for ; Fri, 31 Jul 2026 14:43:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785508987; cv=none; b=OiVcc3+vsTLRg2h3hz4V8FxYERVTlkVnIWHYaax8TdEKU6EiYpLi9hcGuOokBvtMHDHswVvxLEqjsLgziKWvMTAwEtHmtxwrvJGWxIl1YwUnixvRuayF/OX86dnLsHzLgjdVGRG3jf3UpfP2jNs7FslHctRP8fksbTBALRK/faA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785508987; c=relaxed/simple; bh=8i7Sevnv258M54JW7rw4cQoD/c8GZN+tnalTlj/Wajs=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=clvuXRLGvXY6lMHco7SuvD1j/doUeW6q/EaFsDEn7rSnWokpVWveqfx16XYm09juk+C/fwvuTzWklTWHo/V1XbtCOsc9EhIoAobm2FhYjrCxOmRKY0zqXA61GflwKdrWrA53lF+iUG4PQqpLqa3AD6gmzjGPwSBCo+es95REf8M= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TZIl3IsX; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TZIl3IsX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 25A271F000E9; Fri, 31 Jul 2026 14:43:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785508985; bh=9+qGFmMCXxXQZUlVzsydvaIqjrBJVb6+5+UuTkV7tvA=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=TZIl3IsXiSU+hgVXvm1gocGrPNPPEgz0n3o7mA/lxvs9aBT09pIYUytCvkHUd2cmv fee5TXMLe0SV1LKGw0GitCNzyAowetwG5lc1gRlm3w7+d5q+470L0XrneX0SLckVx7 ELPswYs/7Y/pSSsrRRAbzexJu8x/1AKhNtFBsL/Lk3W89xgD1dL5cVT6YB0MZBciYT 2zsJZjuqrAcqlmBKDvJMMawaWEBsJM6xv4NGR8Z7hz3qTaSV0CZTFFWpfcKjTU1QPn lB10Ebt5/DuJ953OG5T+/T5Kmk4Uvo/8BIC4IVATvEJ86ghWB541erc0mzccbyg4eS EroTjBT+69CvA== Date: Fri, 31 Jul 2026 15:43:01 +0100 From: Will Deacon To: Aman Priyadarshi Cc: catalin.marinas@arm.com, Jason@zx2c4.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Ard Biesheuvel Subject: Re: [PATCH] arm64: archrandom: avoid trapping ID register read in __cpu_has_rng() Message-ID: References: <20260720140615.99343-1-amanp@apple.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260720140615.99343-1-amanp@apple.com> Hi Aman, On Mon, Jul 20, 2026 at 03:06:15PM +0100, Aman Priyadarshi wrote: > __cpu_has_rng() has an early-boot fallback, taken before the > ARM64_HAS_RNG alternative is patched, that calls > this_cpu_has_cap(ARM64_HAS_RNG). With SCOPE_LOCAL_CPU that resolves the > capability by reading ID_AA64ISAR0_EL1 directly from hardware via > __read_sysreg_by_encoding(), on every invocation. > > Until the CRNG is seeded, crng_make_state() routes every get_random_*() > through extract_entropy(), which drains architectural entropy via > arch_get_random_seed_longs()/arch_get_random_longs() and so calls > __cpu_has_rng() several times per request. On a direct (non-EFI) boot > there is no bootloader seed, so the CRNG stays unseeded for much of > boot and essentially every early randomness consumer takes this path. > > Under virtualization this is costly: the hypervisor traps guest > accesses to the ID registers (HCR_EL2.TID3), making each read a vmexit, > producing ~200k trapped ID_AA64ISAR0_EL1 reads during boot. > > The register value is invariant, so read the sanitised feature register > instead. read_sanitised_ftr_reg() returns the cached value from > arm64_ftr_regs[] with no sysreg access, and hence no trap. That array > is populated by cpuinfo_store_boot_cpu() in smp_prepare_boot_cpu(), > before the first early RNG use in random_init_early(), so it is always > valid here. > > With this change the trapped reads drop from ~200k to handful number of > times, and the boot time drops roughly by 6.3% in the test environment. Yikes, that's quite a compelling performance improvement. > 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? Will --->8 diff --git a/arch/arm64/include/asm/archrandom.h b/arch/arm64/include/asm/archrandom.h index 8babfbe31f95..1c6ccc1776cd 100644 --- a/arch/arm64/include/asm/archrandom.h +++ b/arch/arm64/include/asm/archrandom.h @@ -61,8 +61,17 @@ 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())) { + /* + * Query the in-memory sanitised value to avoid a potential + * trap when accessing the ID register under a hypervisor. + */ + u64 isar0 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR0_EL1); + u64 rndr = SYS_FIELD_GET(ID_AA64ISAR0_EL1, RNDR, isar0); + + return rndr >= ID_AA64ISAR0_EL1_RNDR_IMP; + } + return alternative_has_cap_unlikely(ARM64_HAS_RNG); }