Skip to content

Commit 59a4ca8

Browse files
committed
Extract the cpu capabilities from the auxiliary vector
Check for neon/asimd and pmull for arm and aarch64.
1 parent e098059 commit 59a4ca8

File tree

4 files changed

+110
-1
lines changed

4 files changed

+110
-1
lines changed

src/runtime/aarch64.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
4545
value
4646
}
4747

48+
impl linux::FeatureQuery for linux::AuxVec {
49+
fn has_feature(&mut self, x: &__Feature) -> bool {
50+
use self::__Feature::*;
51+
if let Some(caps) = self.lookup(linux::AT::HWCAP) {
52+
match *x {
53+
asimd => caps & (1 << 1) != 0,
54+
pmull => caps & (1 << 4) != 0,
55+
}
56+
} else {
57+
false
58+
}
59+
}
60+
}
61+
4862
impl linux::FeatureQuery for linux::CpuInfo {
4963
fn has_feature(&mut self, x: &__Feature) -> bool {
5064
use self::__Feature::*;

src/runtime/arm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
4242
value
4343
}
4444

45+
impl linux::FeatureQuery for linux::AuxVec {
46+
fn has_feature(&mut self, x: &__Feature) -> bool {
47+
use self::__Feature::*;
48+
match *x {
49+
neon => self.lookup(linux::AT::HWCAP)
50+
.map(|caps| caps & (1 << 12) != 0)
51+
.unwrap_or(false),
52+
pmull => self.lookup(linux::AT::HWCAP2)
53+
.map(|caps| caps & (1 << 4) != 0)
54+
.unwrap_or(false),
55+
}
56+
}
57+
}
58+
4559
/// Is the CPU known to have a broken NEON unit?
4660
///
4761
/// See https://crbug.com/341598.

src/runtime/linux/auxvec.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//! Reads /proc/self/auxv on Linux systems
2+
3+
use std::prelude::v1::*;
4+
use std::slice;
5+
use std::mem;
6+
use std::fmt;
7+
8+
pub struct AuxVec {
9+
raw: Vec<usize>,
10+
}
11+
12+
#[derive(Clone, Debug, PartialEq)]
13+
#[allow(dead_code)]
14+
pub enum AT {
15+
PLATFORM = 15,
16+
HWCAP = 16,
17+
HWCAP2 = 26,
18+
}
19+
20+
impl fmt::Debug for AuxVec {
21+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22+
f.debug_list()
23+
.entries(self.raw.chunks(2).map(|kv| (kv[0], kv[1])))
24+
.finish()
25+
}
26+
}
27+
28+
impl AuxVec {
29+
/// Reads /proc/self/auxv into AuxVec.
30+
// TODO: make it less ugly if possible
31+
pub fn new() -> Result<Self, ::std::io::Error> {
32+
use std::io::Read;
33+
let mut file = ::std::fs::File::open("/proc/self/auxv")?;
34+
let mut buf = [0usize; 64];
35+
let mut raw = unsafe {
36+
slice::from_raw_parts_mut(
37+
buf.as_mut_ptr() as *mut u8,
38+
buf.len() * mem::size_of::<usize>(),
39+
)
40+
};
41+
let l = file.read(&mut raw)? / mem::size_of::<usize>();
42+
43+
mem::forget(raw);
44+
45+
let mut v = Vec::new();
46+
47+
v.extend_from_slice(&buf[..l]);
48+
49+
Ok(AuxVec { raw: v })
50+
}
51+
52+
/// Returns the value for the AT key.
53+
pub fn lookup(&self, key: AT) -> Option<usize> {
54+
let k = key as usize;
55+
for el in self.raw.chunks(2) {
56+
if el[0] == k {
57+
return Some(el[1]);
58+
}
59+
}
60+
None
61+
}
62+
}
63+
64+
#[cfg(test)]
65+
mod tests {
66+
use super::*;
67+
68+
#[cfg(target_os = "linux")]
69+
#[test]
70+
fn test_auxvec_linux() {
71+
let auxvec = AuxVec::new().unwrap();
72+
println!("{:?}", auxvec.lookup(AT::HWCAP));
73+
println!("{:?}", auxvec);
74+
}
75+
}

src/runtime/linux/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
mod cpuinfo;
33
pub use self::cpuinfo::CpuInfo;
44

5+
mod auxvec;
6+
pub use self::auxvec::*;
7+
58
use super::__Feature;
69

710
pub trait FeatureQuery {
@@ -21,7 +24,10 @@ fn detect_features_impl<T: FeatureQuery>(x: T) -> usize {
2124

2225
/// Detects ARM features:
2326
pub fn detect_features() -> usize {
24-
// FIXME: use libc::getauxval, and if that fails /proc/auxv
27+
// Try to read /proc/self/auxv
28+
if let Ok(v) = auxvec::AuxVec::new() {
29+
return detect_features_impl(v);
30+
}
2531
// Try to read /proc/cpuinfo
2632
if let Ok(v) = cpuinfo::CpuInfo::new() {
2733
return detect_features_impl(v);

0 commit comments

Comments
 (0)