Re: [PATCH v9 1/4] riscv: cpufeature: Introduce ISA bases bitmap and rva23u64 detection

From: Icenowy Zheng

Date: Mon Nov 09 2026 - 11:00:55 EST


在 2026-11-09一的 07:47 -0500,Guodong Xu写道:
> Introduce a per-hart and host-wide bitmap of conformant ISA "bases"
> (named profile-class sets such as IMA and RVA23U64), computed at init
> time by riscv_init_isa_bases().
>
> The IMA base is set unconditionally: it is behavior the kernel always
> provides, and is intentionally not derived from the I, M and A
> extensions.
>
> Register riscv_init_isa_bases() as an arch_initcall. That is late
> enough that core_initcall(tagged_addr_init) has probed senvcfg.PMM
> and
> populated have_user_pmlen_*; without that ordering,
> riscv_have_user_pmlen(7) would still return its default false and the
> RVA23U64 detection path would always bail. It is also early enough
> that
> arch_initcall_sync(init_hwprobe_vdso_data) finds the bases populated
> when it snapshots the hwprobe values into the vDSO data page.
>
> Consider this as the cache that subsequent consumers (hwprobe's
> RVA23U64 base behavior bit, /proc/cpuinfo's "isa bases" lines, etc.)
> can read without recomputing, which keeps them consistent with
> each other.
>
> Co-developed-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
> Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
> Signed-off-by: Guodong Xu <guodong.xu@xxxxxxxxxxxxxxxx>
> ---
> v9: Set the IMA base unconditionally; do not derive it from I, M and
> A.
> v8: Add Co-developed-by for Andrew Jones (Conor).
> v7:
> - Register riscv_init_isa_bases() at arch_initcall, ahead of the vDSO
>   hwprobe snapshot at arch_initcall_sync; v6 returned 0 for
>   RISCV_HWPROBE_KEY_BASE_BEHAVIOR through the vDSO.
> - Keep riscv_isa_bases static; add riscv_isa_base_available().
> v6: No change.
> v5: No change.
> v4:
> - In riscv_set_isa_base(), reorder those __setbit(RISCV_ISA_EXT_X,m)
>   lines to make them conform to the order they appear in the RVA23
> 1.0
>   Profile.
> v3:
> - Add a blank line before the subsys_initcall() registration
> (Andrew).
> - Set the local ext_mask with __set_bit() and test the mandate set
> with
>   !bitmap_subset() (Sashiko).
> - Require the Zic64b ISA extension in the RVA23U64 mask,
>   instead of open-coded cache block-size check. (New, thoughts from
> Andrew)
> v2:
> - Implement riscv_init_isa_bases() that runs at system init time,
>   after tagged_addr_init() populates have_user_pmlen_*.
> - Split RVA23S64 placeholder into a future patch.
> ---
>  arch/riscv/include/asm/cpufeature.h |  13 +++++
>  arch/riscv/kernel/cpufeature.c      | 109
> ++++++++++++++++++++++++++++++++++++
>  2 files changed, 122 insertions(+)
>
> diff --git a/arch/riscv/include/asm/cpufeature.h
> b/arch/riscv/include/asm/cpufeature.h
> index 99799cc6c198..2ce1a1e212c9 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -25,8 +25,20 @@ struct riscv_cpuinfo {
>   unsigned long mimpid;
>  };
>  
> +enum {
> + RISCV_ISA_BASE_IMA,

I may have missed something, but would it be worth to add a GC tier?

I think many Linux distros have GC defined as their baseline.

Thanks,
Icenowy

> + RISCV_ISA_BASE_RVA23U64,
> + RISCV_NR_ISA_BASES,
> +};
> +
> +/**
> + * struct riscv_isainfo - per-hart ISA state
> + * @isa: bitmap of ISA extensions this hart implements
> + * @isa_bases: bitmap of profile bases this hart conforms to
> + */
>  struct riscv_isainfo {
>   DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX);
> + DECLARE_BITMAP(isa_bases, RISCV_NR_ISA_BASES);
>  };
>  
>  DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
> @@ -134,6 +146,7 @@ extern const size_t riscv_isa_ext_count;
>  extern bool riscv_isa_fallback;
>  
>  unsigned long riscv_isa_extension_base(const unsigned long
> *isa_bitmap);
> +bool riscv_isa_base_available(const unsigned long *isa_bases,
> unsigned int base);
>  static __always_inline bool riscv_cpu_has_extension_likely(int cpu,
> const unsigned long ext)
>  {
>   compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be <
> RISCV_ISA_EXT_MAX");
> diff --git a/arch/riscv/kernel/cpufeature.c
> b/arch/riscv/kernel/cpufeature.c
> index 72bce616491f..0377fc148785 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -41,6 +41,9 @@ unsigned long elf_hwcap __read_mostly;
>  /* Host ISA bitmap */
>  DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
>  
> +/* Host ISA bases bitmap */
> +static DECLARE_BITMAP(riscv_isa_bases, RISCV_NR_ISA_BASES)
> __read_mostly;
> +
>  /* Per-cpu ISA extensions. */
>  struct riscv_isainfo hart_isa[NR_CPUS];
>  
> @@ -81,6 +84,26 @@ bool __riscv_isa_extension_available(const
> unsigned long *isa_bitmap, unsigned i
>  }
>  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
>  
> +/**
> + * riscv_isa_base_available() - Check whether a given ISA base is
> + * available or not
> + *
> + * @isa_bases: ISA bases bitmap to use
> + * @base: bit position of the desired ISA base
> + * Return: true or false
> + *
> + * NOTE: If isa_bases is NULL then the host ISA bases bitmap will be
> used.
> + */
> +bool riscv_isa_base_available(const unsigned long *isa_bases,
> unsigned int base)
> +{
> + const unsigned long *bmap = isa_bases ? isa_bases :
> riscv_isa_bases;
> +
> + if (base >= RISCV_NR_ISA_BASES)
> + return false;
> +
> + return test_bit(base, bmap);
> +}
> +
>  static int riscv_ext_f_depends(const struct riscv_isa_ext_data
> *data,
>          const unsigned long *isa_bitmap)
>  {
> @@ -1406,3 +1429,89 @@ void __init_or_module
> riscv_cpufeature_patch_func(struct alt_entry *begin,
>   if (early)
>   local_flush_icache_all();
>  }
> +
> +/*
> + * Compute the set of bases a hart conforms to. Profile bases such
> as
> + * RVA23U64 are derived from its resolved ISA bitmap.
> + *
> + * If @isa_bitmap is NULL, the host ISA bitmap (the AND across all
> harts) is
> + * used.
> + */
> +static void riscv_set_isa_bases(unsigned long *bases, const unsigned
> long *isa_bitmap)
> +{
> + const unsigned long *isa = isa_bitmap ? isa_bitmap :
> riscv_isa;
> + DECLARE_BITMAP(ext_mask, RISCV_ISA_EXT_MAX) = { 0 };
> +
> + /* The IMA base is behavior the kernel always provides. */
> + set_bit(RISCV_ISA_BASE_IMA, bases);
> +
> + /* RVA23U64 */
> +
> + /* Supm with PMLEN=7 */
> + if (!riscv_have_user_pmlen(7))
> + return;
> +
> + __set_bit(RISCV_ISA_EXT_I, ext_mask);
> + __set_bit(RISCV_ISA_EXT_M, ext_mask);
> + __set_bit(RISCV_ISA_EXT_A, ext_mask);
> + __set_bit(RISCV_ISA_EXT_F, ext_mask);
> + __set_bit(RISCV_ISA_EXT_D, ext_mask);
> + __set_bit(RISCV_ISA_EXT_C, ext_mask);
> + __set_bit(RISCV_ISA_EXT_B, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICSR, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICNTR, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZIHPM, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICCIF, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICCRSE, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICCAMOA, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICCLSM, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZA64RS, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZIHINTPAUSE, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZIC64B, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICBOM, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICBOP, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICBOZ, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZFHMIN, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZKT, ext_mask);
> + __set_bit(RISCV_ISA_EXT_V, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZVFHMIN, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZVBB, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZVKT, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZIHINTNTL, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZICOND, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZIMOP, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZCMOP, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZCB, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZFA, ext_mask);
> + __set_bit(RISCV_ISA_EXT_ZAWRS, ext_mask);
> + __set_bit(RISCV_ISA_EXT_SUPM, ext_mask);
> +
> + if (!bitmap_subset(ext_mask, isa, RISCV_ISA_EXT_MAX))
> + return;
> +
> + set_bit(RISCV_ISA_BASE_RVA23U64, bases);
> +}
> +
> +/*
> + * Populate the host ISA bases bitmap (riscv_isa_bases) and each
> + * hart's per-cpu isa_bases.
> + */
> +static int __init riscv_init_isa_bases(void)
> +{
> + int cpu;
> +
> + for_each_possible_cpu(cpu)
> + riscv_set_isa_bases(hart_isa[cpu].isa_bases,
> hart_isa[cpu].isa);
> +
> + riscv_set_isa_bases(riscv_isa_bases, NULL);
> + return 0;
> +}
> +
> +/*
> + * Registered as arch_initcall: late enough that
> + * core_initcall(tagged_addr_init) has populated have_user_pmlen_*,
> + * and early enough that arch_initcall_sync(init_hwprobe_vdso_data)
> + * finds the ISA bases populated when it snapshots the hwprobe
> + * values into the vDSO data page.
> + */
> +arch_initcall(riscv_init_isa_bases);