# Building RISC-V Target with Cmake #
> **Warning**
-> We cannot detect rvv support at runtime, running the rvv code on a no-rvv target is a risk. Users should disable the rvv when the target does not support it.
+> Runtime rvv detection (using `hwcap`) requires linux kernel 6.5 or newer.
>
-> We will have a better solution when the kernels update `hwcap` or `hwprobe` for risc-v.
-
+> When running on older kernels, we fall back to compile-time detection, potentially this can cause crashes if rvv is enabled at compile but not supported by the target cpu.
+> Therefore if older kernel support is needed, rvv should be disabled if the target cpu does not support it.
## Prerequisite: Build RISC-V Clang Toolchain and QEMU ##
If you don't have prebuilt clang and riscv64 qemu, you can refer to the [script](https://github.com/sifive/prepare-riscv-toolchain-qemu/blob/main/prepare_riscv_toolchain_qemu.sh) to get the source. Copy the script to the zlib-ng root directory, and run it to download the source and build them. Modify the content according to your conditions (e.g., toolchain version).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/auxv.h>
+#include <sys/utsname.h>
#include "../../zbuild.h"
#include "riscv_features.h"
-/* TODO: detect risc-v cpu info at runtime when the kernel updates hwcap or hwprobe for risc-v */
-void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) {
+#define ISA_V_HWCAP (1 << ('v' - 'a'))
+
+int Z_INTERNAL is_kernel_version_greater_or_equal_to_6_5() {
+ struct utsname buffer;
+ uname(&buffer);
+
+ int major, minor;
+ if (sscanf(buffer.release, "%d.%d", &major, &minor) != 2) {
+ // Something bad with uname()
+ return 0;
+ }
+
+ if (major > 6 || major == 6 && minor >= 5)
+ return 1;
+ return 0;
+}
+
+void Z_INTERNAL riscv_check_features_compile_time(struct riscv_cpu_features *features) {
#if defined(__riscv_v) && defined(__linux__)
features->has_rvv = 1;
#else
features->has_rvv = 0;
#endif
}
+
+void Z_INTERNAL riscv_check_features_runtime(struct riscv_cpu_features *features) {
+ unsigned long hw_cap = getauxval(AT_HWCAP);
+ features->has_rvv = hw_cap & ISA_V_HWCAP;
+}
+
+void Z_INTERNAL riscv_check_features(struct riscv_cpu_features *features) {
+ if (is_kernel_version_greater_or_equal_to_6_5())
+ riscv_check_features_runtime(features);
+ else
+ riscv_check_features_compile_time(features);
+}