diff mbox series

[2/6] arm64: HWCAP: add support for ELF_HWCAP2

Message ID 1549459868-45992-3-git-send-email-andrew.murray@arm.com (mailing list archive)
State New, archived
Headers show
Series Initial support for CVADP | expand

Commit Message

Andrew Murray Feb. 6, 2019, 1:31 p.m. UTC
As we will exhaust the first 32 bits of ELF_HWCAP let's start
exposing ELF_HWCAP2 to userspace.

Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we
prefer to expand into ELF_HWCAP2 in order to provide a consistent
view to userspace between ILP32 and LP64.

To reduce complexity and allow for future expansion, we now
represent hwcaps in the kernel as ordinals and use a
KERNEL_HWCAP_ prefix. This allows us to support automatic feature
based module loading for all our hwcaps.

We introduce cpu_set_feature to set hwcaps in the relevant
elf_hwcapX variable which compliments the existing cpu_have_feature
helper. These helpers allow us to clean up existing direct uses of
elf_hwcap.

Signed-off-by: Andrew Murray <andrew.murray@arm.com>
---
 arch/arm64/crypto/aes-ce-ccm-glue.c      |  2 +-
 arch/arm64/crypto/aes-neonbs-glue.c      |  2 +-
 arch/arm64/crypto/chacha-neon-glue.c     |  2 +-
 arch/arm64/crypto/crct10dif-ce-glue.c    |  2 +-
 arch/arm64/crypto/ghash-ce-glue.c        |  6 +--
 arch/arm64/crypto/nhpoly1305-neon-glue.c |  2 +-
 arch/arm64/crypto/sha256-glue.c          |  4 +-
 arch/arm64/include/asm/cpufeature.h      | 18 +++++++--
 arch/arm64/include/asm/hwcap.h           | 41 ++++++++++++++++++-
 arch/arm64/include/uapi/asm/hwcap.h      |  2 +-
 arch/arm64/kernel/cpufeature.c           | 69 +++++++++++++++++---------------
 arch/arm64/kernel/cpuinfo.c              |  2 +-
 arch/arm64/kernel/fpsimd.c               |  4 +-
 drivers/clocksource/arm_arch_timer.c     |  8 ++++
 14 files changed, 111 insertions(+), 53 deletions(-)

Comments

Dave Martin Feb. 7, 2019, 11:31 a.m. UTC | #1
On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote:
> As we will exhaust the first 32 bits of ELF_HWCAP let's start
> exposing ELF_HWCAP2 to userspace.
> 
> Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we
> prefer to expand into ELF_HWCAP2 in order to provide a consistent
> view to userspace between ILP32 and LP64.
> 
> To reduce complexity and allow for future expansion, we now
> represent hwcaps in the kernel as ordinals and use a
> KERNEL_HWCAP_ prefix. This allows us to support automatic feature
> based module loading for all our hwcaps.
> 
> We introduce cpu_set_feature to set hwcaps in the relevant
> elf_hwcapX variable which compliments the existing cpu_have_feature
> helper. These helpers allow us to clean up existing direct uses of
> elf_hwcap.
> 
> Signed-off-by: Andrew Murray <andrew.murray@arm.com>
> ---

[...]

> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index dfcfba7..15d939e 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -18,11 +18,10 @@
>   * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
>   * in the kernel and for user space to keep track of which optional features
>   * are supported by the current system. So let's map feature 'x' to HWCAP_x.
> - * Note that HWCAP_x constants are bit fields so we need to take the log.
>   */
>  
> -#define MAX_CPU_FEATURES	(8 * sizeof(elf_hwcap))
> -#define cpu_feature(x)		ilog2(HWCAP_ ## x)
> +#define MAX_CPU_FEATURES	(2 * 8 * sizeof(unsigned long))

Doesn't this make 2 * 8 * 8 == 128?

Maybe just say "64".  We open-code 32 later anyway.

> +#define cpu_feature(x)		(KERNEL_HWCAP_ ## x)
>  
>  #ifndef __ASSEMBLY__
>  
> @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready;
>  
>  bool this_cpu_has_cap(unsigned int cap);
>  
> +static inline void cpu_set_feature(unsigned int num)
> +{
> +	if (num < 32)
> +		elf_hwcap |= BIT(num);
> +	else
> +		elf_hwcap2 |= BIT(num - 32);
> +}
> +
>  static inline bool cpu_have_feature(unsigned int num)
>  {
> -	return elf_hwcap & (1UL << num);
> +	if (num < 32)
> +		return elf_hwcap & BIT(num);
> +	else
> +		return elf_hwcap2 & BIT(num - 32);
>  }

Nit: I worry a bit that people will blithely pass HWCAP_foo to these,
not realising that the interface has changed.

Can we do something like the following:

static inline bool __cpu_have_feature(unsigned int num)
{
	if (WARN_ON(num >= 64))
		return false;

	if (num < 32)
		return elf_hwcap & BIT(num);
	else
		return elf_hwcap2 & BIT(num);
}

#define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name))


In compiletime-constant cases, the compiler should simply delete the
WARN.  A couple of cases in the cpufeatures and /proc/cpuinfo code would
need to use __cpu_have_feature directly and would retain the WARN, but
that's not fastpath and probably not the end of the world, plus we
get an additional debugging aid if that code goes wrong.

Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making
it impossible to specify invalid or user-encoded hwcaps there either.
Then we might justifiably omit the policing in __cpu_have_feature()
altogether.

>  
>  /* System capability check for constant caps */
> diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
> index 400b80b..05ee9b9 100644
> --- a/arch/arm64/include/asm/hwcap.h
> +++ b/arch/arm64/include/asm/hwcap.h
> @@ -39,12 +39,49 @@
>  #define COMPAT_HWCAP2_SHA2	(1 << 3)
>  #define COMPAT_HWCAP2_CRC32	(1 << 4)
>  
> +/*
> + * KERNEL_HWCAP flags - for elf_hwcap (in kernel)
> + */
> +#define KERNEL_HWCAP_FP                ilog2(HWCAP_FP)
> +#define KERNEL_HWCAP_ASIMD             ilog2(HWCAP_ASIMD)
> +#define KERNEL_HWCAP_EVTSTRM           ilog2(HWCAP_EVTSTRM)
> +#define KERNEL_HWCAP_AES               ilog2(HWCAP_AES)
> +#define KERNEL_HWCAP_PMULL             ilog2(HWCAP_PMULL)
> +#define KERNEL_HWCAP_SHA1              ilog2(HWCAP_SHA1)
> +#define KERNEL_HWCAP_SHA2              ilog2(HWCAP_SHA2)
> +#define KERNEL_HWCAP_CRC32             ilog2(HWCAP_CRC32)
> +#define KERNEL_HWCAP_ATOMICS           ilog2(HWCAP_ATOMICS)
> +#define KERNEL_HWCAP_FPHP              ilog2(HWCAP_FPHP)
> +#define KERNEL_HWCAP_ASIMDHP           ilog2(HWCAP_ASIMDHP)
> +#define KERNEL_HWCAP_CPUID             ilog2(HWCAP_CPUID)
> +#define KERNEL_HWCAP_ASIMDRDM          ilog2(HWCAP_ASIMDRDM)
> +#define KERNEL_HWCAP_JSCVT             ilog2(HWCAP_JSCVT)
> +#define KERNEL_HWCAP_FCMA              ilog2(HWCAP_FCMA)
> +#define KERNEL_HWCAP_LRCPC             ilog2(HWCAP_LRCPC)
> +#define KERNEL_HWCAP_DCPOP             ilog2(HWCAP_DCPOP)
> +#define KERNEL_HWCAP_SHA3              ilog2(HWCAP_SHA3)
> +#define KERNEL_HWCAP_SM3               ilog2(HWCAP_SM3)
> +#define KERNEL_HWCAP_SM4               ilog2(HWCAP_SM4)
> +#define KERNEL_HWCAP_ASIMDDP           ilog2(HWCAP_ASIMDDP)
> +#define KERNEL_HWCAP_SHA512            ilog2(HWCAP_SHA512)
> +#define KERNEL_HWCAP_SVE               ilog2(HWCAP_SVE)
> +#define KERNEL_HWCAP_ASIMDFHM          ilog2(HWCAP_ASIMDFHM)
> +#define KERNEL_HWCAP_DIT               ilog2(HWCAP_DIT)
> +#define KERNEL_HWCAP_USCAT             ilog2(HWCAP_USCAT)
> +#define KERNEL_HWCAP_ILRCPC            ilog2(HWCAP_ILRCPC)
> +#define KERNEL_HWCAP_FLAGM             ilog2(HWCAP_FLAGM)
> +#define KERNEL_HWCAP_SSBS              ilog2(HWCAP_SSBS)
> +#define KERNEL_HWCAP_SB                ilog2(HWCAP_SB)
> +#define KERNEL_HWCAP_PACA              ilog2(HWCAP_PACA)
> +#define KERNEL_HWCAP_PACG              ilog2(HWCAP_PACG)

Nit: Odd spacing?  Personally I wouldn't indent with spaces just so that
(ilog2() + 32) lines up nicely, but that's just my opinion and not a
huge deal.

(The spacing can make subsequent diffs look jagged by default, which
can be a distraction for reviewers.)

> +
>  #ifndef __ASSEMBLY__
>  /*
>   * This yields a mask that user programs can use to figure out what
>   * instruction set this cpu supports.
>   */
> -#define ELF_HWCAP		(elf_hwcap)
> +#define ELF_HWCAP		elf_hwcap
> +#define ELF_HWCAP2		elf_hwcap2

Do we need elf_hwcap2 at all?

We could just have these macros fish the bits out of a single variable,
or wherever.

However, it may be better to keep things this way if we want to maintain
the elf_hwcap in the kernel/module ABI.  See note on EXPORT_SYMBOL_GPL()
removal for elf_hwcap in the subsequent patch.

>  
>  #ifdef CONFIG_COMPAT
>  #define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
> @@ -60,6 +97,6 @@ enum {
>  #endif
>  };
>  
> -extern unsigned long elf_hwcap;
> +extern unsigned long elf_hwcap, elf_hwcap2;
>  #endif
>  #endif
> diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
> index 5f0750c..453b45a 100644
> --- a/arch/arm64/include/uapi/asm/hwcap.h
> +++ b/arch/arm64/include/uapi/asm/hwcap.h
> @@ -18,7 +18,7 @@
>  #define _UAPI__ASM_HWCAP_H
>  
>  /*
> - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
> + * HWCAP flags - for AT_HWCAP
>   */
>  #define HWCAP_FP		(1 << 0)
>  #define HWCAP_ASIMD		(1 << 1)
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index f6d84e2..d10a455 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -38,6 +38,9 @@
>  unsigned long elf_hwcap __read_mostly;
>  EXPORT_SYMBOL_GPL(elf_hwcap);
>  
> +unsigned long elf_hwcap2 __read_mostly;
> +EXPORT_SYMBOL_GPL(elf_hwcap2);
> +

Historically nobody used this because it didn't exist, and we don't want
anybody to use it (since cpu_have_feature() etc. is the preferred
interface).

So lose EXPORT_SYMBOL_GPL() here.  (You remove it in any case in a
subsequent patch, but having it even transiently sends mixed messages
about the intent.)

[...]

Otherwise looks reasonable.

Cheers
---Dave
Andrew Murray Feb. 18, 2019, 3:32 p.m. UTC | #2
On Thu, Feb 07, 2019 at 11:31:24AM +0000, Dave Martin wrote:
> On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote:
> > As we will exhaust the first 32 bits of ELF_HWCAP let's start
> > exposing ELF_HWCAP2 to userspace.
> > 
> > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we
> > prefer to expand into ELF_HWCAP2 in order to provide a consistent
> > view to userspace between ILP32 and LP64.
> > 
> > To reduce complexity and allow for future expansion, we now
> > represent hwcaps in the kernel as ordinals and use a
> > KERNEL_HWCAP_ prefix. This allows us to support automatic feature
> > based module loading for all our hwcaps.
> > 
> > We introduce cpu_set_feature to set hwcaps in the relevant
> > elf_hwcapX variable which compliments the existing cpu_have_feature
> > helper. These helpers allow us to clean up existing direct uses of
> > elf_hwcap.
> > 
> > Signed-off-by: Andrew Murray <andrew.murray@arm.com>
> > ---
> 
> [...]
> 
> > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> > index dfcfba7..15d939e 100644
> > --- a/arch/arm64/include/asm/cpufeature.h
> > +++ b/arch/arm64/include/asm/cpufeature.h
> > @@ -18,11 +18,10 @@
> >   * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
> >   * in the kernel and for user space to keep track of which optional features
> >   * are supported by the current system. So let's map feature 'x' to HWCAP_x.
> > - * Note that HWCAP_x constants are bit fields so we need to take the log.
> >   */
> >  
> > -#define MAX_CPU_FEATURES	(8 * sizeof(elf_hwcap))
> > -#define cpu_feature(x)		ilog2(HWCAP_ ## x)
> > +#define MAX_CPU_FEATURES	(2 * 8 * sizeof(unsigned long))
> 
> Doesn't this make 2 * 8 * 8 == 128?
> 
> Maybe just say "64".  We open-code 32 later anyway.

I guess 128 would have been correct if we use all the bits of
each ELF_HWCAP{,2} - but we chose to limit each ELF_HWCAP to be
32 bits.

I'll set this to 64 as you suggest.

> 
> > +#define cpu_feature(x)		(KERNEL_HWCAP_ ## x)
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready;
> >  
> >  bool this_cpu_has_cap(unsigned int cap);
> >  
> > +static inline void cpu_set_feature(unsigned int num)
> > +{
> > +	if (num < 32)
> > +		elf_hwcap |= BIT(num);
> > +	else
> > +		elf_hwcap2 |= BIT(num - 32);
> > +}
> > +
> >  static inline bool cpu_have_feature(unsigned int num)
> >  {
> > -	return elf_hwcap & (1UL << num);
> > +	if (num < 32)
> > +		return elf_hwcap & BIT(num);
> > +	else
> > +		return elf_hwcap2 & BIT(num - 32);
> >  }
> 
> Nit: I worry a bit that people will blithely pass HWCAP_foo to these,
> not realising that the interface has changed.

Yeah this would be an easy mistake to make.

> 
> Can we do something like the following:
> 
> static inline bool __cpu_have_feature(unsigned int num)
> {
> 	if (WARN_ON(num >= 64))
> 		return false;
> 
> 	if (num < 32)
> 		return elf_hwcap & BIT(num);
> 	else
> 		return elf_hwcap2 & BIT(num);
> }
> 
> #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name))

It took me a while to figure out what the benefit of the above line
is - this means that callers of cpu_have_feature must use the unprefixed
feature name (e.g. SHA512), anything else such as (KERNEL_HWCAP_SHA512
or HWCAP_SHA512) would result in a compile time error. Whereas without
this users could pass KERNEL_HWCAP_x or HWCAP_x without compile errors
yet resulting in incorrectly passing a bitfield when using HWCAP_x.

> 
> 
> In compiletime-constant cases, the compiler should simply delete the
> WARN.

Is this really needed? Surely this would only come into play when a user
directly calls __cpu_have_feature. I think this is overkill, especially
as __cpu_have_feature is a new function.


>  A couple of cases in the cpufeatures and /proc/cpuinfo code would
> need to use __cpu_have_feature directly and would retain the WARN, but
> that's not fastpath and probably not the end of the world, plus we
> get an additional debugging aid if that code goes wrong.

But even so, the WARN (for the cpuinfo case) is unlikely to ever be hit.

The challenge with this approach is print_cpu_modalias (drivers/base/cpu.c),
this also uses cpu_have_feature - this expects cpu_have_feature to take
an ordinal. How can we work around this?

> 
> Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making
> it impossible to specify invalid or user-encoded hwcaps there either.
> Then we might justifiably omit the policing in __cpu_have_feature()
> altogether.

This would certainly please checkpatch with respect to line lengths :)

However since this patchset, we now use cpu_have_feature elsewhere, such
as in the crypto drivers.

> 
> >  
> >  /* System capability check for constant caps */
> > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
> > index 400b80b..05ee9b9 100644
> > --- a/arch/arm64/include/asm/hwcap.h
> > +++ b/arch/arm64/include/asm/hwcap.h
> > @@ -39,12 +39,49 @@
> >  #define COMPAT_HWCAP2_SHA2	(1 << 3)
> >  #define COMPAT_HWCAP2_CRC32	(1 << 4)
> >  
> > +/*
> > + * KERNEL_HWCAP flags - for elf_hwcap (in kernel)
> > + */
> > +#define KERNEL_HWCAP_FP                ilog2(HWCAP_FP)
> > +#define KERNEL_HWCAP_ASIMD             ilog2(HWCAP_ASIMD)
> > +#define KERNEL_HWCAP_EVTSTRM           ilog2(HWCAP_EVTSTRM)
> > +#define KERNEL_HWCAP_AES               ilog2(HWCAP_AES)
> > +#define KERNEL_HWCAP_PMULL             ilog2(HWCAP_PMULL)
> > +#define KERNEL_HWCAP_SHA1              ilog2(HWCAP_SHA1)
> > +#define KERNEL_HWCAP_SHA2              ilog2(HWCAP_SHA2)
> > +#define KERNEL_HWCAP_CRC32             ilog2(HWCAP_CRC32)
> > +#define KERNEL_HWCAP_ATOMICS           ilog2(HWCAP_ATOMICS)
> > +#define KERNEL_HWCAP_FPHP              ilog2(HWCAP_FPHP)
> > +#define KERNEL_HWCAP_ASIMDHP           ilog2(HWCAP_ASIMDHP)
> > +#define KERNEL_HWCAP_CPUID             ilog2(HWCAP_CPUID)
> > +#define KERNEL_HWCAP_ASIMDRDM          ilog2(HWCAP_ASIMDRDM)
> > +#define KERNEL_HWCAP_JSCVT             ilog2(HWCAP_JSCVT)
> > +#define KERNEL_HWCAP_FCMA              ilog2(HWCAP_FCMA)
> > +#define KERNEL_HWCAP_LRCPC             ilog2(HWCAP_LRCPC)
> > +#define KERNEL_HWCAP_DCPOP             ilog2(HWCAP_DCPOP)
> > +#define KERNEL_HWCAP_SHA3              ilog2(HWCAP_SHA3)
> > +#define KERNEL_HWCAP_SM3               ilog2(HWCAP_SM3)
> > +#define KERNEL_HWCAP_SM4               ilog2(HWCAP_SM4)
> > +#define KERNEL_HWCAP_ASIMDDP           ilog2(HWCAP_ASIMDDP)
> > +#define KERNEL_HWCAP_SHA512            ilog2(HWCAP_SHA512)
> > +#define KERNEL_HWCAP_SVE               ilog2(HWCAP_SVE)
> > +#define KERNEL_HWCAP_ASIMDFHM          ilog2(HWCAP_ASIMDFHM)
> > +#define KERNEL_HWCAP_DIT               ilog2(HWCAP_DIT)
> > +#define KERNEL_HWCAP_USCAT             ilog2(HWCAP_USCAT)
> > +#define KERNEL_HWCAP_ILRCPC            ilog2(HWCAP_ILRCPC)
> > +#define KERNEL_HWCAP_FLAGM             ilog2(HWCAP_FLAGM)
> > +#define KERNEL_HWCAP_SSBS              ilog2(HWCAP_SSBS)
> > +#define KERNEL_HWCAP_SB                ilog2(HWCAP_SB)
> > +#define KERNEL_HWCAP_PACA              ilog2(HWCAP_PACA)
> > +#define KERNEL_HWCAP_PACG              ilog2(HWCAP_PACG)
> 
> Nit: Odd spacing?  Personally I wouldn't indent with spaces just so that
> (ilog2() + 32) lines up nicely, but that's just my opinion and not a
> huge deal.
> 
> (The spacing can make subsequent diffs look jagged by default, which
> can be a distraction for reviewers.)

I'll convert to tabs, I probably copy pasted and the tabs got converted.

> 
> > +
> >  #ifndef __ASSEMBLY__
> >  /*
> >   * This yields a mask that user programs can use to figure out what
> >   * instruction set this cpu supports.
> >   */
> > -#define ELF_HWCAP		(elf_hwcap)
> > +#define ELF_HWCAP		elf_hwcap
> > +#define ELF_HWCAP2		elf_hwcap2
> 
> Do we need elf_hwcap2 at all?
> 
> We could just have these macros fish the bits out of a single variable,
> or wherever.
> 
> However, it may be better to keep things this way if we want to maintain
> the elf_hwcap in the kernel/module ABI.  See note on EXPORT_SYMBOL_GPL()
> removal for elf_hwcap in the subsequent patch.

OK, I'll leave it as it is.

> 
> >  
> >  #ifdef CONFIG_COMPAT
> >  #define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
> > @@ -60,6 +97,6 @@ enum {
> >  #endif
> >  };
> >  
> > -extern unsigned long elf_hwcap;
> > +extern unsigned long elf_hwcap, elf_hwcap2;
> >  #endif
> >  #endif
> > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
> > index 5f0750c..453b45a 100644
> > --- a/arch/arm64/include/uapi/asm/hwcap.h
> > +++ b/arch/arm64/include/uapi/asm/hwcap.h
> > @@ -18,7 +18,7 @@
> >  #define _UAPI__ASM_HWCAP_H
> >  
> >  /*
> > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
> > + * HWCAP flags - for AT_HWCAP
> >   */
> >  #define HWCAP_FP		(1 << 0)
> >  #define HWCAP_ASIMD		(1 << 1)
> > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> > index f6d84e2..d10a455 100644
> > --- a/arch/arm64/kernel/cpufeature.c
> > +++ b/arch/arm64/kernel/cpufeature.c
> > @@ -38,6 +38,9 @@
> >  unsigned long elf_hwcap __read_mostly;
> >  EXPORT_SYMBOL_GPL(elf_hwcap);
> >  
> > +unsigned long elf_hwcap2 __read_mostly;
> > +EXPORT_SYMBOL_GPL(elf_hwcap2);
> > +
> 
> Historically nobody used this because it didn't exist, and we don't want
> anybody to use it (since cpu_have_feature() etc. is the preferred
> interface).

In that case I should probably EXPORT_SYMBOL_GPL cpu_have_feature.

> 
> So lose EXPORT_SYMBOL_GPL() here.  (You remove it in any case in a
> subsequent patch, but having it even transiently sends mixed messages
> about the intent.)

No problem.

> 
> [...]
> 
> Otherwise looks reasonable.

Thanks for the review.

Andrew Murray

> 
> Cheers
> ---Dave
Dave Martin Feb. 18, 2019, 4:02 p.m. UTC | #3
On Mon, Feb 18, 2019 at 03:32:06PM +0000, Andrew Murray wrote:
> On Thu, Feb 07, 2019 at 11:31:24AM +0000, Dave Martin wrote:
> > On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote:
> > > As we will exhaust the first 32 bits of ELF_HWCAP let's start
> > > exposing ELF_HWCAP2 to userspace.
> > > 
> > > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we
> > > prefer to expand into ELF_HWCAP2 in order to provide a consistent
> > > view to userspace between ILP32 and LP64.
> > > 
> > > To reduce complexity and allow for future expansion, we now
> > > represent hwcaps in the kernel as ordinals and use a
> > > KERNEL_HWCAP_ prefix. This allows us to support automatic feature
> > > based module loading for all our hwcaps.
> > > 
> > > We introduce cpu_set_feature to set hwcaps in the relevant
> > > elf_hwcapX variable which compliments the existing cpu_have_feature
> > > helper. These helpers allow us to clean up existing direct uses of
> > > elf_hwcap.
> > > 
> > > Signed-off-by: Andrew Murray <andrew.murray@arm.com>
> > > ---
> > 
> > [...]
> > 
> > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> > > index dfcfba7..15d939e 100644
> > > --- a/arch/arm64/include/asm/cpufeature.h
> > > +++ b/arch/arm64/include/asm/cpufeature.h
> > > @@ -18,11 +18,10 @@
> > >   * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
> > >   * in the kernel and for user space to keep track of which optional features
> > >   * are supported by the current system. So let's map feature 'x' to HWCAP_x.
> > > - * Note that HWCAP_x constants are bit fields so we need to take the log.
> > >   */
> > >  
> > > -#define MAX_CPU_FEATURES	(8 * sizeof(elf_hwcap))
> > > -#define cpu_feature(x)		ilog2(HWCAP_ ## x)
> > > +#define MAX_CPU_FEATURES	(2 * 8 * sizeof(unsigned long))
> > 
> > Doesn't this make 2 * 8 * 8 == 128?
> > 
> > Maybe just say "64".  We open-code 32 later anyway.
> 
> I guess 128 would have been correct if we use all the bits of
> each ELF_HWCAP{,2} - but we chose to limit each ELF_HWCAP to be
> 32 bits.
> 
> I'll set this to 64 as you suggest.
> 
> > 
> > > +#define cpu_feature(x)		(KERNEL_HWCAP_ ## x)
> > >  
> > >  #ifndef __ASSEMBLY__
> > >  
> > > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready;
> > >  
> > >  bool this_cpu_has_cap(unsigned int cap);
> > >  
> > > +static inline void cpu_set_feature(unsigned int num)
> > > +{
> > > +	if (num < 32)
> > > +		elf_hwcap |= BIT(num);
> > > +	else
> > > +		elf_hwcap2 |= BIT(num - 32);
> > > +}
> > > +
> > >  static inline bool cpu_have_feature(unsigned int num)
> > >  {
> > > -	return elf_hwcap & (1UL << num);
> > > +	if (num < 32)
> > > +		return elf_hwcap & BIT(num);
> > > +	else
> > > +		return elf_hwcap2 & BIT(num - 32);
> > >  }
> > 
> > Nit: I worry a bit that people will blithely pass HWCAP_foo to these,
> > not realising that the interface has changed.
> 
> Yeah this would be an easy mistake to make.
> 
> > 
> > Can we do something like the following:
> > 
> > static inline bool __cpu_have_feature(unsigned int num)
> > {
> > 	if (WARN_ON(num >= 64))
> > 		return false;
> > 
> > 	if (num < 32)
> > 		return elf_hwcap & BIT(num);
> > 	else
> > 		return elf_hwcap2 & BIT(num);
> > }
> > 
> > #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name))
> 
> It took me a while to figure out what the benefit of the above line
> is - this means that callers of cpu_have_feature must use the unprefixed
> feature name (e.g. SHA512), anything else such as (KERNEL_HWCAP_SHA512
> or HWCAP_SHA512) would result in a compile time error. Whereas without
> this users could pass KERNEL_HWCAP_x or HWCAP_x without compile errors
> yet resulting in incorrectly passing a bitfield when using HWCAP_x.

That was the idea (apologies for being cryptic...)

> > In compiletime-constant cases, the compiler should simply delete the
> > WARN.
> 
> Is this really needed? Surely this would only come into play when a user
> directly calls __cpu_have_feature. I think this is overkill, especially
> as __cpu_have_feature is a new function.
> 
> >  A couple of cases in the cpufeatures and /proc/cpuinfo code would
> > need to use __cpu_have_feature directly and would retain the WARN, but
> > that's not fastpath and probably not the end of the world, plus we
> > get an additional debugging aid if that code goes wrong.
> 
> But even so, the WARN (for the cpuinfo case) is unlikely to ever be hit.

Sure, since we don't expect general purpose callers to use
__cpu_have_feature() directly it is a bit paranoid to include the WARN.
Given the contexts in which this is used, I wouldn't lose sleep if it
weren't there.

> The challenge with this approach is print_cpu_modalias (drivers/base/cpu.c),
> this also uses cpu_have_feature - this expects cpu_have_feature to take
> an ordinal. How can we work around this?
> 
> > 
> > Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making
> > it impossible to specify invalid or user-encoded hwcaps there either.
> > Then we might justifiably omit the policing in __cpu_have_feature()
> > altogether.
> 
> This would certainly please checkpatch with respect to line lengths :)
> 
> However since this patchset, we now use cpu_have_feature elsewhere, such
> as in the crypto drivers.

Hmmm, those are irksome issues.

It would be nice to split the ordinal versus symbolic cpu_have_feature()
into separate macros, but that would involve a change to code outside
arch/arm64.  It's almost certainly not worth the pain.


Can you take a look at arch/arm?  That already has hwcap2.
It may makes some sense to follow a common approach, although I'm not
sure how

	#define __hwcap_feature(x)      ilog2(HWCAP_ ## x)
	#define __hwcap2_feature(x)     (32 + ilog2(HWCAP2_ ## x))
	#define cpu_feature(x)          __hwcap2_feature(x)

is supposed to work for cpu_feature(SWP) for example...  Maybe I missed
something.

> > >  /* System capability check for constant caps */
> > > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
> > > index 400b80b..05ee9b9 100644
> > > --- a/arch/arm64/include/asm/hwcap.h
> > > +++ b/arch/arm64/include/asm/hwcap.h
> > > @@ -39,12 +39,49 @@

[...]

> > > +#define KERNEL_HWCAP_SSBS              ilog2(HWCAP_SSBS)
> > > +#define KERNEL_HWCAP_SB                ilog2(HWCAP_SB)
> > > +#define KERNEL_HWCAP_PACA              ilog2(HWCAP_PACA)
> > > +#define KERNEL_HWCAP_PACG              ilog2(HWCAP_PACG)
> > 
> > Nit: Odd spacing?  Personally I wouldn't indent with spaces just so that
> > (ilog2() + 32) lines up nicely, but that's just my opinion and not a
> > huge deal.
> > 
> > (The spacing can make subsequent diffs look jagged by default, which
> > can be a distraction for reviewers.)
> 
> I'll convert to tabs, I probably copy pasted and the tabs got converted.
> 
> > 
> > > +
> > >  #ifndef __ASSEMBLY__
> > >  /*
> > >   * This yields a mask that user programs can use to figure out what
> > >   * instruction set this cpu supports.
> > >   */
> > > -#define ELF_HWCAP		(elf_hwcap)
> > > +#define ELF_HWCAP		elf_hwcap
> > > +#define ELF_HWCAP2		elf_hwcap2
> > 
> > Do we need elf_hwcap2 at all?
> > 
> > We could just have these macros fish the bits out of a single variable,
> > or wherever.
> > 
> > However, it may be better to keep things this way if we want to maintain
> > the elf_hwcap in the kernel/module ABI.  See note on EXPORT_SYMBOL_GPL()
> > removal for elf_hwcap in the subsequent patch.
> 
> OK, I'll leave it as it is.
> 
> > 
> > >  
> > >  #ifdef CONFIG_COMPAT
> > >  #define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
> > > @@ -60,6 +97,6 @@ enum {
> > >  #endif
> > >  };
> > >  
> > > -extern unsigned long elf_hwcap;
> > > +extern unsigned long elf_hwcap, elf_hwcap2;
> > >  #endif
> > >  #endif
> > > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
> > > index 5f0750c..453b45a 100644
> > > --- a/arch/arm64/include/uapi/asm/hwcap.h
> > > +++ b/arch/arm64/include/uapi/asm/hwcap.h
> > > @@ -18,7 +18,7 @@
> > >  #define _UAPI__ASM_HWCAP_H
> > >  
> > >  /*
> > > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
> > > + * HWCAP flags - for AT_HWCAP
> > >   */
> > >  #define HWCAP_FP		(1 << 0)
> > >  #define HWCAP_ASIMD		(1 << 1)
> > > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> > > index f6d84e2..d10a455 100644
> > > --- a/arch/arm64/kernel/cpufeature.c
> > > +++ b/arch/arm64/kernel/cpufeature.c
> > > @@ -38,6 +38,9 @@
> > >  unsigned long elf_hwcap __read_mostly;
> > >  EXPORT_SYMBOL_GPL(elf_hwcap);
> > >  
> > > +unsigned long elf_hwcap2 __read_mostly;
> > > +EXPORT_SYMBOL_GPL(elf_hwcap2);
> > > +
> > 
> > Historically nobody used this because it didn't exist, and we don't want
> > anybody to use it (since cpu_have_feature() etc. is the preferred
> > interface).
> 
> In that case I should probably EXPORT_SYMBOL_GPL cpu_have_feature.
> 
> > 
> > So lose EXPORT_SYMBOL_GPL() here.  (You remove it in any case in a
> > subsequent patch, but having it even transiently sends mixed messages
> > about the intent.)
> 
> No problem.

Hmmm, since this inline in a header we'd have to EXPORT_SYMBOL_GPL the
things it depends on (elf_hwcap, elf_hwcap2) rather than the (inline)
function itself.

So maybe we can't do better than the current situation after all.

If so, I guess exporting elf_hwcap2 as GPL is OK.

Cheers
---Dave
Andrew Murray Feb. 19, 2019, 4:52 p.m. UTC | #4
On Mon, Feb 18, 2019 at 04:02:38PM +0000, Dave Martin wrote:
> On Mon, Feb 18, 2019 at 03:32:06PM +0000, Andrew Murray wrote:
> > On Thu, Feb 07, 2019 at 11:31:24AM +0000, Dave Martin wrote:
> > > On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote:
> > > > As we will exhaust the first 32 bits of ELF_HWCAP let's start
> > > > exposing ELF_HWCAP2 to userspace.
> > > > 
> > > > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we
> > > > prefer to expand into ELF_HWCAP2 in order to provide a consistent
> > > > view to userspace between ILP32 and LP64.
> > > > 
> > > > To reduce complexity and allow for future expansion, we now
> > > > represent hwcaps in the kernel as ordinals and use a
> > > > KERNEL_HWCAP_ prefix. This allows us to support automatic feature
> > > > based module loading for all our hwcaps.
> > > > 
> > > > We introduce cpu_set_feature to set hwcaps in the relevant
> > > > elf_hwcapX variable which compliments the existing cpu_have_feature
> > > > helper. These helpers allow us to clean up existing direct uses of
> > > > elf_hwcap.
> > > > 
> > > > Signed-off-by: Andrew Murray <andrew.murray@arm.com>
> > > > ---
> > > 
> > > [...]
> > > 
> > > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> > > > index dfcfba7..15d939e 100644
> > > > --- a/arch/arm64/include/asm/cpufeature.h
> > > > +++ b/arch/arm64/include/asm/cpufeature.h
> > > > @@ -18,11 +18,10 @@
> > > >   * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
> > > >   * in the kernel and for user space to keep track of which optional features
> > > >   * are supported by the current system. So let's map feature 'x' to HWCAP_x.
> > > > - * Note that HWCAP_x constants are bit fields so we need to take the log.
> > > >   */
> > > >  
> > > > -#define MAX_CPU_FEATURES	(8 * sizeof(elf_hwcap))
> > > > -#define cpu_feature(x)		ilog2(HWCAP_ ## x)
> > > > +#define MAX_CPU_FEATURES	(2 * 8 * sizeof(unsigned long))
> > > 
> > > Doesn't this make 2 * 8 * 8 == 128?
> > > 
> > > Maybe just say "64".  We open-code 32 later anyway.
> > 
> > I guess 128 would have been correct if we use all the bits of
> > each ELF_HWCAP{,2} - but we chose to limit each ELF_HWCAP to be
> > 32 bits.
> > 
> > I'll set this to 64 as you suggest.
> > 
> > > 
> > > > +#define cpu_feature(x)		(KERNEL_HWCAP_ ## x)
> > > >  
> > > >  #ifndef __ASSEMBLY__
> > > >  
> > > > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready;
> > > >  
> > > >  bool this_cpu_has_cap(unsigned int cap);
> > > >  
> > > > +static inline void cpu_set_feature(unsigned int num)
> > > > +{
> > > > +	if (num < 32)
> > > > +		elf_hwcap |= BIT(num);
> > > > +	else
> > > > +		elf_hwcap2 |= BIT(num - 32);
> > > > +}
> > > > +
> > > >  static inline bool cpu_have_feature(unsigned int num)
> > > >  {
> > > > -	return elf_hwcap & (1UL << num);
> > > > +	if (num < 32)
> > > > +		return elf_hwcap & BIT(num);
> > > > +	else
> > > > +		return elf_hwcap2 & BIT(num - 32);
> > > >  }
> > > 
> > > Nit: I worry a bit that people will blithely pass HWCAP_foo to these,
> > > not realising that the interface has changed.
> > 
> > Yeah this would be an easy mistake to make.
> > 
> > > 
> > > Can we do something like the following:
> > > 
> > > static inline bool __cpu_have_feature(unsigned int num)
> > > {
> > > 	if (WARN_ON(num >= 64))
> > > 		return false;
> > > 
> > > 	if (num < 32)
> > > 		return elf_hwcap & BIT(num);
> > > 	else
> > > 		return elf_hwcap2 & BIT(num);
> > > }
> > > 
> > > #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name))
> > 
> > It took me a while to figure out what the benefit of the above line
> > is - this means that callers of cpu_have_feature must use the unprefixed
> > feature name (e.g. SHA512), anything else such as (KERNEL_HWCAP_SHA512
> > or HWCAP_SHA512) would result in a compile time error. Whereas without
> > this users could pass KERNEL_HWCAP_x or HWCAP_x without compile errors
> > yet resulting in incorrectly passing a bitfield when using HWCAP_x.
> 
> That was the idea (apologies for being cryptic...)

:)

> 
> > > In compiletime-constant cases, the compiler should simply delete the
> > > WARN.
> > 
> > Is this really needed? Surely this would only come into play when a user
> > directly calls __cpu_have_feature. I think this is overkill, especially
> > as __cpu_have_feature is a new function.
> > 
> > >  A couple of cases in the cpufeatures and /proc/cpuinfo code would
> > > need to use __cpu_have_feature directly and would retain the WARN, but
> > > that's not fastpath and probably not the end of the world, plus we
> > > get an additional debugging aid if that code goes wrong.
> > 
> > But even so, the WARN (for the cpuinfo case) is unlikely to ever be hit.
> 
> Sure, since we don't expect general purpose callers to use
> __cpu_have_feature() directly it is a bit paranoid to include the WARN.
> Given the contexts in which this is used, I wouldn't lose sleep if it
> weren't there.
> 
> > The challenge with this approach is print_cpu_modalias (drivers/base/cpu.c),
> > this also uses cpu_have_feature - this expects cpu_have_feature to take
> > an ordinal. How can we work around this?
> > 
> > > 
> > > Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making
> > > it impossible to specify invalid or user-encoded hwcaps there either.
> > > Then we might justifiably omit the policing in __cpu_have_feature()
> > > altogether.
> > 
> > This would certainly please checkpatch with respect to line lengths :)
> > 
> > However since this patchset, we now use cpu_have_feature elsewhere, such
> > as in the crypto drivers.
> 
> Hmmm, those are irksome issues.
> 
> It would be nice to split the ordinal versus symbolic cpu_have_feature()
> into separate macros, but that would involve a change to code outside
> arch/arm64.  It's almost certainly not worth the pain.
> 
> 
> Can you take a look at arch/arm?  That already has hwcap2.
> It may makes some sense to follow a common approach, although I'm not
> sure how
> 
> 	#define __hwcap_feature(x)      ilog2(HWCAP_ ## x)
> 	#define __hwcap2_feature(x)     (32 + ilog2(HWCAP2_ ## x))
> 	#define cpu_feature(x)          __hwcap2_feature(x)
> 
> is supposed to work for cpu_feature(SWP) for example...  Maybe I missed
> something.

The limitation with the arm32 approach is that you can only support automatic
module loading with features covered in HWCAP2. We can avoid this.

For arm32 cpu_feature(AES) will only match within HWCAP2, you would get
unintended behaviour if you used a feature name from HWCAP such as NEON.

Thus cpu_have_feature(cpu_feature(X)) is limited to HWCAP2.

Prior to this patchset cpu_have_feature had a sole user and that is
print_cpu_modalias. CPU features are normally tested by directly comparing
against elf_hwcap.

> 
> > > >  /* System capability check for constant caps */
> > > > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
> > > > index 400b80b..05ee9b9 100644
> > > > --- a/arch/arm64/include/asm/hwcap.h
> > > > +++ b/arch/arm64/include/asm/hwcap.h
> > > > @@ -39,12 +39,49 @@
> 
> [...]
> 
> > > > +#define KERNEL_HWCAP_SSBS              ilog2(HWCAP_SSBS)
> > > > +#define KERNEL_HWCAP_SB                ilog2(HWCAP_SB)
> > > > +#define KERNEL_HWCAP_PACA              ilog2(HWCAP_PACA)
> > > > +#define KERNEL_HWCAP_PACG              ilog2(HWCAP_PACG)
> > > 
> > > Nit: Odd spacing?  Personally I wouldn't indent with spaces just so that
> > > (ilog2() + 32) lines up nicely, but that's just my opinion and not a
> > > huge deal.
> > > 
> > > (The spacing can make subsequent diffs look jagged by default, which
> > > can be a distraction for reviewers.)
> > 
> > I'll convert to tabs, I probably copy pasted and the tabs got converted.
> > 
> > > 
> > > > +
> > > >  #ifndef __ASSEMBLY__
> > > >  /*
> > > >   * This yields a mask that user programs can use to figure out what
> > > >   * instruction set this cpu supports.
> > > >   */
> > > > -#define ELF_HWCAP		(elf_hwcap)
> > > > +#define ELF_HWCAP		elf_hwcap
> > > > +#define ELF_HWCAP2		elf_hwcap2
> > > 
> > > Do we need elf_hwcap2 at all?
> > > 
> > > We could just have these macros fish the bits out of a single variable,
> > > or wherever.
> > > 
> > > However, it may be better to keep things this way if we want to maintain
> > > the elf_hwcap in the kernel/module ABI.  See note on EXPORT_SYMBOL_GPL()
> > > removal for elf_hwcap in the subsequent patch.
> > 
> > OK, I'll leave it as it is.
> > 
> > > 
> > > >  
> > > >  #ifdef CONFIG_COMPAT
> > > >  #define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
> > > > @@ -60,6 +97,6 @@ enum {
> > > >  #endif
> > > >  };
> > > >  
> > > > -extern unsigned long elf_hwcap;
> > > > +extern unsigned long elf_hwcap, elf_hwcap2;
> > > >  #endif
> > > >  #endif
> > > > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
> > > > index 5f0750c..453b45a 100644
> > > > --- a/arch/arm64/include/uapi/asm/hwcap.h
> > > > +++ b/arch/arm64/include/uapi/asm/hwcap.h
> > > > @@ -18,7 +18,7 @@
> > > >  #define _UAPI__ASM_HWCAP_H
> > > >  
> > > >  /*
> > > > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
> > > > + * HWCAP flags - for AT_HWCAP
> > > >   */
> > > >  #define HWCAP_FP		(1 << 0)
> > > >  #define HWCAP_ASIMD		(1 << 1)
> > > > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> > > > index f6d84e2..d10a455 100644
> > > > --- a/arch/arm64/kernel/cpufeature.c
> > > > +++ b/arch/arm64/kernel/cpufeature.c
> > > > @@ -38,6 +38,9 @@
> > > >  unsigned long elf_hwcap __read_mostly;
> > > >  EXPORT_SYMBOL_GPL(elf_hwcap);
> > > >  
> > > > +unsigned long elf_hwcap2 __read_mostly;
> > > > +EXPORT_SYMBOL_GPL(elf_hwcap2);
> > > > +
> > > 
> > > Historically nobody used this because it didn't exist, and we don't want
> > > anybody to use it (since cpu_have_feature() etc. is the preferred
> > > interface).
> > 
> > In that case I should probably EXPORT_SYMBOL_GPL cpu_have_feature.
> > 
> > > 
> > > So lose EXPORT_SYMBOL_GPL() here.  (You remove it in any case in a
> > > subsequent patch, but having it even transiently sends mixed messages
> > > about the intent.)
> > 
> > No problem.
> 
> Hmmm, since this inline in a header we'd have to EXPORT_SYMBOL_GPL the
> things it depends on (elf_hwcap, elf_hwcap2) rather than the (inline)
> function itself.
> 
> So maybe we can't do better than the current situation after all.
> 
> If so, I guess exporting elf_hwcap2 as GPL is OK.

Actually my patchset moves the cpu_have_feature function a C file. So I could
add a EXPORT_SYMBOL_GPL to this and the other functions I introduce
(cpu_set_feature, cpu_get_elf_hwcap{,2}).

Unless you have objections I'll respin with this approach.

Andrew Murray

> 
> Cheers
> ---Dave
diff mbox series

Patch

diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
index 68b11aa..8bca470 100644
--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
+++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
@@ -374,7 +374,7 @@  static struct aead_alg ccm_aes_alg = {
 
 static int __init aes_mod_init(void)
 {
-	if (!(elf_hwcap & HWCAP_AES))
+	if (!cpu_have_feature(KERNEL_HWCAP_AES))
 		return -ENODEV;
 	return crypto_register_aead(&ccm_aes_alg);
 }
diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c
index e7a95a5..e5a8334 100644
--- a/arch/arm64/crypto/aes-neonbs-glue.c
+++ b/arch/arm64/crypto/aes-neonbs-glue.c
@@ -440,7 +440,7 @@  static int __init aes_init(void)
 	int err;
 	int i;
 
-	if (!(elf_hwcap & HWCAP_ASIMD))
+	if (!cpu_have_feature(KERNEL_HWCAP_ASIMD))
 		return -ENODEV;
 
 	err = crypto_register_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
diff --git a/arch/arm64/crypto/chacha-neon-glue.c b/arch/arm64/crypto/chacha-neon-glue.c
index bece1d8..54de986 100644
--- a/arch/arm64/crypto/chacha-neon-glue.c
+++ b/arch/arm64/crypto/chacha-neon-glue.c
@@ -173,7 +173,7 @@  static struct skcipher_alg algs[] = {
 
 static int __init chacha_simd_mod_init(void)
 {
-	if (!(elf_hwcap & HWCAP_ASIMD))
+	if (!cpu_have_feature(KERNEL_HWCAP_ASIMD))
 		return -ENODEV;
 
 	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
diff --git a/arch/arm64/crypto/crct10dif-ce-glue.c b/arch/arm64/crypto/crct10dif-ce-glue.c
index b461d62..d78d123 100644
--- a/arch/arm64/crypto/crct10dif-ce-glue.c
+++ b/arch/arm64/crypto/crct10dif-ce-glue.c
@@ -88,7 +88,7 @@  static struct shash_alg crc_t10dif_alg = {
 
 static int __init crc_t10dif_mod_init(void)
 {
-	if (elf_hwcap & HWCAP_PMULL)
+	if (cpu_have_feature(KERNEL_HWCAP_PMULL))
 		crc_t10dif_pmull = crc_t10dif_pmull_p64;
 	else
 		crc_t10dif_pmull = crc_t10dif_pmull_p8;
diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c
index 067d893..f3aa5dd 100644
--- a/arch/arm64/crypto/ghash-ce-glue.c
+++ b/arch/arm64/crypto/ghash-ce-glue.c
@@ -646,10 +646,10 @@  static int __init ghash_ce_mod_init(void)
 {
 	int ret;
 
-	if (!(elf_hwcap & HWCAP_ASIMD))
+	if (!cpu_have_feature(KERNEL_HWCAP_ASIMD))
 		return -ENODEV;
 
-	if (elf_hwcap & HWCAP_PMULL)
+	if (cpu_have_feature(KERNEL_HWCAP_PMULL))
 		pmull_ghash_update = pmull_ghash_update_p64;
 
 	else
@@ -659,7 +659,7 @@  static int __init ghash_ce_mod_init(void)
 	if (ret)
 		return ret;
 
-	if (elf_hwcap & HWCAP_PMULL) {
+	if (cpu_have_feature(KERNEL_HWCAP_PMULL)) {
 		ret = crypto_register_aead(&gcm_aes_alg);
 		if (ret)
 			crypto_unregister_shash(&ghash_alg);
diff --git a/arch/arm64/crypto/nhpoly1305-neon-glue.c b/arch/arm64/crypto/nhpoly1305-neon-glue.c
index 22cc32a..7e6815b 100644
--- a/arch/arm64/crypto/nhpoly1305-neon-glue.c
+++ b/arch/arm64/crypto/nhpoly1305-neon-glue.c
@@ -56,7 +56,7 @@  static struct shash_alg nhpoly1305_alg = {
 
 static int __init nhpoly1305_mod_init(void)
 {
-	if (!(elf_hwcap & HWCAP_ASIMD))
+	if (!cpu_have_feature(KERNEL_HWCAP_ASIMD))
 		return -ENODEV;
 
 	return crypto_register_shash(&nhpoly1305_alg);
diff --git a/arch/arm64/crypto/sha256-glue.c b/arch/arm64/crypto/sha256-glue.c
index 4aedeae..7799f4c 100644
--- a/arch/arm64/crypto/sha256-glue.c
+++ b/arch/arm64/crypto/sha256-glue.c
@@ -173,7 +173,7 @@  static int __init sha256_mod_init(void)
 	if (ret)
 		return ret;
 
-	if (elf_hwcap & HWCAP_ASIMD) {
+	if (cpu_have_feature(KERNEL_HWCAP_ASIMD)) {
 		ret = crypto_register_shashes(neon_algs, ARRAY_SIZE(neon_algs));
 		if (ret)
 			crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
@@ -183,7 +183,7 @@  static int __init sha256_mod_init(void)
 
 static void __exit sha256_mod_fini(void)
 {
-	if (elf_hwcap & HWCAP_ASIMD)
+	if (cpu_have_feature(KERNEL_HWCAP_ASIMD))
 		crypto_unregister_shashes(neon_algs, ARRAY_SIZE(neon_algs));
 	crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
 }
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index dfcfba7..15d939e 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -18,11 +18,10 @@ 
  * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
  * in the kernel and for user space to keep track of which optional features
  * are supported by the current system. So let's map feature 'x' to HWCAP_x.
- * Note that HWCAP_x constants are bit fields so we need to take the log.
  */
 
-#define MAX_CPU_FEATURES	(8 * sizeof(elf_hwcap))
-#define cpu_feature(x)		ilog2(HWCAP_ ## x)
+#define MAX_CPU_FEATURES	(2 * 8 * sizeof(unsigned long))
+#define cpu_feature(x)		(KERNEL_HWCAP_ ## x)
 
 #ifndef __ASSEMBLY__
 
@@ -396,9 +395,20 @@  extern struct static_key_false arm64_const_caps_ready;
 
 bool this_cpu_has_cap(unsigned int cap);
 
+static inline void cpu_set_feature(unsigned int num)
+{
+	if (num < 32)
+		elf_hwcap |= BIT(num);
+	else
+		elf_hwcap2 |= BIT(num - 32);
+}
+
 static inline bool cpu_have_feature(unsigned int num)
 {
-	return elf_hwcap & (1UL << num);
+	if (num < 32)
+		return elf_hwcap & BIT(num);
+	else
+		return elf_hwcap2 & BIT(num - 32);
 }
 
 /* System capability check for constant caps */
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 400b80b..05ee9b9 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -39,12 +39,49 @@ 
 #define COMPAT_HWCAP2_SHA2	(1 << 3)
 #define COMPAT_HWCAP2_CRC32	(1 << 4)
 
+/*
+ * KERNEL_HWCAP flags - for elf_hwcap (in kernel)
+ */
+#define KERNEL_HWCAP_FP                ilog2(HWCAP_FP)
+#define KERNEL_HWCAP_ASIMD             ilog2(HWCAP_ASIMD)
+#define KERNEL_HWCAP_EVTSTRM           ilog2(HWCAP_EVTSTRM)
+#define KERNEL_HWCAP_AES               ilog2(HWCAP_AES)
+#define KERNEL_HWCAP_PMULL             ilog2(HWCAP_PMULL)
+#define KERNEL_HWCAP_SHA1              ilog2(HWCAP_SHA1)
+#define KERNEL_HWCAP_SHA2              ilog2(HWCAP_SHA2)
+#define KERNEL_HWCAP_CRC32             ilog2(HWCAP_CRC32)
+#define KERNEL_HWCAP_ATOMICS           ilog2(HWCAP_ATOMICS)
+#define KERNEL_HWCAP_FPHP              ilog2(HWCAP_FPHP)
+#define KERNEL_HWCAP_ASIMDHP           ilog2(HWCAP_ASIMDHP)
+#define KERNEL_HWCAP_CPUID             ilog2(HWCAP_CPUID)
+#define KERNEL_HWCAP_ASIMDRDM          ilog2(HWCAP_ASIMDRDM)
+#define KERNEL_HWCAP_JSCVT             ilog2(HWCAP_JSCVT)
+#define KERNEL_HWCAP_FCMA              ilog2(HWCAP_FCMA)
+#define KERNEL_HWCAP_LRCPC             ilog2(HWCAP_LRCPC)
+#define KERNEL_HWCAP_DCPOP             ilog2(HWCAP_DCPOP)
+#define KERNEL_HWCAP_SHA3              ilog2(HWCAP_SHA3)
+#define KERNEL_HWCAP_SM3               ilog2(HWCAP_SM3)
+#define KERNEL_HWCAP_SM4               ilog2(HWCAP_SM4)
+#define KERNEL_HWCAP_ASIMDDP           ilog2(HWCAP_ASIMDDP)
+#define KERNEL_HWCAP_SHA512            ilog2(HWCAP_SHA512)
+#define KERNEL_HWCAP_SVE               ilog2(HWCAP_SVE)
+#define KERNEL_HWCAP_ASIMDFHM          ilog2(HWCAP_ASIMDFHM)
+#define KERNEL_HWCAP_DIT               ilog2(HWCAP_DIT)
+#define KERNEL_HWCAP_USCAT             ilog2(HWCAP_USCAT)
+#define KERNEL_HWCAP_ILRCPC            ilog2(HWCAP_ILRCPC)
+#define KERNEL_HWCAP_FLAGM             ilog2(HWCAP_FLAGM)
+#define KERNEL_HWCAP_SSBS              ilog2(HWCAP_SSBS)
+#define KERNEL_HWCAP_SB                ilog2(HWCAP_SB)
+#define KERNEL_HWCAP_PACA              ilog2(HWCAP_PACA)
+#define KERNEL_HWCAP_PACG              ilog2(HWCAP_PACG)
+
 #ifndef __ASSEMBLY__
 /*
  * This yields a mask that user programs can use to figure out what
  * instruction set this cpu supports.
  */
-#define ELF_HWCAP		(elf_hwcap)
+#define ELF_HWCAP		elf_hwcap
+#define ELF_HWCAP2		elf_hwcap2
 
 #ifdef CONFIG_COMPAT
 #define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
@@ -60,6 +97,6 @@  enum {
 #endif
 };
 
-extern unsigned long elf_hwcap;
+extern unsigned long elf_hwcap, elf_hwcap2;
 #endif
 #endif
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 5f0750c..453b45a 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -18,7 +18,7 @@ 
 #define _UAPI__ASM_HWCAP_H
 
 /*
- * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
+ * HWCAP flags - for AT_HWCAP
  */
 #define HWCAP_FP		(1 << 0)
 #define HWCAP_ASIMD		(1 << 1)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index f6d84e2..d10a455 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -38,6 +38,9 @@ 
 unsigned long elf_hwcap __read_mostly;
 EXPORT_SYMBOL_GPL(elf_hwcap);
 
+unsigned long elf_hwcap2 __read_mostly;
+EXPORT_SYMBOL_GPL(elf_hwcap2);
+
 #ifdef CONFIG_COMPAT
 #define COMPAT_ELF_HWCAP_DEFAULT	\
 				(COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
@@ -1536,39 +1539,39 @@  static const struct arm64_cpu_capabilities ptr_auth_hwcap_gen_matches[] = {
 #endif
 
 static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_SHA512),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDRDM),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA3),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SM3),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SM4),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDDP),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDFHM),
-	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_TS_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FLAGM),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP),
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_DIT_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_DIT),
-	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_DCPOP),
-	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_JSCVT),
-	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FCMA),
-	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_LRCPC),
-	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ILRCPC),
-	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_SB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SB),
-	HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_AT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_USCAT),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_PMULL),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_AES),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SHA1),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SHA2),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_SHA512),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_CRC32),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_ATOMICS),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDRDM),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SHA3),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SM3),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SM4),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDDP),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDFHM),
+	HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_TS_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FLAGM),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, KERNEL_HWCAP_FP),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FPHP),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, KERNEL_HWCAP_ASIMD),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDHP),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_DIT_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DIT),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DCPOP),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_JSCVT),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FCMA),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_LRCPC),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_ILRCPC),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_SB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SB),
+	HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_AT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_USCAT),
 #ifdef CONFIG_ARM64_SVE
-	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, KERNEL_HWCAP_SVE),
 #endif
-	HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, HWCAP_SSBS),
+	HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, KERNEL_HWCAP_SSBS),
 #ifdef CONFIG_ARM64_PTR_AUTH
-	HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, HWCAP_PACA),
-	HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, HWCAP_PACG),
+	HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, KERNEL_HWCAP_PACA),
+	HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, KERNEL_HWCAP_PACG),
 #endif
 	{},
 };
@@ -1588,7 +1591,7 @@  static void __init cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap)
 {
 	switch (cap->hwcap_type) {
 	case CAP_HWCAP:
-		elf_hwcap |= cap->hwcap;
+		cpu_set_feature(cap->hwcap);
 		break;
 #ifdef CONFIG_COMPAT
 	case CAP_COMPAT_HWCAP:
@@ -1611,7 +1614,7 @@  static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap)
 
 	switch (cap->hwcap_type) {
 	case CAP_HWCAP:
-		rc = (elf_hwcap & cap->hwcap) != 0;
+		rc = cpu_have_feature(cap->hwcap);
 		break;
 #ifdef CONFIG_COMPAT
 	case CAP_COMPAT_HWCAP:
@@ -1632,7 +1635,7 @@  static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap)
 static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
 {
 	/* We support emulation of accesses to CPU ID feature registers */
-	elf_hwcap |= HWCAP_CPUID;
+	cpu_set_feature(KERNEL_HWCAP_CPUID);
 	for (; hwcaps->matches; hwcaps++)
 		if (hwcaps->matches(hwcaps, cpucap_default_scope(hwcaps)))
 			cap_set_elf_hwcap(hwcaps);
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index ca0685f..810db95 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -167,7 +167,7 @@  static int c_show(struct seq_file *m, void *v)
 #endif /* CONFIG_COMPAT */
 		} else {
 			for (j = 0; hwcap_str[j]; j++)
-				if (elf_hwcap & (1 << j))
+				if (cpu_have_feature(j))
 					seq_printf(m, " %s", hwcap_str[j]);
 		}
 		seq_puts(m, "\n");
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 5ebe73b..f28837c 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1258,14 +1258,14 @@  static inline void fpsimd_hotplug_init(void) { }
  */
 static int __init fpsimd_init(void)
 {
-	if (elf_hwcap & HWCAP_FP) {
+	if (cpu_have_feature(KERNEL_HWCAP_FP)) {
 		fpsimd_pm_init();
 		fpsimd_hotplug_init();
 	} else {
 		pr_notice("Floating-point is not implemented\n");
 	}
 
-	if (!(elf_hwcap & HWCAP_ASIMD))
+	if (!cpu_have_feature(KERNEL_HWCAP_ASIMD))
 		pr_notice("Advanced SIMD is not implemented\n");
 
 	return sve_sysctl_init();
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 9a7d4dc..5b2d56d 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -778,7 +778,11 @@  static void arch_timer_evtstrm_enable(int divider)
 	cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
 			| ARCH_TIMER_VIRT_EVT_EN;
 	arch_timer_set_cntkctl(cntkctl);
+#ifdef CONFIG_ARM64
+	cpu_set_feature(KERNEL_HWCAP_EVTSTRM);
+#else
 	elf_hwcap |= HWCAP_EVTSTRM;
+#endif
 #ifdef CONFIG_COMPAT
 	compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
 #endif
@@ -1000,7 +1004,11 @@  static int arch_timer_cpu_pm_notify(struct notifier_block *self,
 	} else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) {
 		arch_timer_set_cntkctl(__this_cpu_read(saved_cntkctl));
 
+#ifdef CONFIG_ARM64
+		if (cpu_have_feature(KERNEL_HWCAP_EVTSTRM))
+#else
 		if (elf_hwcap & HWCAP_EVTSTRM)
+#endif
 			cpumask_set_cpu(smp_processor_id(), &evtstrm_available);
 	}
 	return NOTIFY_OK;