summaryrefslogtreecommitdiff
path: root/neozip/arch/riscv/riscv_features.c
diff options
context:
space:
mode:
Diffstat (limited to 'neozip/arch/riscv/riscv_features.c')
-rw-r--r--neozip/arch/riscv/riscv_features.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/neozip/arch/riscv/riscv_features.c b/neozip/arch/riscv/riscv_features.c
new file mode 100644
index 0000000000..b23f10a699
--- /dev/null
+++ b/neozip/arch/riscv/riscv_features.c
@@ -0,0 +1,99 @@
+#ifdef RISCV_FEATURES
+
+#define _DEFAULT_SOURCE 1 /* For syscall() */
+
+#include "zbuild.h"
+#include "riscv_features.h"
+
+#include <sys/utsname.h>
+
+#if defined(__linux__) && defined(HAVE_SYS_AUXV_H)
+# 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);
+
+ features->has_rvv = hw_cap & ISA_V_HWCAP;
+ features->has_zbc = hw_cap & ISA_ZBC_HWCAP;
+
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+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);
+}
+
+void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) {
+ riscv_check_features_runtime(features);
+#ifdef RISCV_RVV
+ if (features->has_rvv) {
+ size_t e8m1_vec_len;
+ intptr_t vtype_reg_val;
+ // Check that a vuint8m1_t vector is at least 16 bytes and that tail
+ // agnostic and mask agnostic mode are supported
+ //
+ __asm__ volatile(
+ "vsetvli %0, zero, e8, m1, ta, ma\n\t"
+ "csrr %1, vtype"
+ : "=r"(e8m1_vec_len), "=r"(vtype_reg_val));
+
+ // The RVV target is supported if the VILL bit of VTYPE (the MSB bit of
+ // VTYPE) is not set and the length of a vuint8m1_t vector is at least 16
+ // bytes
+ features->has_rvv = (vtype_reg_val >= 0 && e8m1_vec_len >= 16);
+ }
+#endif
+}
+
+#endif