[PATCH v7 5/7] arm64: Add support for FEAT_{LS64, LS64_V}

Suzuki K Poulose suzuki.poulose at arm.com
Fri Nov 7 04:05:18 PST 2025


On 07/11/2025 07:21, Zhou Wang wrote:
> From: Yicong Yang <yangyicong at hisilicon.com>
> 
> Armv8.7 introduces single-copy atomic 64-byte loads and stores
> instructions and its variants named under FEAT_{LS64, LS64_V}.
> These features are identified by ID_AA64ISAR1_EL1.LS64 and the
> use of such instructions in userspace (EL0) can be trapped. In
> order to support the use of corresponding instructions in userspace:
> - Make ID_AA64ISAR1_EL1.LS64 visbile to userspace
> - Add identifying and enabling in the cpufeature list
> - Expose these support of these features to userspace through HWCAP3
>    and cpuinfo
> 
> ld64b/st64b (FEAT_LS64) and st64bv (FEAT_LS64_V) is intended for
> special memory (device memory) so requires support by the CPU, system
> and target memory location (device that support these instructions).
> The HWCAP3_{LS64, LS64_V} implies the support of CPU and system (since
> no identification method from system, so SoC vendors should advertise
> support in the CPU if system also support them).
> 
> Otherwise for ld64b/st64b the atomicity may not be guaranteed or a
> DABT will be generated, so users (probably userspace driver developer)
> should make sure the target memory (device) also have the support.
> For st64bv 0xffffffffffffffff will be returned as status result for
> unsupported memory so user should check it.
> 
> Document the restrictions along with HWCAP3_{LS64, LS64_V}.
> 
> Signed-off-by: Yicong Yang <yangyicong at hisilicon.com>
> Signed-off-by: Zhou Wang <wangzhou1 at hisilicon.com>
> ---
>   Documentation/arch/arm64/booting.rst    | 12 ++++++
>   Documentation/arch/arm64/elf_hwcaps.rst | 14 +++++++
>   arch/arm64/include/asm/hwcap.h          |  2 +
>   arch/arm64/include/uapi/asm/hwcap.h     |  2 +
>   arch/arm64/kernel/cpufeature.c          | 51 +++++++++++++++++++++++++
>   arch/arm64/kernel/cpuinfo.c             |  2 +
>   arch/arm64/tools/cpucaps                |  2 +
>   7 files changed, 85 insertions(+)
> 
> diff --git a/Documentation/arch/arm64/booting.rst b/Documentation/arch/arm64/booting.rst
> index e4f953839f71..2c56d76ecafb 100644
> --- a/Documentation/arch/arm64/booting.rst
> +++ b/Documentation/arch/arm64/booting.rst
> @@ -556,6 +556,18 @@ Before jumping into the kernel, the following conditions must be met:
>   
>      - MDCR_EL3.TPM (bit 6) must be initialized to 0b0
>   
> +  For CPUs with support for 64-byte loads and stores without status (FEAT_LS64):
> +
> +  - If the kernel is entered at EL1 and EL2 is present:
> +
> +    - HCRX_EL2.EnALS (bit 1) must be initialised to 0b1.
> +
> +  For CPUs with support for 64-byte stores with status (FEAT_LS64_V):
> +
> +  - If the kernel is entered at EL1 and EL2 is present:
> +
> +    - HCRX_EL2.EnASR (bit 2) must be initialised to 0b1.
> +
>   The requirements described above for CPU mode, caches, MMUs, architected
>   timers, coherency and system registers apply to all CPUs.  All CPUs must
>   enter the kernel in the same exception level.  Where the values documented
> diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst
> index a15df4956849..b86059bc288b 100644
> --- a/Documentation/arch/arm64/elf_hwcaps.rst
> +++ b/Documentation/arch/arm64/elf_hwcaps.rst
> @@ -444,6 +444,20 @@ HWCAP3_MTE_STORE_ONLY
>   HWCAP3_LSFE
>       Functionality implied by ID_AA64ISAR3_EL1.LSFE == 0b0001
>   
> +HWCAP3_LS64
> +    Functionality implied by ID_AA64ISAR1_EL1.LS64 == 0b0001. Note that
> +    the function of instruction ld64b/st64b requires support by CPU, system
> +    and target (device) memory location and HWCAP3_LS64 implies the support
> +    of CPU. User should only use ld64b/st64b on supported target (device)
> +    memory location, otherwise fallback to the non-atomic alternatives.
> +
> +HWCAP3_LS64_V
> +    Functionality implied by ID_AA64ISAR1_EL1.LS64 == 0b0010. Same to
> +    HWCAP3_LS64 that HWCAP3_LS64_V implies CPU's support of instruction
> +    st64bv but also requires the support from the system and target (device)
> +    memory location. st64bv supports return status result and 0xFFFFFFFFFFFFFFFF
> +    will be returned for unsupported memory location.
> +
>   
>   4. Unused AT_HWCAP bits
>   -----------------------
> diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
> index 6d567265467c..3c0804fb3435 100644
> --- a/arch/arm64/include/asm/hwcap.h
> +++ b/arch/arm64/include/asm/hwcap.h
> @@ -179,6 +179,8 @@
>   #define KERNEL_HWCAP_MTE_FAR		__khwcap3_feature(MTE_FAR)
>   #define KERNEL_HWCAP_MTE_STORE_ONLY	__khwcap3_feature(MTE_STORE_ONLY)
>   #define KERNEL_HWCAP_LSFE		__khwcap3_feature(LSFE)
> +#define KERNEL_HWCAP_LS64		__khwcap3_feature(LS64)
> +#define KERNEL_HWCAP_LS64_V		__khwcap3_feature(LS64_V)
>   
>   /*
>    * This yields a mask that user programs can use to figure out what
> diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
> index 575564ecdb0b..79bc77425b82 100644
> --- a/arch/arm64/include/uapi/asm/hwcap.h
> +++ b/arch/arm64/include/uapi/asm/hwcap.h
> @@ -146,5 +146,7 @@
>   #define HWCAP3_MTE_FAR		(1UL << 0)
>   #define HWCAP3_MTE_STORE_ONLY		(1UL << 1)
>   #define HWCAP3_LSFE		(1UL << 2)
> +#define HWCAP3_LS64		(1UL << 3)
> +#define HWCAP3_LS64_V		(1UL << 4)
>   
>   #endif /* _UAPI__ASM_HWCAP_H */
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 5ed401ff79e3..dcc5ba620a7e 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -239,6 +239,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
>   };
>   
>   static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
> +	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_LS64_SHIFT, 4, 0),
>   	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_XS_SHIFT, 4, 0),
>   	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_I8MM_SHIFT, 4, 0),
>   	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_DGH_SHIFT, 4, 0),
> @@ -2259,6 +2260,38 @@ static void cpu_enable_e0pd(struct arm64_cpu_capabilities const *cap)
>   }
>   #endif /* CONFIG_ARM64_E0PD */
>   
> +static bool has_ls64(const struct arm64_cpu_capabilities *entry, int __unused)
> +{
> +	u64 ls64;
> +
> +	ls64 = cpuid_feature_extract_field(__read_sysreg_by_encoding(entry->sys_reg),
> +					   entry->field_pos, entry->sign);

Why are we always reading from the "local" CPU ? Shouldn't this be based 
on the SCOPE ?

i.e., read from the sanitised feature state for SCOPE_SYSTEM (given that 
is the SCOPE for the capability)

and read from the local CPU for SCOPE_LOCAL (for checks in late CPUs).


> +
> +	if (ls64 == ID_AA64ISAR1_EL1_LS64_NI ||
> +	    ls64 > ID_AA64ISAR1_EL1_LS64_LS64_ACCDATA)

Given this is FTR_LOWER_SAFE, why do we skip anything that is HIGHER 
than a particular value ? You must be able to fall back to the 
has_cpuid_feature() check for both these CAPs.


> +		return false;
> +



---8>---

> +	if (entry->capability == ARM64_HAS_LS64 &&
> +	    ls64 >= ID_AA64ISAR1_EL1_LS64_LS64)
> +		return true;
> +
> +	if (entry->capability == ARM64_HAS_LS64_V &&
> +	    ls64 >= ID_AA64ISAR1_EL1_LS64_LS64_V)
> +		return true;
> +
> +	return false;

--<8---


minor nit: You could simplify this to:

	return (ls64 >= entry->min_field_value)


Suzuki



More information about the linux-arm-kernel mailing list