[PATCH v7 09/11] riscv: cpufeature: Introduce ISA bases bitmap and rva23u64 detection
From: Guodong Xu <hidden>
Date: 2026-09-15 07:17:33
Also in:
linux-devicetree, linux-kselftest, linux-riscv, lkml, spacemit
Subsystem:
risc-v architecture, the rest · Maintainers:
Paul Walmsley, Palmer Dabbelt, Albert Ou, Linus Torvalds
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(). 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. Signed-off-by: Andrew Jones <redacted> Signed-off-by: Guodong Xu <redacted> --- 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 | 113 ++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+)
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b2..89c64d42ee745 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, + 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);
@@ -130,6 +142,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 de7cff5f48c34..f88031660e6fc 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 */ +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) {
@@ -1334,3 +1357,93 @@ 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 }; + + /* 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_subset(ext_mask, isa, RISCV_ISA_EXT_MAX)) + return; + + set_bit(RISCV_ISA_BASE_IMA, bases); + + /* RVA23U64 */ + + /* Supm with PMLEN=7 */ + if (!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_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);
--
2.43.0