Skip to content

Commit

Permalink
Support changing OPENSSL_armcap with environment variable on Apple 64…
Browse files Browse the repository at this point in the history
…-bit ARM systems (aws#1045)

* use handle_cpu_env from cpu_aarch64_linux.c to cpu_aarch64_apple.c

* always use OPENSSL_armcap() when detecting hardware capabilities on arm

* refactor duplicated into cpu_aarch64.h/c

* add ifdefs to cpu_aarch64.h/c

* Update comments

Co-authored-by: Nevine Ebeid <[email protected]>

* adjust line length of comment

* set arm capabilities functions to fillow format of x86 ones

* make rest of the arm capability functions in line with x86 ones

---------

Co-authored-by: Nevine Ebeid <[email protected]>
Co-authored-by: Bill Yang <[email protected]>
  • Loading branch information
3 people committed Jul 31, 2023
1 parent 9973451 commit edaaed0
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 34 deletions.
52 changes: 52 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_aarch64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP)

#include "cpu_aarch64.h"

void handle_cpu_env(uint32_t *out, const char *in) {
const int invert = in[0] == '~';
const int or = in[0] == '|';
const int skip_first_byte = invert || or;
const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x';
uint32_t armcap = out[0];

int sscanf_result;
uint32_t v;
if (hex) {
sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx32, &v);
} else {
sscanf_result = sscanf(in + skip_first_byte, "%" PRIu32, &v);
}

if (!sscanf_result) {
return;
}

// Detect if the user is trying to use the environment variable to set
// a capability that is _not_ available on the CPU:
// If the runtime capability check (e.g via getauxval() on Linux)
// returned a non-zero hwcap in `armcap` (out)
// and a bit set in the requested `v` is not set in `armcap`,
// abort instead of crashing later.
// The case of invert cannot enable an unexisting capability;
// it can only disable an existing one.
if (!invert && armcap && (~armcap & v))
{
fprintf(stderr,
"Fatal Error: HW capability found: 0x%02X, but HW capability requested: 0x%02X.\n",
armcap, v);
exit(1);
}

if (invert) {
out[0] &= ~v;
} else if (or) {
out[0] |= v;
} else {
out[0] = v;
}
}

#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP
31 changes: 31 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_aarch64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#ifndef OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H
#define OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H

#if defined(__cplusplus)
extern "C" {
#endif

#include <inttypes.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP)

// cpu_aarch64 contains common functions used across multiple cpu_aarch64_* files

// handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|.
// See the comment in |OPENSSL_cpuid_setup| about this.
void handle_cpu_env(uint32_t *out, const char *in);

#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP

#if defined(__cplusplus)
}
#endif

#endif // OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H
16 changes: 16 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_aarch64_apple.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <openssl/arm_arch.h>

#include "cpu_aarch64.h"

extern uint32_t OPENSSL_armcap_P;

Expand Down Expand Up @@ -67,6 +68,21 @@ void OPENSSL_cpuid_setup(void) {
if (has_hw_feature("hw.optional.armv8_2_sha512")) {
OPENSSL_armcap_P |= ARMV8_SHA512;
}

// OPENSSL_armcap is a 32-bit, unsigned value which may start with "0x" to
// indicate a hex value. Prior to the 32-bit value, a '~' or '|' may be given.
//
// If the '~' prefix is present:
// the value is inverted and ANDed with the probed CPUID result
// If the '|' prefix is present:
// the value is ORed with the probed CPUID result
// Otherwise:
// the value is taken as the result of the CPUID
const char *env;
env = getenv("OPENSSL_armcap");
if (env != NULL) {
handle_cpu_env(&OPENSSL_armcap_P, env);
}
}

#endif // OPENSSL_AARCH64 && OPENSSL_APPLE && !OPENSSL_STATIC_ARMCAP
35 changes: 1 addition & 34 deletions crypto/fipsmodule/cpucap/cpu_aarch64_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,46 +22,13 @@
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/arm_arch.h>

#include "cpu_aarch64.h"

extern uint32_t OPENSSL_armcap_P;

// handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|
// and |out[1]|. See the comment in |OPENSSL_cpuid_setup| about this.
static void handle_cpu_env(uint32_t *out, const char *in) {
const int invert = in[0] == '~';
const int or = in[0] == '|';
const int skip_first_byte = invert || or;
const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x';

int sscanf_result;
uint32_t v;
if (hex) {
sscanf_result = sscanf(in + invert + 2, "%" PRIx32, &v);
} else {
sscanf_result = sscanf(in + invert, "%" PRIu32, &v);
}

if (!sscanf_result) {
return;
}

if (invert) {
out[0] &= ~v;
} else if (or) {
out[0] |= v;
} else {
out[0] = v;
}
}

void OPENSSL_cpuid_setup(void) {
unsigned long hwcap = getauxval(AT_HWCAP);

Expand Down

0 comments on commit edaaed0

Please sign in to comment.