Initial PowerPC support

Rely mainly on parsing auxv since the cpuinfo information is incomplete.
This commit is contained in:
Luca Barbato 2017-12-11 18:17:13 +01:00 committed by gnzlbg
parent f775bf3931
commit baace2fc3f
4 changed files with 191 additions and 2 deletions

View file

@ -214,4 +214,89 @@ CPU revision : 1";
assert!(cpuinfo.field("Features").has("neon"));
assert!(cpuinfo.field("Features").has("asimd"));
}
const POWER8E_POWERKVM: &str = r"processor : 0
cpu : POWER8E (raw), altivec supported
clock : 3425.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 1
cpu : POWER8E (raw), altivec supported
clock : 3425.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 2
cpu : POWER8E (raw), altivec supported
clock : 3425.000000MHz
revision : 2.1 (pvr 004b 0201)
processor : 3
cpu : POWER8E (raw), altivec supported
clock : 3425.000000MHz
revision : 2.1 (pvr 004b 0201)
timebase : 512000000
platform : pSeries
model : IBM pSeries (emulated by qemu)
machine : CHRP IBM pSeries (emulated by qemu)";
#[test]
fn test_cpuinfo_linux_power8_powerkvm() {
let cpuinfo = CpuInfo::from_str(POWER8E_POWERKVM).unwrap();
assert_eq!(cpuinfo.field("cpu"), "POWER8E (raw), altivec supported");
assert!(cpuinfo.field("cpu").has("altivec"));
}
const POWER5P: &str = r"processor : 0
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 1
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 2
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 3
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 4
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 5
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 6
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
processor : 7
cpu : POWER5+ (gs)
clock : 1900.098000MHz
revision : 2.1 (pvr 003b 0201)
timebase : 237331000
platform : pSeries
machine : CHRP IBM,9133-55A";
#[test]
fn test_cpuinfo_linux_power5p() {
let cpuinfo = CpuInfo::from_str(POWER5P).unwrap();
assert_eq!(cpuinfo.field("cpu"), "POWER5+ (gs)");
assert!(!cpuinfo.field("cpu").has("altivec"));
}
}

View file

@ -20,6 +20,10 @@ fn detect_features_impl<T: FeatureQuery>(x: T) -> usize {
{
super::aarch64::detect_features(x)
}
#[cfg(target_arch = "powerpc64")]
{
super::powerpc64::detect_features(x)
}
}
/// Detects CPU features:

View file

@ -17,12 +17,18 @@ mod aarch64;
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
pub use self::aarch64::__Feature;
#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
#[macro_use]
mod powerpc64;
#[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
pub use self::powerpc64::__Feature;
#[cfg(all(target_os = "linux",
any(target_arch = "arm", target_arch = "aarch64")))]
any(target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc64")))]
mod linux;
#[cfg(all(target_os = "linux",
any(target_arch = "arm", target_arch = "aarch64")))]
any(target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc64")))]
pub use self::linux::detect_features;
/// Performs run-time feature detection.

View file

@ -0,0 +1,94 @@
//! Run-time feature detection on PowerPC64.
use super::{bit, linux};
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
("altivec") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::altivec{})
};
("vsx") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::vsx{})
};
("power8") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::power8{})
};
($t:tt) => { compile_error!(concat!("unknown PowerPC target feature: ", $t)) };
}
/// PowerPC CPU Feature enum. Each variant denotes a position in a bitset
/// for a particular feature.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[repr(u8)]
pub enum __Feature {
/// Altivec
altivec,
/// VSX
vsx,
/// Power8
power8,
}
pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
let mut value: usize = 0;
{
let mut enable_feature = |f| {
if x.has_feature(&f) {
value = bit::set(value, f as u32);
}
};
enable_feature(__Feature::altivec);
enable_feature(__Feature::vsx);
enable_feature(__Feature::power8);
}
value
}
/// Probe the ELF Auxiliary vector for hardware capabilities
///
/// The values are part of the platform-specific [asm/cputable.h][cputable]
///
/// [cputable]: https://github.com/torvalds/linux/blob/master/arch/powerpc/include/uapi/asm/cputable.h
impl linux::FeatureQuery for linux::AuxVec {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;
match *x {
altivec => self.lookup(linux::AT::HWCAP)
.map(|caps| caps & 0x10000000 != 0)
.unwrap_or(false),
vsx => self.lookup(linux::AT::HWCAP)
.map(|caps| caps & 0x00000080 != 0)
.unwrap_or(false),
power8 => self.lookup(linux::AT::HWCAP2)
.map(|caps| caps & 0x80000000 != 0)
.unwrap_or(false),
}
}
}
/// Check for altivec support only
///
/// PowerPC's /proc/cpuinfo lacks a proper Feature field,
/// but `altivec` support is indicated in the `cpu` field.
impl linux::FeatureQuery for linux::CpuInfo {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;
match *x {
altivec => self.field("cpu").has("altivec"),
_ => false
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn detect_feature() {
println!("altivec {}", __unstable_detect_feature!("altivec"));
println!("vsx {}", __unstable_detect_feature!("vsx"));
println!("power8 {}", __unstable_detect_feature!("power8"));
}
}