[PATCH v2] riscv: hwprobe: allow querying available RISCV_HWPROBE_KEY_IMA_EXT_0 bits
Alexandre Ghiti
alex at ghiti.fr
Thu Aug 14 05:55:07 PDT 2025
On 8/14/25 13:57, Paris Oplopoios wrote:
>> What about parsing the isa string?
> Yes, parsing the ISA string would work. But if we're going
> to do that, we might as well not use hwprobe at all. In my
> opinion, using the syscall is much easier to implement and maintain.
You're right.
>
>
>> And do you have a real usecase in
>> mind? I mean which project would benefit from this?
> Yes, I want this feature for an x86-on-RISC-V userspace emulator
> called felix86. We do runtime extension detection for our JIT.
> Currently, for any extension that defines instructions we use the SIGILL
> method previously described, because there's no way to tell with just
> a hwprobe call whether a 0 bit means extension not present or kernel
> too old. But we can't do this for all extensions, some don't define
> instructions.
>
> The end goal would be being able to detect an extension using hwprobe, and if
> it's not detectable, notifying the user that we can't detect it and
> they can mark
> it as enabled in the emulator's config file.
Ok, I'm not opposed anymore, but I have added Conor in cc to have his
opinion. Can you add that ^ to the change log? And now let's talk about
the patch, see my comments below.
>
> On Thu, 14 Aug 2025 at 14:22, Alexandre Ghiti <alex at ghiti.fr> wrote:
>> On 8/14/25 12:32, Paris Oplopoios wrote:
>>> Hello Alexandre,
>>>
>>>> trying to figure out if an extension is available will likely result in a SIGILL, so that will kill your application
>>> SIGILL can be captured with a signal handler and extension support can
>>> be checked this way. Not all extensions can be detected using this
>>> method, and it's much more straightforward to ask the kernel.
>>>
>>>> Why don't you check the kernel config or even the hwprobe.h header? Since basically here, you use a syscall to return an information that is visible already from userspace.
>>> To give an example, imagine a new extension Znew comes out, it
>>> occupies the bit 1<<59. Let's say my kernel version was built with
>>> support for detecting it and yours wasn't, but we both have the same
>>> hardware. I compile a binary of a program that wants to do runtime
>>> extension detection and I want to distribute it.
>>>
>>> If I use the config or the hwprobe.h header during compilation time,
>>> the compiled binary is assuming that both mine and your system have
>>> this new bit. So when my program tries to detect it, it will find it
>>> on my hardware but not yours. That's because my kernel was built to
>>> support this bit in hwprobe but yours wasn't.
>>>
>>> But in reality your hardware does have the extension. However, how
>>> will my program differentiate from "doesn't have an extension" and
>>> "kernel version not new enough"? Maybe I'd like to know that the
>>> kernel doesn't have the bit, and notify the user with an "update your
>>> kernel" message. Maybe I'd like to do the fallback SIGILL extension
>>> detection instead.
>>
>> What about parsing the isa string? And do you have a real usecase in
>> mind? I mean which project would benefit from this?
>>
>>
>>> PS: I'm assuming you meant checking config/hwprobe.h at compilation
>>> time. If you meant parsing it at runtime, that simply wouldn't be
>>> possible on all environments (think chroots).
>>>
>>> On Thu, 14 Aug 2025 at 12:37, Alexandre Ghiti <alex at ghiti.fr> wrote:
>>>> Hi Paris,
>>>>
>>>> On 8/13/25 20:05, offtkp wrote:
>>>>> When probing for extensions using RISCV_HWPROBE_KEY_IMA_EXT_0, a missing
>>>>> bit in the resulting bitmask means the extension is not available or the
>>>>> kernel is not recent enough to support the bit. Currently, there's no
>>>>> way to differentiate between the two.
>>>>>
>>>>> This adds a new riscv_hwprobe key, RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL,
>>>>> which returns a bitmask of all the queryable extensions supported by the
>>>>> kernel in RISCV_HWPROBE_KEY_IMA_EXT_0. This can allow programs to use a
>>>>> fallback extension detection method when the bit they want to query is
>>>>> not available in the kernel they are running on.
>>>> Admittedly, I'm not convinced this is necessary. As you showed in your
>>>> v1, trying to figure out if an extension is available will likely result
>>>> in a SIGILL, so that will kill your application. Why don't you check the
>>>> kernel config or even the hwprobe.h header? Since basically here, you
>>>> use a syscall to return an information that is visible already from
>>>> userspace.
>>>>
>>>> But maybe I'm missing an interesting usecase, just let me know.
>>>>
>>>> Thanks,
>>>>
>>>> Alex
>>>>
>>>>
>>>>> Signed-off-by: offtkp <parisoplop at gmail.com>
>>>>> ---
>>>>> Changes in v2:
>>>>> - convert spaces to tabs
>>>>> - use git format-patch to create diff
>>>>>
>>>>> Documentation/arch/riscv/hwprobe.rst | 5 ++++-
>>>>> arch/riscv/include/asm/hwprobe.h | 3 ++-
>>>>> arch/riscv/include/uapi/asm/hwprobe.h | 2 ++
>>>>> arch/riscv/kernel/sys_hwprobe.c | 4 ++++
>>>>> 4 files changed, 12 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
>>>>> index 2aa9be272d5d..6d77def0a46e 100644
>>>>> --- a/Documentation/arch/riscv/hwprobe.rst
>>>>> +++ b/Documentation/arch/riscv/hwprobe.rst
>>>>> @@ -360,4 +360,7 @@ The following keys are defined:
>>>>>
>>>>> * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq
>>>>> vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
>>>>> - Instruction Extensions Specification.
>>>>> \ No newline at end of file
>>>>> + Instruction Extensions Specification.
>>>>> +
>>>>> +* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL`: A bitmask containing the extensions
>>>>> + that can be probed using the :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0` key.
>>>>> \ No newline at end of file
>>>>> diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h
>>>>> index 7fe0a379474a..501d49b7a02a 100644
>>>>> --- a/arch/riscv/include/asm/hwprobe.h
>>>>> +++ b/arch/riscv/include/asm/hwprobe.h
>>>>> @@ -8,7 +8,8 @@
>>>>>
>>>>> #include <uapi/asm/hwprobe.h>
>>>>>
>>>>> -#define RISCV_HWPROBE_MAX_KEY 13
>>>>> +#define RISCV_HWPROBE_MAX_KEY 14
>>>>> +#define RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL_VALUE ((1ULL << 59) - 1)
59 should not be hardcoded, even with your comment below. Let's
introduce something like RISCV_HWPROBE_EXT_COUNT or similar.
>>>>>
>>>>> static inline bool riscv_hwprobe_key_is_valid(__s64 key)
>>>>> {
>>>>> diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
>>>>> index aaf6ad970499..a3b92df4dc05 100644
>>>>> --- a/arch/riscv/include/uapi/asm/hwprobe.h
>>>>> +++ b/arch/riscv/include/uapi/asm/hwprobe.h
>>>>> @@ -82,6 +82,7 @@ struct riscv_hwprobe {
>>>>> #define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56)
>>>>> #define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57)
>>>>> #define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58)
>>>>> +/* Change RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL_VALUE when adding items. */
>>>>> #define RISCV_HWPROBE_KEY_CPUPERF_0 5
>>>>> #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
>>>>> #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
>>>>> @@ -106,6 +107,7 @@ struct riscv_hwprobe {
>>>>> #define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0 11
>>>>> #define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12
>>>>> #define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13
>>>>> +#define RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL 14
>>>>> /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
>>>>>
>>>>> /* Flags */
>>>>> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
>>>>> index 0b170e18a2be..40e7fa5f85f3 100644
>>>>> --- a/arch/riscv/kernel/sys_hwprobe.c
>>>>> +++ b/arch/riscv/kernel/sys_hwprobe.c
>>>>> @@ -310,6 +310,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
>>>>> hwprobe_isa_vendor_ext_thead_0(pair, cpus);
>>>>> break;
>>>>>
>>>>> + case RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL:
>>>>> + pair->value = RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL_VALUE;
You don't really need to return a mask here, you can simply return
RISCV_HWPROBE_EXT_COUNT and let the userspace deal with the mask.
>>>>> + break;
>>>>> +
>>>>> /*
>>>>> * For forward compatibility, unknown keys don't fail the whole
>>>>> * call, but get their element key set to -1 and value set to 0
>>>>>
>>>>> _______________________________________________
>>>>> linux-riscv mailing list
>>>>> linux-riscv at lists.infradead.org
>>>>> http://lists.infradead.org/mailman/listinfo/linux-riscv
More information about the linux-riscv
mailing list