Re: [PATCH v2 08/10] riscv: cpufeature: Introduce ISA bases bitmap and rva23u64 detection
From: Guodong Xu
Date: Fri May 29 2026 - 20:44:03 EST
Hi, Drew
On Thu, May 28, 2026 at 12:35 AM Andrew Jones
<andrew.jones@xxxxxxxxxxxxxxxx> wrote:
>
> On Mon, May 11, 2026 at 09:34:53PM -0400, Guodong Xu wrote:
> > Introduce a per-hart and host-wide bitmap of conformant ISA "bases" --
> > named profile-class sets such as IMA and RVA23U64 -- and compute
> > both at init time.
> >
> > This is the cache that subsequent consumers (hwprobe's
> > RVA23U64 base behavior bit, /proc/cpuinfo's "isa bases" lines, etc.)
> > read without recomputing.
> >
> > riscv_init_isa_bases() iterates over all possible cpus to populate
> > each hart_isa[cpu].isa_bases, then computes the host-wide
> > riscv_isa_bases against the AND-across-harts riscv_isa bitmap. It is
> > registered as a subsys_initcall so it executes after
> > core_initcall(tagged_addr_init), which probes senvcfg.PMM and
> > populates 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.
> >
> > The detection itself is encapsulated in riscv_set_isa_bases(), which
> > takes an output bases bitmap and an input ISA bitmap.
> >
> > Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
> > Signed-off-by: Guodong Xu <guodong@xxxxxxxxxxxx>
> > ---
> > 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 | 14 ++++++
> > arch/riscv/kernel/cpufeature.c | 92 +++++++++++++++++++++++++++++++++++++
> > 2 files changed, 106 insertions(+)
>
> Sashiko points out a few things about this patch which I think I
> agree with
>
> https://sashiko.dev/#/patchset/20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc%40riscstar.com?part=8
Quote the following from Sashiko.dev:
> Should this mask specify the individual subset extensions required by the
> profile instead of the superset extensions like RISCV_ISA_EXT_B,
> RISCV_ISA_EXT_C, and RISCV_ISA_EXT_V?
My preference is to leave the mask on B/C/V (and A) as-is. I'd prefer to
keep matching on the single-letter, rather than expanding them. Here is why:
- The RVA23 profile lists A, B, C and V as single-letter mandatory
extensions; it doesn't enumerate Zaamo/Zalrsc, Zba/Zbb/Zbs, Zc* or the
Zve*/Zvl* subsets in the mandatory set.
- In current merged code, hwprobe_isa_ext0() is already using
riscv_isa_extension_available() signle letter checking for C and V.
PS:
B maybe a special one, just in case anybody raise it. As the community
discussed when I adding it into the bindings, because B comes later than
its sub-components zba/zbb/zbs, so, when I added B, I cleaned up all
in-tree dts files which declared zba/zbb/zbs but not B and made them declare
both.
Link: https://lore.kernel.org/linux-riscv/20260115-adding-b-dtsi-v2-0-254dd61cf947@xxxxxxxxxxxx/
[1]
Also, in the bindings: extensions.yaml, a schema rule is added which requires
a node listing zba, zbb and zbs to also list b (and the reverse). Moving on,
new dtsi/dts fils, a node with only the subsets fails dtbs_check.
One may argue that the schema check doesn't cover ACPI path. But again,
shouldn't the vendor who publishs RVA23 hardware be conformant to the
extensions wording in RVA23 v1.0 spec?
What do you think?
Thanks,
Guodong Xu
docularxu@xxxxxxxxxxx
>
> Additional nit below.
>
> >
> > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > index 739fcc84bf7b2..facc31b2960c6 100644
> > --- a/arch/riscv/include/asm/cpufeature.h
> > +++ b/arch/riscv/include/asm/cpufeature.h
> > @@ -25,10 +25,24 @@ struct riscv_cpuinfo {
> > unsigned long mimpid;
> > };
> >
> > +enum {
> > + RISCV_ISA_BASE_IMA,
> > + 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);
> > };
> >
> > +extern unsigned long riscv_isa_bases[BITS_TO_LONGS(RISCV_NR_ISA_BASES)];
> > +
> > DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
> >
> > extern const struct seq_operations cpuinfo_op;
> > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > index 81145621dc378..6e8dd33aa3888 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 */
> > static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
> >
> > +/* Host ISA bases bitmap */
> > +DECLARE_BITMAP(riscv_isa_bases, RISCV_NR_ISA_BASES) __read_mostly;
> > +
> > /* Per-cpu ISA extensions. */
> > struct riscv_isainfo hart_isa[NR_CPUS];
> >
> > @@ -1305,3 +1308,92 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
> > }
> > }
> > #endif
> > +
> > +/*
> > + * Compute the set of profile bases (IMA, RVA23U64, ...) a hart
> > + * conforms to, given 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 };
> > + DECLARE_BITMAP(tmp, RISCV_ISA_EXT_MAX);
> > +
> > + /* IMA */
> > + set_bit(RISCV_ISA_EXT_I, ext_mask);
> > + set_bit(RISCV_ISA_EXT_M, ext_mask);
> > + set_bit(RISCV_ISA_EXT_A, ext_mask);
> > +
> > + if (bitmap_andnot(tmp, ext_mask, isa, RISCV_ISA_EXT_MAX))
> > + return;
> > +
> > + set_bit(RISCV_ISA_BASE_IMA, bases);
> > +
> > + /* RVA23U64 */
> > +
> > + /* Zic64b and Supm with PMLEN=7 */
> > + if (riscv_cbom_block_size != 64 ||
> > + riscv_cbop_block_size != 64 ||
> > + riscv_cboz_block_size != 64 ||
> > + !riscv_have_user_pmlen(7))
> > + return;
> > +
> > + 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_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_andnot(tmp, 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;
> > +}
>
> Missing blank line here.
>
> Thanks,
> drew
>
> > +/*
> > + * Registered as subsys_initcall so it runs after
> > + * core_initcall(tagged_addr_init) populates have_user_pmlen_*.
> > + */
> > +subsys_initcall(riscv_init_isa_bases);
> >
> > --
> > 2.43.0
> >