Skip to content

Commit 43b6f01

Browse files
committed
std_detect: Support run-time detection on riscv64 FreeBSD
Values are the same as Linux, but only a subset of them is supported. https://github.com/freebsd/freebsd-src/blob/8923de59054358980102ea5acda6c6dd58273957/sys/riscv/include/elf.h#L77-L86
1 parent 25b7ac9 commit 43b6f01

File tree

7 files changed

+105
-19
lines changed

7 files changed

+105
-19
lines changed

ci/build-std-detect.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ targets=(
1919
armv6-unknown-freebsd
2020
powerpc-unknown-freebsd
2121
powerpc64-unknown-freebsd
22+
riscv64gc-unknown-freebsd
2223

2324
# OpenBSD
2425
aarch64-unknown-openbsd

crates/std_detect/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ crate from working on applications in which `std` is not available.
6060
querying `mrs` is implemented for Linux >= 4.11, but not enabled by default.
6161

6262
* FreeBSD:
63-
* `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF
63+
* `arm32`, `powerpc64{,le}`, `riscv64`: `std_detect` supports these on FreeBSD by querying ELF
6464
auxiliary vectors using `sysctl`.
6565
* `arm64`: run-time feature detection is implemented by directly querying `mrs`.
6666

crates/std_detect/src/detect/os/freebsd/auxvec.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
target_arch = "aarch64",
55
target_arch = "arm",
66
target_arch = "powerpc64",
7-
target_arch = "riscv64"
7+
target_arch = "riscv64",
88
),
99
allow(dead_code)
1010
)]
@@ -16,6 +16,11 @@
1616
#[derive(Debug, Copy, Clone)]
1717
pub(crate) struct AuxVec {
1818
pub hwcap: usize,
19+
#[cfg(any(
20+
target_arch = "aarch64",
21+
target_arch = "arm",
22+
target_arch = "powerpc64",
23+
))]
1924
pub hwcap2: usize,
2025
}
2126

@@ -34,12 +39,29 @@ pub(crate) struct AuxVec {
3439
/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707
3540
pub(crate) fn auxv() -> Result<AuxVec, ()> {
3641
let hwcap = archauxv(libc::AT_HWCAP);
37-
let hwcap2 = archauxv(libc::AT_HWCAP2);
38-
// Zero could indicate that no features were detected, but it's also used to
39-
// indicate an error. In particular, on many platforms AT_HWCAP2 will be
40-
// legitimately zero, since it contains the most recent feature flags.
41-
if hwcap != 0 || hwcap2 != 0 {
42-
return Ok(AuxVec { hwcap, hwcap2 });
42+
// Targets with only AT_HWCAP:
43+
#[cfg(any(target_arch = "riscv64"))]
44+
{
45+
// Zero could indicate that no features were detected, but it's also used to
46+
// indicate an error.
47+
if hwcap != 0 {
48+
return Ok(AuxVec { hwcap });
49+
}
50+
}
51+
// Targets with AT_HWCAP and AT_HWCAP2:
52+
#[cfg(any(
53+
target_arch = "aarch64",
54+
target_arch = "arm",
55+
target_arch = "powerpc64",
56+
))]
57+
{
58+
let hwcap2 = archauxv(libc::AT_HWCAP2);
59+
// Zero could indicate that no features were detected, but it's also used to
60+
// indicate an error. In particular, on many platforms AT_HWCAP2 will be
61+
// legitimately zero, since it contains the most recent feature flags.
62+
if hwcap != 0 || hwcap2 != 0 {
63+
return Ok(AuxVec { hwcap, hwcap2 });
64+
}
4365
}
4466
Err(())
4567
}

crates/std_detect/src/detect/os/freebsd/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ cfg_if::cfg_if! {
99
} else if #[cfg(target_arch = "arm")] {
1010
mod arm;
1111
pub(crate) use self::arm::detect_features;
12+
} else if #[cfg(target_arch = "riscv64")] {
13+
mod riscv;
14+
pub(crate) use self::riscv::detect_features;
1215
} else if #[cfg(target_arch = "powerpc64")] {
1316
mod powerpc;
1417
pub(crate) use self::powerpc::detect_features;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! Run-time feature detection for RISC-V on FreeBSD.
2+
3+
use super::auxvec;
4+
use crate::detect::{bit, cache, Feature};
5+
6+
/// Read list of supported features from the auxiliary vector.
7+
pub(crate) fn detect_features() -> cache::Initializer {
8+
let mut value = cache::Initializer::default();
9+
let enable_feature = |value: &mut cache::Initializer, feature, enable| {
10+
if enable {
11+
value.set(feature as u32);
12+
}
13+
};
14+
let enable_features = |value: &mut cache::Initializer, feature_slice: &[Feature], enable| {
15+
if enable {
16+
for feature in feature_slice {
17+
value.set(*feature as u32);
18+
}
19+
}
20+
};
21+
22+
// The values are defined in machine/elf.h.
23+
// https://github.com/freebsd/freebsd-src/blob/release/14.1.0/sys/riscv/include/elf.h
24+
// TODO: https://github.com/freebsd/freebsd-src/commit/228a3e73e16983bc7f985b24ef20909500792d3c
25+
if let Ok(auxv) = auxvec::auxv() {
26+
enable_feature(
27+
&mut value,
28+
Feature::a,
29+
bit::test(auxv.hwcap, (b'a' - b'a').into()),
30+
);
31+
enable_feature(
32+
&mut value,
33+
Feature::c,
34+
bit::test(auxv.hwcap, (b'c' - b'a').into()),
35+
);
36+
enable_features(
37+
&mut value,
38+
&[Feature::d, Feature::f, Feature::zicsr],
39+
bit::test(auxv.hwcap, (b'd' - b'a').into()),
40+
);
41+
enable_features(
42+
&mut value,
43+
&[Feature::f, Feature::zicsr],
44+
bit::test(auxv.hwcap, (b'f' - b'a').into()),
45+
);
46+
let has_i = bit::test(auxv.hwcap, (b'i' - b'a').into());
47+
// If future RV128I is supported, implement with `enable_feature` here
48+
#[cfg(target_pointer_width = "64")]
49+
enable_feature(&mut value, Feature::rv64i, has_i);
50+
#[cfg(target_pointer_width = "32")]
51+
enable_feature(&mut value, Feature::rv32i, has_i);
52+
enable_feature(
53+
&mut value,
54+
Feature::m,
55+
bit::test(auxv.hwcap, (b'm' - b'a').into()),
56+
);
57+
}
58+
59+
value
60+
}

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
2121

2222
// The values are part of the platform-specific [asm/hwcap.h][hwcap]
2323
//
24-
// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/riscv/include/asm/hwcap.h
24+
// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/riscv/include/uapi/asm/hwcap.h
2525
let auxv = auxvec::auxv().expect("read auxvec"); // should not fail on RISC-V platform
2626
enable_feature(
2727
&mut value,
@@ -49,25 +49,23 @@ pub(crate) fn detect_features() -> cache::Initializer {
4949
enable_feature(&mut value, Feature::rv64i, has_i);
5050
#[cfg(target_pointer_width = "32")]
5151
enable_feature(&mut value, Feature::rv32i, has_i);
52-
#[cfg(target_pointer_width = "32")]
5352
enable_feature(
5453
&mut value,
55-
Feature::rv32e,
56-
bit::test(auxv.hwcap, (b'e' - b'a').into()),
57-
);
58-
enable_feature(
59-
&mut value,
60-
Feature::h,
61-
bit::test(auxv.hwcap, (b'h' - b'a').into()),
54+
Feature::m,
55+
bit::test(auxv.hwcap, (b'm' - b'a').into()),
6256
);
6357
enable_feature(
6458
&mut value,
65-
Feature::m,
66-
bit::test(auxv.hwcap, (b'm' - b'a').into()),
59+
Feature::v,
60+
bit::test(auxv.hwcap, (b'v' - b'a').into()),
6761
);
6862
// FIXME: Auxvec does not show supervisor feature support, but this mode may be useful
6963
// to detect when Rust is used to write Linux kernel modules.
7064
// These should be more than Auxvec way to detect supervisor features.
7165

66+
// FIXME: Auxv only supports single-letter extensions.
67+
// We can use riscv_hwprobe for multi-letter extensions.
68+
// https://github.com/torvalds/linux/blob/master/Documentation/arch/riscv/hwprobe.rst
69+
7270
value
7371
}

crates/std_detect/tests/cpu-detection.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ fn aarch64_bsd() {
187187
println!("sha2: {:?}", is_aarch64_feature_detected!("sha2"));
188188
}
189189

190+
// TODO: add test for riscv_{linux,freebsd}
191+
190192
#[test]
191193
#[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
192194
fn aarch64_darwin() {

0 commit comments

Comments
 (0)