Re: [RFC PATCH v1 08/11] riscv: hwprobe: Introduce rva23u64 base behavior
From: Guodong Xu
Date: Fri Mar 06 2026 - 07:10:52 EST
Hi, Drew
On Fri, Feb 6, 2026 at 8:24 AM Andrew Jones
<andrew.jones@xxxxxxxxxxxxxxxx> wrote:
>
> Provide a bit to conveniently determine when RVA23U64 is supported.
> While it's already possible to determine RVA23U64 support with five
> hwprobe calls and four prctl calls it would be error-prone to require
> anything (and we presume eventually almost everything) that needs to
> check for RVA23U64 support to all implement those calls and specific
> checks. And, while RVA23U64 is the IMA base with mandated extensions,
> most software will consider it a new base. For these reasons, add
> the RVA23U64 bit as a base behavior bit.
>
> Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
> ---
> Documentation/arch/riscv/hwprobe.rst | 8 +++
> arch/riscv/include/uapi/asm/hwprobe.h | 3 +-
> arch/riscv/kernel/sys_hwprobe.c | 72 +++++++++++++++++++
> .../selftests/riscv/hwprobe/which-cpus.c | 2 +-
> 4 files changed, 83 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
> index 97226b7c5936..6d915e7ba58a 100644
> --- a/Documentation/arch/riscv/hwprobe.rst
> +++ b/Documentation/arch/riscv/hwprobe.rst
> @@ -67,6 +67,14 @@ The following keys are defined:
> programs (it may still be executed in userspace via a
> kernel-controlled mechanism such as the vDSO).
>
> + * :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64`: Support for all mandatory
> + extensions of RVA23U64, as defined in the RISC-V Profiles specification
> + starting from commit b1d80660 ("Updated to ratified state.")
> +
> + The RVA23U64 base is based upon the IMA base and therefore IMA extension
> + keys (e.g. :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`:) may be used to probe
> + optional extensions.
> +
> * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing the extensions
> that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`:
> base system behavior.
> diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
> index fed9ea6fd2b5..72d2a4d0b733 100644
> --- a/arch/riscv/include/uapi/asm/hwprobe.h
> +++ b/arch/riscv/include/uapi/asm/hwprobe.h
> @@ -21,7 +21,8 @@ struct riscv_hwprobe {
> #define RISCV_HWPROBE_KEY_MARCHID 1
> #define RISCV_HWPROBE_KEY_MIMPID 2
> #define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
> -#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0)
> +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0)
> +#define RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64 (1 << 1)
> #define RISCV_HWPROBE_KEY_IMA_EXT_0 4
> #define RISCV_HWPROBE_IMA_FD (1 << 0)
> #define RISCV_HWPROBE_IMA_C (1 << 1)
> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> index 31d222301bf0..4b9981b15ebe 100644
> --- a/arch/riscv/kernel/sys_hwprobe.c
> +++ b/arch/riscv/kernel/sys_hwprobe.c
> @@ -23,6 +23,7 @@
> #include <asm/vendor_extensions/thead_hwprobe.h>
> #include <vdso/vsyscall.h>
>
> +extern bool riscv_have_user_pmlen_7;
>
> #define EXT_KEY(isa_arg, ext, pv, missing) \
> do { \
> @@ -222,6 +223,75 @@ static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext)
> return (pair.value & ext);
> }
>
> +#define HWPROBE_EXT0_RVA23U64 ( \
> + /* IMA is always supported */ \
> + RISCV_HWPROBE_IMA_FD | \
> + RISCV_HWPROBE_IMA_C | \
> + /* B is Zba, Zbb and Zbs */ \
> + RISCV_HWPROBE_EXT_ZBA | \
> + RISCV_HWPROBE_EXT_ZBB | \
> + RISCV_HWPROBE_EXT_ZBS | \
> + /* ZICSR is always supported */ \
About Zicsr always?
It is not rigorous compared to the other extensions that are checked
explicitly.
With the deprecated 'riscv,isa' DT string (ACPI doesn't do this),
"i" implies zicsr (along with zicntr, zifencei, zihpm). But with
'riscv,isa-extensions', zicsr must be listed explicitly, it is not
automatically derived from "i". (see cputfeature.c)
BTW, this also serves as an example where:
- RISCV_ISA_EXT_ZICSR exists, (your patch 10 checked it)
- but no corresponding hwprobe export RISCV_HWPROBE_EXT_ZICSR.
So, as I suggested, it's better we detect rva23u64 as a combination of
RISCV_ISA_EXT_...; instead of using RISCV_HWPROBE_EXT_...
> + RISCV_HWPROBE_EXT_ZICNTR | \
> + RISCV_HWPROBE_EXT_ZIHPM | \
> + /* ZICCIF is in EXT1 */ \
> + /* ZICCRSE is in EXT1 */ \
> + /* ZICCAMOA is in EXT1 */ \
> + RISCV_HWPROBE_EXT_ZICCLSM | \
> + /* ZA64RS is in EXT1 */ \
> + RISCV_HWPROBE_EXT_ZIHINTPAUSE | \
> + /* ZIC64B (check block sizes are 64b) */ \
> + RISCV_HWPROBE_EXT_ZICBOM | \
> + RISCV_HWPROBE_EXT_ZICBOP | \
> + RISCV_HWPROBE_EXT_ZICBOZ | \
> + RISCV_HWPROBE_EXT_ZFHMIN | \
> + RISCV_HWPROBE_EXT_ZKT | \
> + RISCV_HWPROBE_IMA_V | \
> + RISCV_HWPROBE_EXT_ZVFHMIN | \
> + RISCV_HWPROBE_EXT_ZVBB | \
> + RISCV_HWPROBE_EXT_ZVKT | \
> + RISCV_HWPROBE_EXT_ZIHINTNTL | \
> + RISCV_HWPROBE_EXT_ZICOND | \
> + RISCV_HWPROBE_EXT_ZIMOP | \
> + RISCV_HWPROBE_EXT_ZCMOP | \
> + RISCV_HWPROBE_EXT_ZCB | \
> + RISCV_HWPROBE_EXT_ZFA | \
> + RISCV_HWPROBE_EXT_ZAWRS | \
> + RISCV_HWPROBE_EXT_SUPM /* (check PMLEN=7 support) */ \
> +)
> +
> +#define HWPROBE_EXT1_RVA23U64 ( \
> + RISCV_HWPROBE_EXT_ZICCIF | \
> + RISCV_HWPROBE_EXT_ZICCRSE | \
> + RISCV_HWPROBE_EXT_ZICCAMOA | \
> + RISCV_HWPROBE_EXT_ZA64RS \
> +)
> +
> +static bool hwprobe_has_rva23u64(const struct cpumask *cpus)
> +{
> + struct riscv_hwprobe pair;
> +
> + if (!IS_ENABLED(CONFIG_64BIT))
> + return false;
> +
> + /* Additional mandates for Zic64b and Supm */
> + if (riscv_cbom_block_size != 64 ||
> + riscv_cbop_block_size != 64 ||
> + riscv_cboz_block_size != 64 ||
> + !riscv_have_user_pmlen_7)
> + return false;
> +
> + hwprobe_isa_ext0(&pair, cpus);
> + if ((pair.value & HWPROBE_EXT0_RVA23U64) != HWPROBE_EXT0_RVA23U64)
> + return false;
> +
> + hwprobe_isa_ext1(&pair, cpus);
> + if ((pair.value & HWPROBE_EXT1_RVA23U64) != HWPROBE_EXT1_RVA23U64)
> + return false;
> +
> + return true;
> +}
For record purpose, I double checked the above list and function:
all 33 mandatory extensions required by RVA23U64 are checked in this
patch, none missing.
BR,
Guodong
> +
> #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
> static u64 hwprobe_misaligned(const struct cpumask *cpus)
> {
> @@ -312,6 +382,8 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
> */
> case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
> pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
> + if (hwprobe_has_rva23u64(cpus))
> + pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64;
> break;
>
> case RISCV_HWPROBE_KEY_IMA_EXT_0:
> diff --git a/tools/testing/selftests/riscv/hwprobe/which-cpus.c b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
> index 587feb198c04..f8c797b1d0fd 100644
> --- a/tools/testing/selftests/riscv/hwprobe/which-cpus.c
> +++ b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
> @@ -105,7 +105,7 @@ int main(int argc, char **argv)
> pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, };
> rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
> assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR &&
> - pairs[0].value == RISCV_HWPROBE_BASE_BEHAVIOR_IMA);
> + (pairs[0].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA));
>
> pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, };
> rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
> --
> 2.43.0
>