Skip to content

Commit

Permalink
Get rid of getauxval error detection and just return 0. Inline top le…
Browse files Browse the repository at this point in the history
…vel of feature detection into init.

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
  • Loading branch information
marshallpierce committed Jan 14, 2017
1 parent 9781b03 commit ee5b621
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 98 deletions.
28 changes: 8 additions & 20 deletions crypto/cpu-arm-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,25 @@
unsigned long getauxval(unsigned long type) __attribute__((weak));

/*
* getauxval() may or may not be available. In addition, it may not find
* the type requested.
* - If getauxval() is not available, this returns -1.
* - If getauxval() is available but the requested type is not found or another
* error occurs, this returns 0.
* - If getauxval() is available but a different error occurs, this returns -2.
* - If getauxval() is available and the requested type is found, this returns
* 1 and also writes to the result pointer param.
* If getauxval is not available, or an error occurs, return 0.
* Otherwise, return the value found.
*/
int32_t getauxval_wrapper(unsigned long type, unsigned long *result);
unsigned long getauxval_wrapper(unsigned long type);

#include <errno.h>

int32_t getauxval_wrapper(unsigned long type, unsigned long *result) {
unsigned long getauxval_wrapper(unsigned long type) {
if (getauxval == NULL) {
return -1;
return 0;
}

unsigned long auxval = getauxval(type);
if (errno == ENOENT) {
// as of glibc 2.19, errno is ENOENT if the type is not found.
// map errors to a zero value
if (errno != 0) {
errno = 0;
return 0;
} else if (errno != 0) {
// as of glibc 2.23 the only error is enoent, but more errors
// may be added
errno = 0;
return -2;
}

*result = auxval;
return 1;
return auxval;
}
#endif
62 changes: 19 additions & 43 deletions src/cpu_feature/arm_linux/arm_linux.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
use self::auxv::Type;
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_os="linux"))]
use self::auxv::NativeProvider;
use self::auxv::{AT_HWCAP, AT_HWCAP2, Provider};

// See /usr/include/asm/hwcap.h on an ARM installation for the source of these values
const ARM_HWCAP2_AES: Type = 1 << 0;
const ARM_HWCAP2_PMULL: Type = 1 << 1;
const ARM_HWCAP2_SHA1: Type = 1 << 2;
const ARM_HWCAP2_SHA2: Type = 1 << 3;
const ARM_HWCAP2_AES: auxv::Type = 1 << 0;
const ARM_HWCAP2_PMULL: auxv::Type = 1 << 1;
const ARM_HWCAP2_SHA1: auxv::Type = 1 << 2;
const ARM_HWCAP2_SHA2: auxv::Type = 1 << 3;

const ARM_HWCAP_NEON: Type = 1 << 12;
const ARM_HWCAP_NEON: auxv::Type = 1 << 12;

// Constants used in GFp_armcap_P
// Keep in sync with include/openssl/arm_arch.h
Expand All @@ -20,41 +15,24 @@ const ARMV8_SHA1: u32 = 1 << 3;
const ARMV8_SHA256: u32 = 1 << 4;
const ARMV8_PMULL: u32 = 1 << 5;

extern "C" {
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os="linux"))]
#[allow(non_upper_case_globals)]
pub static mut GFp_armcap_P: u32;
}

#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os="linux"))]
pub fn arm_linux_set_cpu_features() {
let getauxval = NativeProvider {};

unsafe {
GFp_armcap_P |= armcap_from_features(getauxval);
}
}

/// returns a u32 with bits set for use in GFp_armcap_P
fn armcap_from_features<G: Provider> (getauxval: G) -> u32 {
let hwcap = getauxval.getauxval(AT_HWCAP).unwrap_or(0);
pub fn armcap_from_features<G: auxv::Provider> (getauxval: G) -> u32 {
let hwcap = getauxval.getauxval(auxv::AT_HWCAP);

// Matching OpenSSL, only report other features if NEON is present.
let mut armcap: u32 = 0;
if hwcap & ARM_HWCAP_NEON != 0 {
armcap |= ARMV7_NEON;

let hwcap2 = getauxval.getauxval(AT_HWCAP2).unwrap_or(0);
let hwcap2 = getauxval.getauxval(auxv::AT_HWCAP2);

armcap |= armcap_for_hwcap2(hwcap2);
}

return armcap;
}

fn armcap_for_hwcap2(hwcap2: Type) -> u32 {
fn armcap_for_hwcap2(hwcap2: auxv::Type) -> u32 {
let mut ret: u32 = 0;
if hwcap2 & ARM_HWCAP2_AES != 0 {
ret |= ARMV8_AES;
Expand Down Expand Up @@ -82,17 +60,15 @@ mod tests {
ARMV8_AES, ARMV8_PMULL, ARMV8_SHA1, ARMV8_SHA256, ARM_HWCAP2_AES,
ARM_HWCAP2_PMULL, ARM_HWCAP2_SHA1, ARM_HWCAP2_SHA2,
ARM_HWCAP_NEON};
use super::auxv::{Type, GetauxvalError,
Provider, AT_HWCAP, AT_HWCAP2};
use super::auxv;

struct StubGetauxval {
auxv: HashMap<Type, Type>
auxv: HashMap<auxv::Type, auxv::Type>
}

impl Provider for StubGetauxval {
fn getauxval(&self, auxv_type: Type)
-> Result<Type, GetauxvalError> {
self.auxv.get(&auxv_type).map(|v| *v).ok_or(GetauxvalError::NotFound)
impl auxv::Provider for StubGetauxval {
fn getauxval(&self, auxv_type: auxv::Type) -> auxv::Type {
self.auxv.get(&auxv_type).map(|v| *v).unwrap_or(0)
}
}

Expand All @@ -104,8 +80,8 @@ mod tests {
#[test]
fn armcap_bits_arm_8_with_neon_only_getauxv_hwcap_and_all_getauxv_hwcap2_yields_all_features_armcap() {
let mut auxv = HashMap::new();
let _ = auxv.insert(AT_HWCAP, ARM_HWCAP_NEON);
let _ = auxv.insert(AT_HWCAP2, ARM_HWCAP2_AES | ARM_HWCAP2_PMULL | ARM_HWCAP2_SHA1 | ARM_HWCAP2_SHA2);
let _ = auxv.insert(auxv::AT_HWCAP, ARM_HWCAP_NEON);
let _ = auxv.insert(auxv::AT_HWCAP2, ARM_HWCAP2_AES | ARM_HWCAP2_PMULL | ARM_HWCAP2_SHA1 | ARM_HWCAP2_SHA2);
let getauxv = StubGetauxval {
auxv: auxv
};
Expand All @@ -117,8 +93,8 @@ mod tests {
#[test]
fn armcap_bits_arm_8_with_neon_only_getauxv_hwcap_and_aes_getauxv_hwcap2_yields_only_neon_aes_armcap() {
let mut auxv = HashMap::new();
let _ = auxv.insert(AT_HWCAP, ARM_HWCAP_NEON);
let _ = auxv.insert(AT_HWCAP2, ARM_HWCAP2_AES);
let _ = auxv.insert(auxv::AT_HWCAP, ARM_HWCAP_NEON);
let _ = auxv.insert(auxv::AT_HWCAP2, ARM_HWCAP2_AES);
let getauxv = StubGetauxval {
auxv: auxv
};
Expand All @@ -143,7 +119,7 @@ mod tests {

fn hwcap_neon_getauxv() -> StubGetauxval {
let mut auxv = HashMap::new();
let _ = auxv.insert(AT_HWCAP,
let _ = auxv.insert(auxv::AT_HWCAP,
ARM_HWCAP_NEON);

StubGetauxval {
Expand Down
46 changes: 12 additions & 34 deletions src/cpu_feature/arm_linux/auxv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,28 @@ pub type Type = u64;

extern "C" {
/// Invoke getauxval(3) if available. If it's not linked, or if invocation
/// fails or the type is not found, sets success to false and returns 0.
#[cfg(target_os="linux")]
pub fn getauxval_wrapper(auxv_type: Type, success: *mut Type) -> i32;
}

#[derive(Debug, PartialEq)]
pub enum GetauxvalError {
/// getauxval() is not available at runtime
#[cfg(target_os="linux")]
FunctionNotAvailable,
/// getauxval() could not find the requested type
NotFound,
/// getauxval() encountered a different error
#[cfg(target_os="linux")]
UnknownError
/// fails or the type is not found, returns 0.
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os = "linux"))]
pub fn getauxval_wrapper(auxv_type: Type) -> Type;
}

pub trait Provider {
/// Look up an entry in the auxiliary vector. See getauxval(3) in glibc.
/// Unfortunately, prior to glibc 2.19, getauxval() returns 0 without
/// setting `errno` if the type is not found, so on such old systems
/// this will return `Ok(0)` rather than `Err(GetauxvalError::NotFound)`.
fn getauxval(&self, auxv_type: Type) -> Result<Type, GetauxvalError>;
/// If the requested type is not found, 0 will be returned.
fn getauxval(&self, auxv_type: Type) -> Type;
}

#[cfg(target_os="linux")]
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os = "linux"))]
pub struct NativeProvider {}

#[cfg(target_os="linux")]
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os = "linux"))]
impl Provider for NativeProvider {
/// Returns Some if the native invocation succeeds and the requested type was
/// found, otherwise None.
fn getauxval(&self, auxv_type: Type)
-> Result<Type, GetauxvalError> {

let mut result = 0;
fn getauxval(&self, auxv_type: Type) -> Type {
unsafe {
return match getauxval_wrapper(auxv_type, &mut result) {
1 => Ok(result),
0 => Err(GetauxvalError::NotFound),
-1 => Err(GetauxvalError::FunctionNotAvailable),
-2 => Err(GetauxvalError::UnknownError),
x => panic!("getauxval_wrapper returned an unexpected value: {}", x)
}
return getauxval_wrapper(auxv_type);
}
}
}
Expand Down
17 changes: 16 additions & 1 deletion src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os = "linux"))]
use cpu_feature::arm_linux::auxv;

#[inline(always)]
pub fn init_once() {
#[cfg(not(all(target_arch = "aarch64", target_os = "ios")))]
Expand All @@ -27,7 +31,18 @@ pub fn init_once() {
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os = "linux"))]
fn set_cpu_features() {
cpu_feature::arm_linux::arm_linux_set_cpu_features();
let getauxval = auxv::NativeProvider {};

unsafe {
GFp_armcap_P |= armcap_from_features(getauxval);
}
}

extern "C" {
#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"),
target_os="linux"))]
#[allow(non_upper_case_globals)]
pub static mut GFp_armcap_P: u32;
}

// On other platforms (excluding iOS aarch64), use C feature detection
Expand Down

0 comments on commit ee5b621

Please sign in to comment.