From: Xeonacid Date: Sun, 8 Oct 2023 03:30:54 +0000 (+0800) Subject: Support RVV hwcap detect at runtime X-Git-Tag: 2.1.4~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6ff8b52cefe56a824fae1d53fdd687bcde2e53c9;p=thirdparty%2Fzlib-ng.git Support RVV hwcap detect at runtime Fallback to compile-time detect if kernel version lower than 6.5. Co-authored-by: Hans Kristian Rosbach Signed-off-by: Xeonacid --- diff --git a/arch/riscv/README.md b/arch/riscv/README.md index b4309e1a..013095c3 100644 --- a/arch/riscv/README.md +++ b/arch/riscv/README.md @@ -1,10 +1,10 @@ # 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). diff --git a/arch/riscv/riscv_features.c b/arch/riscv/riscv_features.c index 362d7148..b066f427 100644 --- a/arch/riscv/riscv_features.c +++ b/arch/riscv/riscv_features.c @@ -1,15 +1,45 @@ #include #include #include +#include +#include #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); +}