Extract the cpu capabilities from the auxiliary vector
Check for neon/asimd and pmull for arm and aarch64.
This commit is contained in:
parent
f49009e22c
commit
f775bf3931
4 changed files with 135 additions and 2 deletions
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
89
library/stdarch/src/runtime/linux/auxvec.rs
Normal file
89
library/stdarch/src/runtime/linux/auxvec.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue