diff --git a/crates/std_detect/README.md b/crates/std_detect/README.md index 5191b2f665..0053d777aa 100644 --- a/crates/std_detect/README.md +++ b/crates/std_detect/README.md @@ -56,11 +56,14 @@ crate from working on applications in which `std` is not available. [`cupid`](https://crates.io/crates/cupid) crate. * Linux/Android: - * `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `riscv{32,64}`, `loongarch64`, `s390x`: + * `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `loongarch64`, `s390x`: `std_detect` supports these on Linux by querying ELF auxiliary vectors (using `getauxval` when available), and if that fails, by querying `/proc/cpuinfo`. * `arm64`: partial support for doing run-time feature detection by directly querying `mrs` is implemented for Linux >= 4.11, but not enabled by default. + * `riscv{32,64}`: + `std_detect` supports these on Linux by querying `riscv_hwprobe`, and + by querying ELF auxiliary vectors (using `getauxval` when available). * FreeBSD: * `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF diff --git a/crates/std_detect/src/detect/arch/riscv.rs b/crates/std_detect/src/detect/arch/riscv.rs index 2368131fea..cab1b60705 100644 --- a/crates/std_detect/src/detect/arch/riscv.rs +++ b/crates/std_detect/src/detect/arch/riscv.rs @@ -79,14 +79,6 @@ features! { /// * P: `"p"` /// * Zam: `"zam"` /// - /// Defined by Privileged Specification: - /// - /// * Supervisor: `"s"` - /// * Svnapot: `"svnapot"` - /// * Svpbmt: `"svpbmt"` - /// * Svinval: `"svinval"` - /// * Hypervisor: `"h"` - /// /// [ISA manual]: https://github.com/riscv/riscv-isa-manual/ #[stable(feature = "riscv_ratified", since = "1.78.0")] @@ -125,6 +117,10 @@ features! { @FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] a: "a"; /// "A" Extension for Atomic Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zacas: "zacas"; + /// Atomic Compare-And-Swap Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zawrs: "zawrs"; + /// Wait on Reservation Set @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zam: "zam"; without cfg check: true; /// "Zam" Extension for Misaligned Atomics @@ -194,23 +190,59 @@ features! { @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] v: "v"; /// "V" Extension for Vector Operations + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfh: "zvfh"; + /// Vector Extension for Half-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfhmin: "zvfhmin"; + /// Vector Extension for Minimal Half-Precision Floating-Point + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32x: "zve32x"; + /// Vector Extensions for Embedded Processors + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32f: "zve32f"; + /// Vector Extensions for Embedded Processors + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64x: "zve64x"; + /// Vector Extensions for Embedded Processors + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64f: "zve64f"; + /// Vector Extensions for Embedded Processors + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64d: "zve64d"; + /// Vector Extensions for Embedded Processors - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] svnapot: "svnapot"; - without cfg check: true; - /// "Svnapot" Extension for NAPOT Translation Contiguity - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] svpbmt: "svpbmt"; - without cfg check: true; - /// "Svpbmt" Extension for Page-Based Memory Types - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] svinval: "svinval"; - without cfg check: true; - /// "Svinval" Extension for Fine-Grained Address-Translation Cache Invalidation - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] h: "h"; - without cfg check: true; - /// "H" Extension for Hypervisor Support + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkb: "zvkb"; + /// Vector Bit-manipulation used in Cryptography + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbb: "zvbb"; + /// Vector basic bit-manipulation instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbc: "zvbc"; + /// Vector Carryless Multiplication + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkg: "zvkg"; + /// Vector GCM instructions for Cryptography + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkned: "zvkned"; + /// Vector AES Encryption & Decryption (Single Round) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknha: "zvknha"; + /// Vector SHA-2 (SHA-256 only)) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknhb: "zvknhb"; + /// Vector SHA-2 (SHA-256 and SHA-512) + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksed: "zvksed"; + /// SM4 Block Cipher Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksh: "zvksh"; + /// SM3 Hash Function Instructions + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkn: "zvkn"; + /// Shorthand for 'Zvkned', 'Zvknhb', 'Zvkb', and 'Zvkt' + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknc: "zvknc"; + /// Shorthand for 'Zvkn' and 'Zvbc' + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkng: "zvkng"; + /// Shorthand for 'Zvkn' and 'Zvkg' + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvks: "zvks"; + /// Shorthand for 'Zvksed', 'Zvksh', 'Zvkb', and 'Zvkt' + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksc: "zvksc"; + /// Shorthand for 'Zvks' and 'Zvbc' + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksg: "zvksg"; + /// Shorthand for 'Zvks' and 'Zvkg' + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkt: "zvkt"; + /// Vector Data-Independent Execution Latency + + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_scalar_mem: "unaligned-scalar-mem"; + /// Has reasonably performant unaligned scalar + @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_vector_mem: "unaligned-vector-mem"; + /// Has reasonably performant unaligned vector - @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] s: "s"; - without cfg check: true; - /// Supervisor-Level ISA @FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] j: "j"; without cfg check: true; /// "J" Extension for Dynamically Translated Languages diff --git a/crates/std_detect/src/detect/os/linux/riscv.rs b/crates/std_detect/src/detect/os/linux/riscv.rs index 2a9671d75d..ae364e8804 100644 --- a/crates/std_detect/src/detect/os/linux/riscv.rs +++ b/crates/std_detect/src/detect/os/linux/riscv.rs @@ -1,11 +1,118 @@ //! Run-time feature detection for RISC-V on Linux. +//! +//! On RISC-V, detection using auxv only supports single-letter extensions. +//! So, we use riscv_hwprobe that supports multi-letter extensions if available. +//! + +use core::ptr; use super::auxvec; use crate::detect::{Feature, bit, cache}; -/// Read list of supported features from the auxiliary vector. +// See +// for riscv_hwprobe struct and RISCV_HWPROBE_* constants. + +#[repr(C)] +struct riscv_hwprobe { + key: i64, + value: u64, +} + +#[allow(non_upper_case_globals)] +const __NR_riscv_hwprobe: libc::c_long = 258; + +// const RISCV_HWPROBE_KEY_BASE_BEHAVIOR: i64 = 3; +// const RISCV_HWPROBE_BASE_BEHAVIOR_IMA: u64 = 1 << 0; + +const RISCV_HWPROBE_KEY_IMA_EXT_0: i64 = 4; +// const RISCV_HWPROBE_IMA_FD: u64 = 1 << 0; +// const RISCV_HWPROBE_IMA_C: u64 = 1 << 1; +// const RISCV_HWPROBE_IMA_V: u64 = 1 << 2; +const RISCV_HWPROBE_EXT_ZBA: u64 = 1 << 3; +const RISCV_HWPROBE_EXT_ZBB: u64 = 1 << 4; +const RISCV_HWPROBE_EXT_ZBS: u64 = 1 << 5; +// const RISCV_HWPROBE_EXT_ZICBOZ: u64 = 1 << 6; +const RISCV_HWPROBE_EXT_ZBC: u64 = 1 << 7; +const RISCV_HWPROBE_EXT_ZBKB: u64 = 1 << 8; +const RISCV_HWPROBE_EXT_ZBKC: u64 = 1 << 9; +const RISCV_HWPROBE_EXT_ZBKX: u64 = 1 << 10; +const RISCV_HWPROBE_EXT_ZKND: u64 = 1 << 11; +const RISCV_HWPROBE_EXT_ZKNE: u64 = 1 << 12; +const RISCV_HWPROBE_EXT_ZKNH: u64 = 1 << 13; +const RISCV_HWPROBE_EXT_ZKSED: u64 = 1 << 14; +const RISCV_HWPROBE_EXT_ZKSH: u64 = 1 << 15; +const RISCV_HWPROBE_EXT_ZKT: u64 = 1 << 16; +const RISCV_HWPROBE_EXT_ZVBB: u64 = 1 << 17; +const RISCV_HWPROBE_EXT_ZVBC: u64 = 1 << 18; +const RISCV_HWPROBE_EXT_ZVKB: u64 = 1 << 19; +const RISCV_HWPROBE_EXT_ZVKG: u64 = 1 << 20; +const RISCV_HWPROBE_EXT_ZVKNED: u64 = 1 << 21; +const RISCV_HWPROBE_EXT_ZVKNHA: u64 = 1 << 22; +const RISCV_HWPROBE_EXT_ZVKNHB: u64 = 1 << 23; +const RISCV_HWPROBE_EXT_ZVKSED: u64 = 1 << 24; +const RISCV_HWPROBE_EXT_ZVKSH: u64 = 1 << 25; +const RISCV_HWPROBE_EXT_ZVKT: u64 = 1 << 26; +const RISCV_HWPROBE_EXT_ZFH: u64 = 1 << 27; +const RISCV_HWPROBE_EXT_ZFHMIN: u64 = 1 << 28; +// const RISCV_HWPROBE_EXT_ZIHINTNTL: u64 = 1 << 29; +const RISCV_HWPROBE_EXT_ZVFH: u64 = 1 << 30; +const RISCV_HWPROBE_EXT_ZVFHMIN: u64 = 1 << 31; +// const RISCV_HWPROBE_EXT_ZFA: u64 = 1 << 32; +const RISCV_HWPROBE_EXT_ZTSO: u64 = 1 << 33; +const RISCV_HWPROBE_EXT_ZACAS: u64 = 1 << 34; +// const RISCV_HWPROBE_EXT_ZICOND: u64 = 1 << 35; +const RISCV_HWPROBE_EXT_ZIHINTPAUSE: u64 = 1 << 36; +// const RISCV_HWPROBE_EXT_ZVE32X: u64 = 1 << 37; +// const RISCV_HWPROBE_EXT_ZVE32F: u64 = 1 << 38; +// const RISCV_HWPROBE_EXT_ZVE64X: u64 = 1 << 39; +// const RISCV_HWPROBE_EXT_ZVE64F: u64 = 1 << 40; +// const RISCV_HWPROBE_EXT_ZVE64D: u64 = 1 << 41; +// const RISCV_HWPROBE_EXT_ZIMOP: u64 = 1 << 42; +// const RISCV_HWPROBE_EXT_ZCA: u64 = 1 << 43; +// const RISCV_HWPROBE_EXT_ZCB: u64 = 1 << 44; +// const RISCV_HWPROBE_EXT_ZCD: u64 = 1 << 45; +// const RISCV_HWPROBE_EXT_ZCF: u64 = 1 << 46; +// const RISCV_HWPROBE_EXT_ZCMOP: u64 = 1 << 47; +const RISCV_HWPROBE_EXT_ZAWRS: u64 = 1 << 48; +// const RISCV_HWPROBE_EXT_SUPM: u64 = 1 << 49; + +const RISCV_HWPROBE_KEY_CPUPERF_0: i64 = 5; +const RISCV_HWPROBE_MISALIGNED_FAST: u64 = 3; +const RISCV_HWPROBE_MISALIGNED_MASK: u64 = 7; + +const RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF: i64 = 10; +const RISCV_HWPROBE_MISALIGNED_VECTOR_FAST: u64 = 3; + +// syscall returns an unsupported error if riscv_hwprobe is not supported, +// so we can safely use this function on older versions of Linux. +fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool { + unsafe fn __riscv_hwprobe( + pairs: *mut riscv_hwprobe, + pair_count: libc::size_t, + cpu_set_size: libc::size_t, + cpus: *mut libc::c_ulong, + flags: libc::c_uint, + ) -> libc::c_long { + unsafe { + libc::syscall( + __NR_riscv_hwprobe, + pairs, + pair_count, + cpu_set_size, + cpus, + flags, + ) + } + } + + let len = out.len(); + unsafe { __riscv_hwprobe(out.as_mut_ptr(), len, 0, ptr::null_mut(), 0) == 0 } +} + +/// Read list of supported features from riscv_hwprobe or the auxiliary vector. pub(crate) fn detect_features() -> cache::Initializer { let mut value = cache::Initializer::default(); + let enable_feature = |value: &mut cache::Initializer, feature, enable| { if enable { value.set(feature as u32); @@ -46,29 +153,172 @@ pub(crate) fn detect_features() -> cache::Initializer { ); let has_i = bit::test(auxv.hwcap, (b'i' - b'a').into()); // If future RV128I is supported, implement with `enable_feature` here - #[cfg(target_pointer_width = "64")] + // Checking target_pointer_width instead of target_arch is incorrect since + // there are RV64ILP32* ABIs. + #[cfg(target_arch = "riscv64")] enable_feature(&mut value, Feature::rv64i, has_i); - #[cfg(target_pointer_width = "32")] + #[cfg(target_arch = "riscv32")] enable_feature(&mut value, Feature::rv32i, has_i); - #[cfg(target_pointer_width = "32")] + // FIXME: e is not exposed in any of asm/hwcap.h, uapi/asm/hwcap.h, uapi/asm/hwprobe.h + #[cfg(target_arch = "riscv32")] enable_feature( &mut value, Feature::rv32e, bit::test(auxv.hwcap, (b'e' - b'a').into()), ); - enable_feature( - &mut value, - Feature::h, - bit::test(auxv.hwcap, (b'h' - b'a').into()), - ); enable_feature( &mut value, Feature::m, bit::test(auxv.hwcap, (b'm' - b'a').into()), ); - // FIXME: Auxvec does not show supervisor feature support, but this mode may be useful - // to detect when Rust is used to write Linux kernel modules. - // These should be more than Auxvec way to detect supervisor features. + let has_v = bit::test(auxv.hwcap, (b'v' - b'a').into()); + enable_features( + &mut value, + &[ + Feature::v, + Feature::zve32f, + Feature::zve32x, + Feature::zve64d, + Feature::zve64f, + Feature::zve64x, + ], + has_v, + ); + + let mut out = [ + riscv_hwprobe { + key: RISCV_HWPROBE_KEY_IMA_EXT_0, + value: 0, + }, + riscv_hwprobe { + key: RISCV_HWPROBE_KEY_CPUPERF_0, + value: 0, + }, + riscv_hwprobe { + key: RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, + value: 0, + }, + ]; + if _riscv_hwprobe(&mut out) { + let mut enable_feature = |feature, enable| { + if enable { + value.set(feature as u32); + } + }; + if out[0].key != -1 { + let ima_ext_0 = out[0].value; + // i, m, a, f, d, zicsr, and c extensions are detected by hwcap. + // let fd = ima_ext_0 & RISCV_HWPROBE_IMA_FD != 0; + // enable_feature(Feature::f, fd); + // enable_feature(Feature::d, fd); + // enable_feature(Feature::zicsr, fd); // implied by f + // enable_feature(Feature::c, ima_ext_0 & RISCV_HWPROBE_IMA_C != 0); + // enable_feature(Feature::zicboz, ima_ext_0 & RISCV_HWPROBE_EXT_ZICBOZ != 0); + enable_feature(Feature::zfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZFH != 0); + enable_feature(Feature::zfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZFHMIN != 0); + // enable_feature(Feature::zihintntl, ima_ext_0 & RISCV_HWPROBE_EXT_ZIHINTNTL != 0); + // enable_feature(Feature::zfa, ima_ext_0 & RISCV_HWPROBE_EXT_ZFA != 0); + enable_feature(Feature::ztso, ima_ext_0 & RISCV_HWPROBE_EXT_ZTSO != 0); + enable_feature(Feature::zacas, ima_ext_0 & RISCV_HWPROBE_EXT_ZACAS != 0); + // enable_feature(Feature::zicond, ima_ext_0 & RISCV_HWPROBE_EXT_ZICOND != 0); + enable_feature( + Feature::zihintpause, + ima_ext_0 & RISCV_HWPROBE_EXT_ZIHINTPAUSE != 0, + ); + // enable_feature(Feature::zimop, ima_ext_0 & RISCV_HWPROBE_EXT_ZIMOP != 0); + // enable_feature(Feature::zca, ima_ext_0 & RISCV_HWPROBE_EXT_ZCA != 0); + // enable_feature(Feature::zcb, ima_ext_0 & RISCV_HWPROBE_EXT_ZCB != 0); + // enable_feature(Feature::zcd, ima_ext_0 & RISCV_HWPROBE_EXT_ZCD != 0); + // enable_feature(Feature::zcf, ima_ext_0 & RISCV_HWPROBE_EXT_ZCF != 0); + // enable_feature(Feature::zcmop, ima_ext_0 & RISCV_HWPROBE_EXT_ZCMOP != 0); + enable_feature(Feature::zawrs, ima_ext_0 & RISCV_HWPROBE_EXT_ZAWRS != 0); + // enable_feature(Feature::supm, ima_ext_0 & RISCV_HWPROBE_EXT_SUPM != 0); + // Bit-Manipulation ISA extensions + enable_feature(Feature::zba, ima_ext_0 & RISCV_HWPROBE_EXT_ZBA != 0); + enable_feature(Feature::zbb, ima_ext_0 & RISCV_HWPROBE_EXT_ZBB != 0); + enable_feature(Feature::zbs, ima_ext_0 & RISCV_HWPROBE_EXT_ZBS != 0); + enable_feature(Feature::zbc, ima_ext_0 & RISCV_HWPROBE_EXT_ZBC != 0); + // Scalar Crypto ISA extensions + let zbkb = ima_ext_0 & RISCV_HWPROBE_EXT_ZBKB != 0; + enable_feature(Feature::zbkb, zbkb); + let zbkc = ima_ext_0 & RISCV_HWPROBE_EXT_ZBKC != 0; + enable_feature(Feature::zbkc, zbkc); + let zbkx = ima_ext_0 & RISCV_HWPROBE_EXT_ZBKX != 0; + enable_feature(Feature::zbkx, zbkx); + let zknd = ima_ext_0 & RISCV_HWPROBE_EXT_ZKND != 0; + enable_feature(Feature::zknd, zknd); + let zkne = ima_ext_0 & RISCV_HWPROBE_EXT_ZKNE != 0; + enable_feature(Feature::zkne, zkne); + let zknh = ima_ext_0 & RISCV_HWPROBE_EXT_ZKNH != 0; + enable_feature(Feature::zknh, zknh); + let zksed = ima_ext_0 & RISCV_HWPROBE_EXT_ZKSED != 0; + enable_feature(Feature::zksed, zksed); + let zksh = ima_ext_0 & RISCV_HWPROBE_EXT_ZKSH != 0; + enable_feature(Feature::zksh, zksh); + let zkt = ima_ext_0 & RISCV_HWPROBE_EXT_ZKT != 0; + enable_feature(Feature::zkt, zkt); + let zkn = zbkb & zbkc & zbkx & zkne & zknd & zknh; + enable_feature(Feature::zkn, zkn); + // enable_feature(Feature::zk, zkn & zkr & zkt); + enable_feature(Feature::zks, zbkb & zbkc & zbkx & zksed & zksh); + // Refer result from hwcap because it reflects Vector enablement status, unlike hwprobe. + // prctl(PR_RISCV_V_GET_CONTROL) is another way to check this but it doesn't work with + // qemu-user (as of 9.2.1). + // See https://docs.kernel.org/arch/riscv/vector.html for more. + if has_v { + // Standard Vector Extensions + // v and zve{32,64}* extensions are detected by hwcap. + // enable_feature(Feature::v, ima_ext_0 & RISCV_HWPROBE_IMA_V != 0); + enable_feature(Feature::zvfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFH != 0); + enable_feature(Feature::zvfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFHMIN != 0); + // enable_feature(Feature::zve32x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32X != 0); + // enable_feature(Feature::zve32f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32F != 0); + // enable_feature(Feature::zve64x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64X != 0); + // enable_feature(Feature::zve64f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64F != 0); + // enable_feature(Feature::zve64d, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64D != 0); + // Vector Cryptography and Bit-manipulation Extensions + let zvbb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBB != 0; + enable_feature(Feature::zvbb, zvbb); + let zvbc = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBC != 0; + enable_feature(Feature::zvbc, zvbc); + let zvkb = zvbb || ima_ext_0 & RISCV_HWPROBE_EXT_ZVKB != 0; + enable_feature(Feature::zvkb, zvkb); + let zvkg = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKG != 0; + enable_feature(Feature::zvkg, zvkg); + let zvkned = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNED != 0; + enable_feature(Feature::zvkned, zvkned); + enable_feature(Feature::zvknha, ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHA != 0); + let zvknhb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHB != 0; + enable_feature(Feature::zvknhb, zvknhb); + let zvksed = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSED != 0; + enable_feature(Feature::zvksed, zvksed); + let zvksh = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSH != 0; + enable_feature(Feature::zvksh, zvksh); + let zvkt = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKT != 0; + enable_feature(Feature::zvkt, zvkt); + let zvkn = zvkned & zvknhb & zvkb & zvkt; + enable_feature(Feature::zvkn, zvkn); + enable_feature(Feature::zvknc, zvkn & zvbc); + enable_feature(Feature::zvkng, zvkn & zvkg); + let zvks = zvksed & zvksh & zvkb & zvkt; + enable_feature(Feature::zvks, zvks); + enable_feature(Feature::zvksc, zvks & zvbc); + enable_feature(Feature::zvksg, zvks & zvkg); + } + } + if out[1].key != -1 { + enable_feature( + Feature::unaligned_scalar_mem, + out[1].value & RISCV_HWPROBE_MISALIGNED_MASK == RISCV_HWPROBE_MISALIGNED_FAST, + ); + } + if out[2].key != -1 { + enable_feature( + Feature::unaligned_vector_mem, + out[2].value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST, + ); + } + } value } diff --git a/crates/std_detect/tests/cpu-detection.rs b/crates/std_detect/tests/cpu-detection.rs index 2c9cd95d29..9176f8f5b7 100644 --- a/crates/std_detect/tests/cpu-detection.rs +++ b/crates/std_detect/tests/cpu-detection.rs @@ -5,6 +5,10 @@ any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_aarch64_feature_detection) )] +#![cfg_attr( + any(target_arch = "riscv32", target_arch = "riscv64"), + feature(stdarch_riscv_feature_detection) +)] #![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))] #![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))] #![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))] @@ -15,6 +19,8 @@ target_arch = "arm", target_arch = "aarch64", target_arch = "arm64ec", + target_arch = "riscv32", + target_arch = "riscv64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", @@ -220,6 +226,92 @@ fn aarch64_darwin() { println!("sha3: {:?}", is_aarch64_feature_detected!("sha3")); } +#[test] +#[cfg(all( + any(target_arch = "riscv32", target_arch = "riscv64"), + any(target_os = "linux", target_os = "android") +))] +fn riscv_linux() { + println!("rv32i: {}", is_riscv_feature_detected!("rv32i")); + println!("rv32e: {}", is_riscv_feature_detected!("rv32e")); + println!("rv64i: {}", is_riscv_feature_detected!("rv64i")); + println!("rv128i: {}", is_riscv_feature_detected!("rv128i")); + println!("zicsr: {}", is_riscv_feature_detected!("zicsr")); + println!("zicntr: {}", is_riscv_feature_detected!("zicntr")); + println!("zihpm: {}", is_riscv_feature_detected!("zihpm")); + println!("zifencei: {}", is_riscv_feature_detected!("zifencei")); + println!("zihintpause: {}", is_riscv_feature_detected!("zihintpause")); + println!("m: {}", is_riscv_feature_detected!("m")); + println!("a: {}", is_riscv_feature_detected!("a")); + println!("zacas: {}", is_riscv_feature_detected!("zacas")); + println!("zawrs: {}", is_riscv_feature_detected!("zawrs")); + println!("zam: {}", is_riscv_feature_detected!("zam")); + println!("ztso: {}", is_riscv_feature_detected!("ztso")); + println!("f: {}", is_riscv_feature_detected!("f")); + println!("d: {}", is_riscv_feature_detected!("d")); + println!("q: {}", is_riscv_feature_detected!("q")); + println!("zfh: {}", is_riscv_feature_detected!("zfh")); + println!("zfhmin: {}", is_riscv_feature_detected!("zfhmin")); + println!("zfinx: {}", is_riscv_feature_detected!("zfinx")); + println!("zdinx: {}", is_riscv_feature_detected!("zdinx")); + println!("zhinx: {}", is_riscv_feature_detected!("zhinx")); + println!("zhinxmin: {}", is_riscv_feature_detected!("zhinxmin")); + println!("c: {}", is_riscv_feature_detected!("c")); + println!("zba: {}", is_riscv_feature_detected!("zba")); + println!("zbb: {}", is_riscv_feature_detected!("zbb")); + println!("zbc: {}", is_riscv_feature_detected!("zbc")); + println!("zbs: {}", is_riscv_feature_detected!("zbs")); + println!("zbkb: {}", is_riscv_feature_detected!("zbkb")); + println!("zbkc: {}", is_riscv_feature_detected!("zbkc")); + println!("zbkx: {}", is_riscv_feature_detected!("zbkx")); + println!("zknd: {}", is_riscv_feature_detected!("zknd")); + println!("zkne: {}", is_riscv_feature_detected!("zkne")); + println!("zknh: {}", is_riscv_feature_detected!("zknh")); + println!("zksed: {}", is_riscv_feature_detected!("zksed")); + println!("zksh: {}", is_riscv_feature_detected!("zksh")); + println!("zkr: {}", is_riscv_feature_detected!("zkr")); + println!("zksed: {}", is_riscv_feature_detected!("zksed")); + println!("zksh: {}", is_riscv_feature_detected!("zksh")); + println!("zkr: {}", is_riscv_feature_detected!("zkr")); + println!("zkn: {}", is_riscv_feature_detected!("zkn")); + println!("zks: {}", is_riscv_feature_detected!("zks")); + println!("zkt: {}", is_riscv_feature_detected!("zkt")); + println!("v: {}", is_riscv_feature_detected!("v")); + println!("zvfh: {}", is_riscv_feature_detected!("zvfh")); + println!("zvfhmin: {}", is_riscv_feature_detected!("zvfhmin")); + println!("zve32x: {}", is_riscv_feature_detected!("zve32x")); + println!("zve32f: {}", is_riscv_feature_detected!("zve32f")); + println!("zve64x: {}", is_riscv_feature_detected!("zve64x")); + println!("zve64f: {}", is_riscv_feature_detected!("zve64f")); + println!("zve64d: {}", is_riscv_feature_detected!("zve64d")); + println!("zvkb: {}", is_riscv_feature_detected!("zvkb")); + println!("zvbb: {}", is_riscv_feature_detected!("zvbb")); + println!("zvbc: {}", is_riscv_feature_detected!("zvbc")); + println!("zvkg: {}", is_riscv_feature_detected!("zvkg")); + println!("zvkned: {}", is_riscv_feature_detected!("zvkned")); + println!("zvknha: {}", is_riscv_feature_detected!("zvknha")); + println!("zvknhb: {}", is_riscv_feature_detected!("zvknhb")); + println!("zvksed: {}", is_riscv_feature_detected!("zvksed")); + println!("zvksh: {}", is_riscv_feature_detected!("zvksh")); + println!("zvkn: {}", is_riscv_feature_detected!("zvkn")); + println!("zvknc: {}", is_riscv_feature_detected!("zvknc")); + println!("zvkng: {}", is_riscv_feature_detected!("zvkng")); + println!("zvks: {}", is_riscv_feature_detected!("zvks")); + println!("zvksc: {}", is_riscv_feature_detected!("zvksc")); + println!("zvksg: {}", is_riscv_feature_detected!("zvksg")); + println!("zvkt: {}", is_riscv_feature_detected!("zvkt")); + println!( + "unaligned-scalar-mem: {}", + is_riscv_feature_detected!("unaligned-scalar-mem") + ); + println!( + "unaligned-vector-mem: {}", + is_riscv_feature_detected!("unaligned-vector-mem") + ); + println!("j: {}", is_riscv_feature_detected!("j")); + println!("p: {}", is_riscv_feature_detected!("p")); +} + #[test] #[cfg(all(target_arch = "powerpc", target_os = "linux"))] fn powerpc_linux() {