]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
riscv: features: add support for detecting V/Zbc via hwprobe
authorIcenowy Zheng <uwu@icenowy.me>
Wed, 28 Jan 2026 08:13:56 +0000 (16:13 +0800)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Sun, 1 Feb 2026 12:06:43 +0000 (13:06 +0100)
Adding support for riscv_hwprobe and detecting V/Zbc via it.

The needed macros should be in Linux 6.12 UAPI headers, which are
shipped by Debian Trixie.

Tested via qemu-user that the Zbc codepath is examined by adding some
code there.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
arch/riscv/riscv_features.c

index 99837349da9f5d06bc1b1eadcc0340a822ff6adf..b23f10a699a9f7125e6a9d125dbe5e02b43d9bf6 100644 (file)
@@ -1,5 +1,7 @@
 #ifdef RISCV_FEATURES
 
+#define _DEFAULT_SOURCE 1 /* For syscall() */
+
 #include "zbuild.h"
 #include "riscv_features.h"
 
@@ -9,9 +11,49 @@
 #  include <sys/auxv.h>
 #endif
 
+#if defined(__linux__) && defined(HAVE_ASM_HWPROBE_H)
+#  include <asm/hwprobe.h>
+#  include <sys/syscall.h> /* For __NR_riscv_hwprobe */
+#  include <unistd.h> /* For syscall() */
+#endif
+
 #define ISA_V_HWCAP (1 << ('v' - 'a'))
 #define ISA_ZBC_HWCAP (1 << 29)
 
+static int riscv_check_features_runtime_hwprobe(struct riscv_cpu_features *features) {
+#if defined(__NR_riscv_hwprobe) && defined(RISCV_HWPROBE_KEY_IMA_EXT_0)
+    struct riscv_hwprobe probes[] = {
+        {RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
+    };
+    int ret;
+    unsigned i;
+
+    ret = syscall(__NR_riscv_hwprobe, probes, sizeof(probes) / sizeof(probes[0]), 0, NULL, 0);
+
+    if (ret != 0) {
+        /* Kernel does not support hwprobe */
+        return 0;
+    }
+
+    for (i = 0; i < sizeof(probes) / sizeof(probes[0]); i++) {
+        switch (probes[i].key) {
+        case RISCV_HWPROBE_KEY_IMA_EXT_0:
+#  ifdef RISCV_HWPROBE_IMA_V
+            features->has_rvv = !!(probes[i].value & RISCV_HWPROBE_IMA_V);
+#  endif
+#  ifdef RISCV_HWPROBE_EXT_ZBC
+            features->has_zbc = !!(probes[i].value & RISCV_HWPROBE_EXT_ZBC);
+#  endif
+            break;
+        }
+    }
+
+    return 1;
+#else
+    return 0;
+#endif
+}
+
 static int riscv_check_features_runtime_hwcap(struct riscv_cpu_features *features) {
 #if defined(__linux__) && defined(HAVE_SYS_AUXV_H)
     unsigned long hw_cap = getauxval(AT_HWCAP);
@@ -26,6 +68,9 @@ static int riscv_check_features_runtime_hwcap(struct riscv_cpu_features *feature
 }
 
 static void riscv_check_features_runtime(struct riscv_cpu_features *features) {
+    if (riscv_check_features_runtime_hwprobe(features))
+        return;
+
     riscv_check_features_runtime_hwcap(features);
 }