Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c29e969

Browse files
committedMar 30, 2025·
std_detect: Use riscv_hwprobe on RISC-V Linux/Android
1 parent 65712f3 commit c29e969

File tree

4 files changed

+459
-8
lines changed

4 files changed

+459
-8
lines changed
 

‎crates/std_detect/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,15 @@ crate from working on applications in which `std` is not available.
5656
[`cupid`](https://crates.io/crates/cupid) crate.
5757

5858
* Linux/Android:
59-
* `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `riscv{32,64}`, `loongarch64`, `s390x`:
59+
* `arm{32, 64}`, `mips{32,64}{,el}`, `powerpc{32,64}{,le}`, `loongarch64`, `s390x`:
6060
`std_detect` supports these on Linux by querying ELF auxiliary vectors (using `getauxval`
6161
when available), and if that fails, by querying `/proc/cpuinfo`.
6262
* `arm64`: partial support for doing run-time feature detection by directly
6363
querying `mrs` is implemented for Linux >= 4.11, but not enabled by default.
64+
* `riscv{32,64}`:
65+
`std_detect` supports these on Linux by querying `riscv_hwprobe`, and
66+
by querying ELF auxiliary vectors (using `getauxval` when available), and if that fails,
67+
by querying `/proc/self/auxv`.
6468

6569
* FreeBSD:
6670
* `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF

‎crates/std_detect/src/detect/arch/riscv.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ features! {
125125
126126
@FEATURE: #[stable(feature = "riscv_ratified", since = "1.78.0")] a: "a";
127127
/// "A" Extension for Atomic Instructions
128+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zacas: "zacas";
129+
/// Atomic Compare-And-Swap Instructions
130+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zawrs: "zawrs";
131+
/// Wait on Reservation Set
128132
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zam: "zam";
129133
without cfg check: true;
130134
/// "Zam" Extension for Misaligned Atomics
@@ -194,6 +198,86 @@ features! {
194198
195199
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] v: "v";
196200
/// "V" Extension for Vector Operations
201+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfh: "zvfh";
202+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
203+
/// Vector Extension for Half-Precision Floating-Point
204+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvfhmin: "zvfhmin";
205+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
206+
/// Vector Extension for Minimal Half-Precision Floating-Point
207+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32x: "zve32x";
208+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
209+
/// Vector Extensions for Embedded Processors
210+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve32f: "zve32f";
211+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
212+
/// Vector Extensions for Embedded Processors
213+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64x: "zve64x";
214+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
215+
/// Vector Extensions for Embedded Processors
216+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64f: "zve64f";
217+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
218+
/// Vector Extensions for Embedded Processors
219+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zve64d: "zve64d";
220+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
221+
/// Vector Extensions for Embedded Processors
222+
223+
// FIXME: we can implement this by getting the current vlen
224+
// i.e., "csrr {vlen}, vlenb" + "slli {vlen}, {vlen}, 3"
225+
// zvl*b: Minimum Vector Length Standard Extensions
226+
227+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkb: "zvkb";
228+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
229+
/// Vector Bit-manipulation used in Cryptography
230+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbb: "zvbb";
231+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
232+
/// Vector basic bit-manipulation instructions
233+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvbc: "zvbc";
234+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
235+
/// Vector Carryless Multiplication
236+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkg: "zvkg";
237+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
238+
/// Vector GCM instructions for Cryptography
239+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkned: "zvkned";
240+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
241+
/// Vector AES Encryption & Decryption (Single Round)
242+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknha: "zvknha";
243+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
244+
/// Vector SHA-2 (SHA-256 only))
245+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknhb: "zvknhb";
246+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
247+
/// Vector SHA-2 (SHA-256 and SHA-512)
248+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksed: "zvksed";
249+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
250+
/// SM4 Block Cipher Instructions
251+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksh: "zvksh";
252+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
253+
/// SM3 Hash Function Instructions
254+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkn: "zvkn";
255+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
256+
/// Shorthand for 'Zvkned', 'Zvknhb', 'Zvkb', and 'Zvkt'
257+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvknc: "zvknc";
258+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
259+
/// Shorthand for 'Zvkn' and 'Zvbc'
260+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkng: "zvkng";
261+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
262+
/// Shorthand for 'Zvkn' and 'Zvkg'
263+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvks: "zvks";
264+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
265+
/// Shorthand for 'Zvksed', 'Zvksh', 'Zvkb', and 'Zvkt'
266+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksc: "zvksc";
267+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
268+
/// Shorthand for 'Zvks' and 'Zvbc'
269+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvksg: "zvksg";
270+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
271+
/// Shorthand for 'Zvks' and 'Zvkg'
272+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] zvkt: "zvkt";
273+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
274+
/// Vector Data-Independent Execution Latency
275+
276+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_scalar_mem: "unaligned-scalar-mem";
277+
/// Has reasonably performant unaligned scalar
278+
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] unaligned_vector_mem: "unaligned-vector-mem";
279+
without cfg check: true; // FIXME: added in https://github.com/rust-lang/rust/pull/138742
280+
/// Has reasonably performant unaligned vector
197281
198282
@FEATURE: #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")] svnapot: "svnapot";
199283
without cfg check: true;

‎crates/std_detect/src/detect/os/linux/riscv.rs

Lines changed: 273 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,268 @@
11
//! Run-time feature detection for RISC-V on Linux.
2+
//!
3+
//! On RISC-V, detection using auxv only supports single-letter extensions.
4+
//! So, we use riscv_hwprobe that supports multi-letter extensions if available.
5+
//! <https://www.kernel.org/doc/html/latest/arch/riscv/hwprobe.html>
6+
7+
use core::ptr;
28

39
use super::auxvec;
410
use crate::detect::{Feature, bit, cache};
511

6-
/// Read list of supported features from the auxiliary vector.
12+
// See <https://github.com/torvalds/linux/blob/master/arch/riscv/include/uapi/asm/hwprobe.h>
13+
// for riscv_hwprobe struct and RISCV_HWPROBE_* constants.
14+
15+
#[repr(C)]
16+
struct riscv_hwprobe {
17+
key: i64,
18+
value: u64,
19+
}
20+
21+
#[allow(non_upper_case_globals)]
22+
const __NR_riscv_hwprobe: libc::c_long = 258;
23+
24+
const RISCV_HWPROBE_KEY_BASE_BEHAVIOR: i64 = 3;
25+
const RISCV_HWPROBE_BASE_BEHAVIOR_IMA: u64 = 1 << 0;
26+
27+
const RISCV_HWPROBE_KEY_IMA_EXT_0: i64 = 4;
28+
const RISCV_HWPROBE_IMA_FD: u64 = 1 << 0;
29+
const RISCV_HWPROBE_IMA_C: u64 = 1 << 1;
30+
const RISCV_HWPROBE_IMA_V: u64 = 1 << 2;
31+
const RISCV_HWPROBE_EXT_ZBA: u64 = 1 << 3;
32+
const RISCV_HWPROBE_EXT_ZBB: u64 = 1 << 4;
33+
const RISCV_HWPROBE_EXT_ZBS: u64 = 1 << 5;
34+
// const RISCV_HWPROBE_EXT_ZICBOZ: u64 = 1 << 6;
35+
const RISCV_HWPROBE_EXT_ZBC: u64 = 1 << 7;
36+
const RISCV_HWPROBE_EXT_ZBKB: u64 = 1 << 8;
37+
const RISCV_HWPROBE_EXT_ZBKC: u64 = 1 << 9;
38+
const RISCV_HWPROBE_EXT_ZBKX: u64 = 1 << 10;
39+
const RISCV_HWPROBE_EXT_ZKND: u64 = 1 << 11;
40+
const RISCV_HWPROBE_EXT_ZKNE: u64 = 1 << 12;
41+
const RISCV_HWPROBE_EXT_ZKNH: u64 = 1 << 13;
42+
const RISCV_HWPROBE_EXT_ZKSED: u64 = 1 << 14;
43+
const RISCV_HWPROBE_EXT_ZKSH: u64 = 1 << 15;
44+
const RISCV_HWPROBE_EXT_ZKT: u64 = 1 << 16;
45+
const RISCV_HWPROBE_EXT_ZVBB: u64 = 1 << 17;
46+
const RISCV_HWPROBE_EXT_ZVBC: u64 = 1 << 18;
47+
const RISCV_HWPROBE_EXT_ZVKB: u64 = 1 << 19;
48+
const RISCV_HWPROBE_EXT_ZVKG: u64 = 1 << 20;
49+
const RISCV_HWPROBE_EXT_ZVKNED: u64 = 1 << 21;
50+
const RISCV_HWPROBE_EXT_ZVKNHA: u64 = 1 << 22;
51+
const RISCV_HWPROBE_EXT_ZVKNHB: u64 = 1 << 23;
52+
const RISCV_HWPROBE_EXT_ZVKSED: u64 = 1 << 24;
53+
const RISCV_HWPROBE_EXT_ZVKSH: u64 = 1 << 25;
54+
const RISCV_HWPROBE_EXT_ZVKT: u64 = 1 << 26;
55+
const RISCV_HWPROBE_EXT_ZFH: u64 = 1 << 27;
56+
const RISCV_HWPROBE_EXT_ZFHMIN: u64 = 1 << 28;
57+
// const RISCV_HWPROBE_EXT_ZIHINTNTL: u64 = 1 << 29;
58+
const RISCV_HWPROBE_EXT_ZVFH: u64 = 1 << 30;
59+
const RISCV_HWPROBE_EXT_ZVFHMIN: u64 = 1 << 31;
60+
// const RISCV_HWPROBE_EXT_ZFA: u64 = 1 << 32;
61+
const RISCV_HWPROBE_EXT_ZTSO: u64 = 1 << 33;
62+
const RISCV_HWPROBE_EXT_ZACAS: u64 = 1 << 34;
63+
// const RISCV_HWPROBE_EXT_ZICOND: u64 = 1 << 35;
64+
const RISCV_HWPROBE_EXT_ZIHINTPAUSE: u64 = 1 << 36;
65+
const RISCV_HWPROBE_EXT_ZVE32X: u64 = 1 << 37;
66+
const RISCV_HWPROBE_EXT_ZVE32F: u64 = 1 << 38;
67+
const RISCV_HWPROBE_EXT_ZVE64X: u64 = 1 << 39;
68+
const RISCV_HWPROBE_EXT_ZVE64F: u64 = 1 << 40;
69+
const RISCV_HWPROBE_EXT_ZVE64D: u64 = 1 << 41;
70+
// const RISCV_HWPROBE_EXT_ZIMOP: u64 = 1 << 42;
71+
// const RISCV_HWPROBE_EXT_ZCA: u64 = 1 << 43;
72+
// const RISCV_HWPROBE_EXT_ZCB: u64 = 1 << 44;
73+
// const RISCV_HWPROBE_EXT_ZCD: u64 = 1 << 45;
74+
// const RISCV_HWPROBE_EXT_ZCF: u64 = 1 << 46;
75+
// const RISCV_HWPROBE_EXT_ZCMOP: u64 = 1 << 47;
76+
const RISCV_HWPROBE_EXT_ZAWRS: u64 = 1 << 48;
77+
// const RISCV_HWPROBE_EXT_SUPM: u64 = 1 << 49;
78+
79+
const RISCV_HWPROBE_KEY_CPUPERF_0: i64 = 5;
80+
const RISCV_HWPROBE_MISALIGNED_FAST: u64 = 3;
81+
const RISCV_HWPROBE_MISALIGNED_MASK: u64 = 7;
82+
83+
const RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF: i64 = 10;
84+
const RISCV_HWPROBE_MISALIGNED_VECTOR_FAST: u64 = 3;
85+
86+
// syscall returns an unsupported error if riscv_hwprobe is not supported,
87+
// so we can safely use this function on older versions of Linux.
88+
fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool {
89+
unsafe fn __riscv_hwprobe(
90+
pairs: *mut riscv_hwprobe,
91+
pair_count: libc::size_t,
92+
cpu_set_size: libc::size_t,
93+
cpus: *mut libc::c_ulong,
94+
flags: libc::c_uint,
95+
) -> libc::c_long {
96+
unsafe {
97+
libc::syscall(
98+
__NR_riscv_hwprobe,
99+
pairs,
100+
pair_count,
101+
cpu_set_size,
102+
cpus,
103+
flags,
104+
)
105+
}
106+
}
107+
108+
let len = out.len();
109+
unsafe { __riscv_hwprobe(out.as_mut_ptr(), len, 0, ptr::null_mut(), 0) == 0 }
110+
}
111+
112+
/// Read list of supported features from riscv_hwprobe or the auxiliary vector.
7113
pub(crate) fn detect_features() -> cache::Initializer {
8114
let mut value = cache::Initializer::default();
115+
116+
let mut out = [
117+
riscv_hwprobe {
118+
key: RISCV_HWPROBE_KEY_BASE_BEHAVIOR,
119+
value: 0,
120+
},
121+
riscv_hwprobe {
122+
key: RISCV_HWPROBE_KEY_IMA_EXT_0,
123+
value: 0,
124+
},
125+
riscv_hwprobe {
126+
key: RISCV_HWPROBE_KEY_CPUPERF_0,
127+
value: 0,
128+
},
129+
riscv_hwprobe {
130+
key: RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF,
131+
value: 0,
132+
},
133+
];
134+
if _riscv_hwprobe(&mut out) {
135+
let mut enable_feature = |feature, enable| {
136+
if enable {
137+
value.set(feature as u32);
138+
}
139+
};
140+
let mut ima = false;
141+
if out[0].key != -1 {
142+
let base_behavior = out[0].value;
143+
ima = base_behavior & RISCV_HWPROBE_BASE_BEHAVIOR_IMA != 0;
144+
#[cfg(target_arch = "riscv32")]
145+
enable_feature(Feature::rv32i, ima);
146+
#[cfg(target_arch = "riscv64")]
147+
enable_feature(Feature::rv64i, ima);
148+
enable_feature(Feature::m, ima);
149+
enable_feature(Feature::a, ima);
150+
}
151+
if ima && out[1].key != -1 {
152+
let ima_ext_0 = out[1].value;
153+
let fd = ima_ext_0 & RISCV_HWPROBE_IMA_FD != 0;
154+
enable_feature(Feature::f, fd);
155+
enable_feature(Feature::d, fd);
156+
enable_feature(Feature::zicsr, fd); // implied by f
157+
enable_feature(Feature::c, ima_ext_0 & RISCV_HWPROBE_IMA_C != 0);
158+
// enable_feature(Feature::zicboz, ima_ext_0 & RISCV_HWPROBE_EXT_ZICBOZ != 0);
159+
enable_feature(Feature::zfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZFH != 0);
160+
enable_feature(Feature::zfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZFHMIN != 0);
161+
// enable_feature(Feature::zihintntl, ima_ext_0 & RISCV_HWPROBE_EXT_ZIHINTNTL != 0);
162+
// enable_feature(Feature::zfa, ima_ext_0 & RISCV_HWPROBE_EXT_ZFA != 0);
163+
enable_feature(Feature::ztso, ima_ext_0 & RISCV_HWPROBE_EXT_ZTSO != 0);
164+
enable_feature(Feature::zacas, ima_ext_0 & RISCV_HWPROBE_EXT_ZACAS != 0);
165+
// enable_feature(Feature::zicond, ima_ext_0 & RISCV_HWPROBE_EXT_ZICOND != 0);
166+
enable_feature(
167+
Feature::zihintpause,
168+
ima_ext_0 & RISCV_HWPROBE_EXT_ZIHINTPAUSE != 0,
169+
);
170+
// enable_feature(Feature::zimop, ima_ext_0 & RISCV_HWPROBE_EXT_ZIMOP != 0);
171+
// enable_feature(Feature::zca, ima_ext_0 & RISCV_HWPROBE_EXT_ZCA != 0);
172+
// enable_feature(Feature::zcb, ima_ext_0 & RISCV_HWPROBE_EXT_ZCB != 0);
173+
// enable_feature(Feature::zcd, ima_ext_0 & RISCV_HWPROBE_EXT_ZCD != 0);
174+
// enable_feature(Feature::zcf, ima_ext_0 & RISCV_HWPROBE_EXT_ZCF != 0);
175+
// enable_feature(Feature::zcmop, ima_ext_0 & RISCV_HWPROBE_EXT_ZCMOP != 0);
176+
enable_feature(Feature::zawrs, ima_ext_0 & RISCV_HWPROBE_EXT_ZAWRS != 0);
177+
// enable_feature(Feature::supm, ima_ext_0 & RISCV_HWPROBE_EXT_SUPM != 0);
178+
// Bit-Manipulation ISA extensions
179+
enable_feature(Feature::zba, ima_ext_0 & RISCV_HWPROBE_EXT_ZBA != 0);
180+
enable_feature(Feature::zbb, ima_ext_0 & RISCV_HWPROBE_EXT_ZBB != 0);
181+
enable_feature(Feature::zbs, ima_ext_0 & RISCV_HWPROBE_EXT_ZBS != 0);
182+
enable_feature(Feature::zbc, ima_ext_0 & RISCV_HWPROBE_EXT_ZBC != 0);
183+
// Scalar Crypto ISA extensions
184+
let zbkb = ima_ext_0 & RISCV_HWPROBE_EXT_ZBKB != 0;
185+
enable_feature(Feature::zbkb, zbkb);
186+
let zbkc = ima_ext_0 & RISCV_HWPROBE_EXT_ZBKC != 0;
187+
enable_feature(Feature::zbkc, zbkc);
188+
let zbkx = ima_ext_0 & RISCV_HWPROBE_EXT_ZBKX != 0;
189+
enable_feature(Feature::zbkx, zbkx);
190+
let zknd = ima_ext_0 & RISCV_HWPROBE_EXT_ZKND != 0;
191+
enable_feature(Feature::zknd, zknd);
192+
let zkne = ima_ext_0 & RISCV_HWPROBE_EXT_ZKNE != 0;
193+
enable_feature(Feature::zkne, zkne);
194+
let zknh = ima_ext_0 & RISCV_HWPROBE_EXT_ZKNH != 0;
195+
enable_feature(Feature::zknh, zknh);
196+
let zksed = ima_ext_0 & RISCV_HWPROBE_EXT_ZKSED != 0;
197+
enable_feature(Feature::zksed, zksed);
198+
let zksh = ima_ext_0 & RISCV_HWPROBE_EXT_ZKSH != 0;
199+
enable_feature(Feature::zksh, zksh);
200+
let zkt = ima_ext_0 & RISCV_HWPROBE_EXT_ZKT != 0;
201+
enable_feature(Feature::zkt, zkt);
202+
let zkn = zbkb & zbkc & zbkx & zkne & zknd & zknh;
203+
enable_feature(Feature::zkn, zkn);
204+
// enable_feature(Feature::zk, zkn & zkr & zkt);
205+
enable_feature(Feature::zks, zbkb & zbkc & zbkx & zksed & zksh);
206+
// Standard Vector Extensions
207+
enable_feature(Feature::v, ima_ext_0 & RISCV_HWPROBE_IMA_V != 0);
208+
enable_feature(Feature::zvfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFH != 0);
209+
enable_feature(Feature::zvfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFHMIN != 0);
210+
enable_feature(Feature::zve32x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32X != 0);
211+
enable_feature(Feature::zve32f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32F != 0);
212+
enable_feature(Feature::zve64x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64X != 0);
213+
enable_feature(Feature::zve64f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64F != 0);
214+
enable_feature(Feature::zve64d, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64D != 0);
215+
// Vector Cryptography and Bit-manipulation Extensions
216+
let zvbb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBB != 0;
217+
enable_feature(Feature::zvbb, zvbb);
218+
let zvbc = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBC != 0;
219+
enable_feature(Feature::zvbc, zvbc);
220+
let zvkb = zvbb || ima_ext_0 & RISCV_HWPROBE_EXT_ZVKB != 0;
221+
enable_feature(Feature::zvkb, zvkb);
222+
let zvkg = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKG != 0;
223+
enable_feature(Feature::zvkg, zvkg);
224+
let zvkned = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNED != 0;
225+
enable_feature(Feature::zvkned, zvkned);
226+
enable_feature(Feature::zvknha, ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHA != 0);
227+
let zvknhb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHB != 0;
228+
enable_feature(Feature::zvknhb, zvknhb);
229+
let zvksed = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSED != 0;
230+
enable_feature(Feature::zvksed, zvksed);
231+
let zvksh = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSH != 0;
232+
enable_feature(Feature::zvksh, zvksh);
233+
let zvkt = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKT != 0;
234+
enable_feature(Feature::zvkt, zvkt);
235+
let zvkn = zvkned & zvknhb & zvkb & zvkt;
236+
enable_feature(Feature::zvkn, zvkn);
237+
enable_feature(Feature::zvknc, zvkn & zvbc);
238+
enable_feature(Feature::zvkng, zvkn & zvkg);
239+
let zvks = zvksed & zvksh & zvkb & zvkt;
240+
enable_feature(Feature::zvks, zvks);
241+
enable_feature(Feature::zvksc, zvks & zvbc);
242+
enable_feature(Feature::zvksg, zvks & zvkg);
243+
}
244+
if out[2].key != -1 {
245+
enable_feature(
246+
Feature::unaligned_scalar_mem,
247+
out[2].value & RISCV_HWPROBE_MISALIGNED_MASK == RISCV_HWPROBE_MISALIGNED_FAST,
248+
);
249+
}
250+
if out[3].key != -1 {
251+
enable_feature(
252+
Feature::unaligned_vector_mem,
253+
out[3].value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST,
254+
);
255+
}
256+
// FIXME: should be enough with hwprobe only, but our code below checks h and e
257+
// unavailable in neither uapi/asm/hwprobe.h nor uapi/asm/hwcap.h.
258+
// https://github.com/torvalds/linux/blob/master/arch/riscv/include/uapi/asm/hwcap.h
259+
// return value;
260+
}
261+
262+
// FIXME: As said in the above FIXME, we currently alway checks auxv too.
263+
// // riscv_hwprobe requires Linux 6.4, so we fallback to auxv-based detection on
264+
// // old Linux kernel.
265+
9266
let enable_feature = |value: &mut cache::Initializer, feature, enable| {
10267
if enable {
11268
value.set(feature as u32);
@@ -22,6 +279,11 @@ pub(crate) fn detect_features() -> cache::Initializer {
22279
// The values are part of the platform-specific [asm/hwcap.h][hwcap]
23280
//
24281
// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/riscv/include/asm/hwcap.h
282+
//
283+
// Note that there is no need to check b'v' - b'a' here for the case where riscv_hwprobe is unsupported,
284+
// since both RISCV_HWPROBE_IMA_V and COMPAT_HWCAP_ISA_V are only supported on Linux 6.5+.
285+
// https://github.com/torvalds/linux/commit/162e4df137c1fea6557fda3e4cdf5dc6ca6d5510
286+
// https://github.com/torvalds/linux/commit/dc6667a4e7e36f283bcd0264a0be55adae4d6f86
25287
let auxv = auxvec::auxv().expect("read auxvec"); // should not fail on RISC-V platform
26288
#[allow(clippy::eq_op)]
27289
enable_feature(
@@ -46,16 +308,20 @@ pub(crate) fn detect_features() -> cache::Initializer {
46308
);
47309
let has_i = bit::test(auxv.hwcap, (b'i' - b'a').into());
48310
// If future RV128I is supported, implement with `enable_feature` here
49-
#[cfg(target_pointer_width = "64")]
311+
// Checking target_pointer_width instead of target_arch is incorrect since
312+
// there are RV64ILP32* ABIs.
313+
#[cfg(target_arch = "riscv64")]
50314
enable_feature(&mut value, Feature::rv64i, has_i);
51-
#[cfg(target_pointer_width = "32")]
315+
#[cfg(target_arch = "riscv32")]
52316
enable_feature(&mut value, Feature::rv32i, has_i);
53-
#[cfg(target_pointer_width = "32")]
317+
// FIXME: e is not exposed in any of asm/hwcap.h, uapi/asm/hwcap.h, uapi/asm/hwprobe.h
318+
#[cfg(target_arch = "riscv32")]
54319
enable_feature(
55320
&mut value,
56321
Feature::rv32e,
57322
bit::test(auxv.hwcap, (b'e' - b'a').into()),
58323
);
324+
// FIXME: h is not exposed in uapi/asm/hwcap.h and uapi/asm/hwprobe.h
59325
enable_feature(
60326
&mut value,
61327
Feature::h,
@@ -66,9 +332,9 @@ pub(crate) fn detect_features() -> cache::Initializer {
66332
Feature::m,
67333
bit::test(auxv.hwcap, (b'm' - b'a').into()),
68334
);
69-
// FIXME: Auxvec does not show supervisor feature support, but this mode may be useful
70-
// to detect when Rust is used to write Linux kernel modules.
71-
// These should be more than Auxvec way to detect supervisor features.
335+
336+
// Neither hwprobe nor auxv supports detection of supervisor feature.
337+
// Since target_os = "linux" is for user mode, their detection is not useful.
72338

73339
value
74340
}

‎crates/std_detect/tests/cpu-detection.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
any(target_arch = "aarch64", target_arch = "arm64ec"),
66
feature(stdarch_aarch64_feature_detection)
77
)]
8+
#![cfg_attr(
9+
any(target_arch = "riscv32", target_arch = "riscv64"),
10+
feature(stdarch_riscv_feature_detection)
11+
)]
812
#![cfg_attr(target_arch = "powerpc", feature(stdarch_powerpc_feature_detection))]
913
#![cfg_attr(target_arch = "powerpc64", feature(stdarch_powerpc_feature_detection))]
1014
#![cfg_attr(target_arch = "s390x", feature(stdarch_s390x_feature_detection))]
@@ -15,6 +19,8 @@
1519
target_arch = "arm",
1620
target_arch = "aarch64",
1721
target_arch = "arm64ec",
22+
target_arch = "riscv32",
23+
target_arch = "riscv64",
1824
target_arch = "powerpc",
1925
target_arch = "powerpc64",
2026
target_arch = "s390x",
@@ -220,6 +226,97 @@ fn aarch64_darwin() {
220226
println!("sha3: {:?}", is_aarch64_feature_detected!("sha3"));
221227
}
222228

229+
#[test]
230+
#[cfg(all(
231+
any(target_arch = "riscv32", target_arch = "riscv64"),
232+
target_os = "linux"
233+
))]
234+
fn riscv_linux() {
235+
println!("rv32i: {}", is_riscv_feature_detected!("rv32i"));
236+
println!("rv32e: {}", is_riscv_feature_detected!("rv32e"));
237+
println!("rv64i: {}", is_riscv_feature_detected!("rv64i"));
238+
println!("rv128i: {}", is_riscv_feature_detected!("rv128i"));
239+
println!("zicsr: {}", is_riscv_feature_detected!("zicsr"));
240+
println!("zicntr: {}", is_riscv_feature_detected!("zicntr"));
241+
println!("zihpm: {}", is_riscv_feature_detected!("zihpm"));
242+
println!("zifencei: {}", is_riscv_feature_detected!("zifencei"));
243+
println!("zihintpause: {}", is_riscv_feature_detected!("zihintpause"));
244+
println!("m: {}", is_riscv_feature_detected!("m"));
245+
println!("a: {}", is_riscv_feature_detected!("a"));
246+
println!("zacas: {}", is_riscv_feature_detected!("zacas"));
247+
println!("zawrs: {}", is_riscv_feature_detected!("zawrs"));
248+
println!("zam: {}", is_riscv_feature_detected!("zam"));
249+
println!("ztso: {}", is_riscv_feature_detected!("ztso"));
250+
println!("f: {}", is_riscv_feature_detected!("f"));
251+
println!("d: {}", is_riscv_feature_detected!("d"));
252+
println!("q: {}", is_riscv_feature_detected!("q"));
253+
println!("zfh: {}", is_riscv_feature_detected!("zfh"));
254+
println!("zfhmin: {}", is_riscv_feature_detected!("zfhmin"));
255+
println!("zfinx: {}", is_riscv_feature_detected!("zfinx"));
256+
println!("zdinx: {}", is_riscv_feature_detected!("zdinx"));
257+
println!("zhinx: {}", is_riscv_feature_detected!("zhinx"));
258+
println!("zhinxmin: {}", is_riscv_feature_detected!("zhinxmin"));
259+
println!("c: {}", is_riscv_feature_detected!("c"));
260+
println!("zba: {}", is_riscv_feature_detected!("zba"));
261+
println!("zbb: {}", is_riscv_feature_detected!("zbb"));
262+
println!("zbc: {}", is_riscv_feature_detected!("zbc"));
263+
println!("zbs: {}", is_riscv_feature_detected!("zbs"));
264+
println!("zbkb: {}", is_riscv_feature_detected!("zbkb"));
265+
println!("zbkc: {}", is_riscv_feature_detected!("zbkc"));
266+
println!("zbkx: {}", is_riscv_feature_detected!("zbkx"));
267+
println!("zknd: {}", is_riscv_feature_detected!("zknd"));
268+
println!("zkne: {}", is_riscv_feature_detected!("zkne"));
269+
println!("zknh: {}", is_riscv_feature_detected!("zknh"));
270+
println!("zksed: {}", is_riscv_feature_detected!("zksed"));
271+
println!("zksh: {}", is_riscv_feature_detected!("zksh"));
272+
println!("zkr: {}", is_riscv_feature_detected!("zkr"));
273+
println!("zksed: {}", is_riscv_feature_detected!("zksed"));
274+
println!("zksh: {}", is_riscv_feature_detected!("zksh"));
275+
println!("zkr: {}", is_riscv_feature_detected!("zkr"));
276+
println!("zkn: {}", is_riscv_feature_detected!("zkn"));
277+
println!("zks: {}", is_riscv_feature_detected!("zks"));
278+
println!("zkt: {}", is_riscv_feature_detected!("zkt"));
279+
println!("v: {}", is_riscv_feature_detected!("v"));
280+
println!("zvfh: {}", is_riscv_feature_detected!("zvfh"));
281+
println!("zvfhmin: {}", is_riscv_feature_detected!("zvfhmin"));
282+
println!("zve32x: {}", is_riscv_feature_detected!("zve32x"));
283+
println!("zve32f: {}", is_riscv_feature_detected!("zve32f"));
284+
println!("zve64x: {}", is_riscv_feature_detected!("zve64x"));
285+
println!("zve64f: {}", is_riscv_feature_detected!("zve64f"));
286+
println!("zve64d: {}", is_riscv_feature_detected!("zve64d"));
287+
println!("zvkb: {}", is_riscv_feature_detected!("zvkb"));
288+
println!("zvbb: {}", is_riscv_feature_detected!("zvbb"));
289+
println!("zvbc: {}", is_riscv_feature_detected!("zvbc"));
290+
println!("zvkg: {}", is_riscv_feature_detected!("zvkg"));
291+
println!("zvkned: {}", is_riscv_feature_detected!("zvkned"));
292+
println!("zvknha: {}", is_riscv_feature_detected!("zvknha"));
293+
println!("zvknhb: {}", is_riscv_feature_detected!("zvknhb"));
294+
println!("zvksed: {}", is_riscv_feature_detected!("zvksed"));
295+
println!("zvksh: {}", is_riscv_feature_detected!("zvksh"));
296+
println!("zvkn: {}", is_riscv_feature_detected!("zvkn"));
297+
println!("zvknc: {}", is_riscv_feature_detected!("zvknc"));
298+
println!("zvkng: {}", is_riscv_feature_detected!("zvkng"));
299+
println!("zvks: {}", is_riscv_feature_detected!("zvks"));
300+
println!("zvksc: {}", is_riscv_feature_detected!("zvksc"));
301+
println!("zvksg: {}", is_riscv_feature_detected!("zvksg"));
302+
println!("zvkt: {}", is_riscv_feature_detected!("zvkt"));
303+
println!(
304+
"unaligned-scalar-mem: {}",
305+
is_riscv_feature_detected!("unaligned-scalar-mem")
306+
);
307+
println!(
308+
"unaligned-vector-mem: {}",
309+
is_riscv_feature_detected!("unaligned-vector-mem")
310+
);
311+
println!("svnapot: {}", is_riscv_feature_detected!("svnapot"));
312+
println!("svpbmt: {}", is_riscv_feature_detected!("svpbmt"));
313+
println!("svinval: {}", is_riscv_feature_detected!("svinval"));
314+
println!("h: {}", is_riscv_feature_detected!("h"));
315+
println!("s: {}", is_riscv_feature_detected!("s"));
316+
println!("j: {}", is_riscv_feature_detected!("j"));
317+
println!("p: {}", is_riscv_feature_detected!("p"));
318+
}
319+
223320
#[test]
224321
#[cfg(all(target_arch = "powerpc", target_os = "linux"))]
225322
fn powerpc_linux() {

0 commit comments

Comments
 (0)
Please sign in to comment.