Extract the cpu capabilities from the auxiliary vector

Check for neon/asimd and pmull for arm and aarch64.
This commit is contained in:
Luca Barbato 2017-12-11 18:14:06 +01:00 committed by gnzlbg
parent f49009e22c
commit f775bf3931
4 changed files with 135 additions and 2 deletions

View file

@ -45,6 +45,25 @@ pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
value
}
/// Probe the ELF Auxiliary vector for hardware capabilities
///
/// The values are part of the platform-specific [asm/hwcap.h][hwcap]
///
/// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
impl linux::FeatureQuery for linux::AuxVec {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;
if let Some(caps) = self.lookup(linux::AT::HWCAP) {
match *x {
asimd => caps & (1 << 1) != 0,
pmull => caps & (1 << 4) != 0,
}
} else {
false
}
}
}
impl linux::FeatureQuery for linux::CpuInfo {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;

View file

@ -42,6 +42,25 @@ pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
value
}
/// Probe the ELF Auxiliary vector for hardware capabilities
///
/// The values are part of the platform-specific [asm/hwcap.h][hwcap]
///
/// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
impl linux::FeatureQuery for linux::AuxVec {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;
match *x {
neon => self.lookup(linux::AT::HWCAP)
.map(|caps| caps & (1 << 12) != 0)
.unwrap_or(false),
pmull => self.lookup(linux::AT::HWCAP2)
.map(|caps| caps & (1 << 1) != 0)
.unwrap_or(false),
}
}
}
/// Is the CPU known to have a broken NEON unit?
///
/// See https://crbug.com/341598.

View file

@ -0,0 +1,89 @@
//! Reads /proc/self/auxv on Linux systems
use std::prelude::v1::*;
use std::slice;
use std::mem;
/// Simple abstraction for the ELF Auxiliary Vector
///
/// the elf.h provide the layout of the single entry as auxv_t.
/// The desugared version is a usize tag followed by a union with
/// the same storage size.
///
/// Cache only the HWCAP and HWCAP2 entries.
#[derive(Debug)]
pub struct AuxVec {
hwcap: Option<usize>,
hwcap2: Option<usize>,
}
#[derive(Clone, Debug, PartialEq)]
#[allow(dead_code)]
/// ELF Auxiliary vector entry types
///
/// The entry types are specified in [linux/auxvec.h][auxvec_h].
///
/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h
pub enum AT {
/// CPU Hardware capabilities, it is a bitfield.
HWCAP = 16,
/// CPU Hardware capabilities, additional bitfield.
HWCAP2 = 26,
}
impl AuxVec {
/// Reads the ELF Auxiliary Vector
///
/// Try to read `/proc/self/auxv`.
// TODO: Make use of getauxval once it is available in a
// reliable way.
pub fn new() -> Result<Self, ::std::io::Error> {
use std::io::Read;
let mut file = ::std::fs::File::open("/proc/self/auxv")?;
let mut buf = [0usize; 64];
let mut raw = unsafe {
slice::from_raw_parts_mut(
buf.as_mut_ptr() as *mut u8,
buf.len() * mem::size_of::<usize>(),
)
};
let _ = file.read(&mut raw)?;
mem::forget(raw);
let mut auxv = AuxVec { hwcap: None, hwcap2: None };
for el in buf.chunks(2) {
if el[0] == AT::HWCAP as usize {
auxv.hwcap = Some(el[1]);
}
if el[0] == AT::HWCAP2 as usize {
auxv.hwcap2 = Some(el[1]);
}
}
Ok(auxv)
}
/// Returns the value for the AT key
pub fn lookup(&self, key: AT) -> Option<usize> {
match key {
AT::HWCAP => self.hwcap,
AT::HWCAP2 => self.hwcap2,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "linux")]
#[test]
fn test_auxvec_linux() {
let auxvec = AuxVec::new().unwrap();
println!("{:?}", auxvec.lookup(AT::HWCAP));
println!("{:?}", auxvec);
}
}

View file

@ -2,6 +2,9 @@
mod cpuinfo;
pub use self::cpuinfo::CpuInfo;
mod auxvec;
pub use self::auxvec::*;
use super::__Feature;
pub trait FeatureQuery {
@ -19,9 +22,12 @@ fn detect_features_impl<T: FeatureQuery>(x: T) -> usize {
}
}
/// Detects ARM features:
/// Detects CPU features:
pub fn detect_features() -> usize {
// FIXME: use libc::getauxval, and if that fails /proc/auxv
// Try to read the ELF Auxiliary Vector
if let Ok(v) = auxvec::AuxVec::new() {
return detect_features_impl(v);
}
// Try to read /proc/cpuinfo
if let Ok(v) = cpuinfo::CpuInfo::new() {
return detect_features_impl(v);