Allow ARM capabilities to be set at compile time.

Some ARM environments don't support |getauxval| or signals and need to
configure the capabilities of the chip at compile time. This change adds
defines that allow them to do so.

Change-Id: I4e6987f69dd13444029bc7ac7ed4dbf8fb1faa76
Reviewed-on: https://boringssl-review.googlesource.com/6280
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
Adam Langley 2015-10-16 15:46:46 -07:00
parent c2ae53db6d
commit 6a7cfbe06a
8 changed files with 111 additions and 22 deletions

View File

@ -91,6 +91,30 @@ binaries.
don't have steps for assembling the assembly language source files, so they
currently cannot be used to build BoringSSL.
## Embedded ARM
ARM, unlike Intel, does not have an instruction that allows applications to
discover the capabilities of the processor. Instead, the capability information
has to be provided by the operating system somehow.
BoringSSL will try to use `getauxval` to discover the capabilities and, failing
that, will probe for NEON support by executing a NEON instruction and handling
any illegal-instruction signal. But some environments don't support that sort
of thing and, for them, it's possible to configure the CPU capabilities
at compile time.
If you define `OPENSSL_STATIC_ARMCAP` then you can define any of the following
to enabling the corresponding ARM feature.
* `OPENSSL_STATIC_ARMCAP_NEON` or `__ARM_NEON__` (note that the latter is set by compilers when NEON support is enabled).
* `OPENSSL_STATIC_ARMCAP_AES`
* `OPENSSL_STATIC_ARMCAP_SHA1`
* `OPENSSL_STATIC_ARMCAP_SHA256`
* `OPENSSL_STATIC_ARMCAP_PMULL`
Note that if a feature is enabled in this way, but not actually supported at
run-time, BoringSSL will likely crash.
# Running tests
There are two sets of tests: the C/C++ tests and the blackbox tests. For former

View File

@ -51,6 +51,8 @@
#include <assert.h>
#include <stdlib.h>
#include <openssl/cpu.h>
#include "internal.h"
@ -1059,10 +1061,9 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
#else
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
#include <openssl/arm_arch.h>
static int hwaes_capable(void) {
return (OPENSSL_armcap_P & ARMV8_AES) != 0;
return CRYPTO_is_ARMv8_AES_capable();
}
int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits,

View File

@ -121,7 +121,7 @@ static char bsaes_capable(void) {
#define HWAES
static int hwaes_capable(void) {
return (OPENSSL_armcap_P & ARMV8_AES) != 0;
return CRYPTO_is_ARMv8_AES_capable();
}
int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits,
@ -1756,7 +1756,7 @@ int EVP_has_aes_hardware(void) {
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
return aesni_capable() && crypto_gcm_clmul_enabled();
#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
return hwaes_capable() && (OPENSSL_armcap_P & ARMV8_PMULL);
return hwaes_capable() && CRYPTO_is_ARMv8_PMULL_capable();
#else
return 0;
#endif

View File

@ -14,15 +14,14 @@
#include <openssl/cpu.h>
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
#if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \
!defined(OPENSSL_STATIC_ARMCAP)
#include <inttypes.h>
#include <string.h>
#if !defined(OPENSSL_TRUSTY)
#include <setjmp.h>
#include <signal.h>
#endif
#include <openssl/arm_arch.h>
@ -33,6 +32,8 @@
unsigned long getauxval(unsigned long type) __attribute__((weak));
extern uint32_t OPENSSL_armcap_P;
char CRYPTO_is_NEON_capable(void) {
return (OPENSSL_armcap_P & ARMV7_NEON) != 0;
}
@ -62,7 +63,15 @@ void CRYPTO_set_NEON_functional(char neon_functional) {
}
}
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM) && !defined(OPENSSL_TRUSTY)
int CRYPTO_is_ARMv8_AES_capable(void) {
return (OPENSSL_armcap_P & ARMV8_AES) != 0;
}
int CRYPTO_is_ARMv8_PMULL_capable(void) {
return (OPENSSL_armcap_P & ARMV8_PMULL) != 0;
}
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM)
static sigjmp_buf sigill_jmp;
@ -120,7 +129,7 @@ static int probe_for_NEON(void) {
return 0;
}
#endif /* !OPENSSL_NO_ASM && OPENSSL_ARM && !OPENSSL_TRUSTY */
#endif /* !OPENSSL_NO_ASM && OPENSSL_ARM */
void OPENSSL_cpuid_setup(void) {
if (getauxval == NULL) {
@ -186,4 +195,5 @@ void OPENSSL_cpuid_setup(void) {
}
}
#endif /* defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) */
#endif /* (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) &&
!defined(OPENSSL_STATIC_ARMCAP) */

View File

@ -17,7 +17,7 @@
#include "internal.h"
#if !defined(OPENSSL_NO_ASM) && \
#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \
(defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
/* x86, x86_64 and the ARMs need to record the result of a cpuid call for the
@ -57,7 +57,27 @@ uint32_t OPENSSL_ia32cap_P[4] = {0};
#include <openssl/arm_arch.h>
#if defined(__ARM_NEON__)
#if defined(OPENSSL_STATIC_ARMCAP)
uint32_t OPENSSL_armcap_P =
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
ARMV7_NEON | ARMV7_NEON_FUNCTIONAL |
#endif
#if defined(OPENSSL_STATIC_ARMCAP_AES)
ARMV8_AES |
#endif
#if defined(OPENSSL_STATIC_ARMCAP_SHA1)
ARMV8_SHA1 |
#endif
#if defined(OPENSSL_STATIC_ARMCAP_SHA256)
ARMV8_SHA256 |
#endif
#if defined(OPENSSL_STATIC_ARMCAP_PMULL)
ARMV8_PMULL |
#endif
0;
#elif defined(__ARM_NEON__)
uint32_t OPENSSL_armcap_P = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL;
#else
uint32_t OPENSSL_armcap_P = ARMV7_NEON_FUNCTIONAL;

View File

@ -355,7 +355,7 @@ void gcm_ghash_4bit_x86(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in
#define GCM_FUNCREF_4BIT
static int pmull_capable(void) {
return (OPENSSL_armcap_P & ARMV8_PMULL) != 0;
return CRYPTO_is_ARMv8_PMULL_capable();
}
void gcm_init_v8(u128 Htable[16], const uint64_t Xi[2]);

View File

@ -102,15 +102,6 @@
* will be included. */
#define __ARM_MAX_ARCH__ 8
#if !__ASSEMBLER__
/* OPENSSL_armcap_P contains flags describing the capabilities of the CPU and
* is easy for assembly code to acesss. For C code, see the functions in
* |cpu.h|. */
extern uint32_t OPENSSL_armcap_P;
#endif /* !__ASSEMBLER__ */
/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */
#define ARMV7_NEON (1 << 0)

View File

@ -94,6 +94,9 @@ extern uint32_t OPENSSL_ia32cap_P[4];
#endif
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
#if !defined(OPENSSL_STATIC_ARMCAP)
/* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. Note
* that |OPENSSL_armcap_P| also exists and contains the same information in a
* form that's easier for assembly to use. */
@ -116,6 +119,46 @@ OPENSSL_EXPORT char CRYPTO_is_NEON_functional(void);
* compiled with |-mfpu=neon| or if |CRYPTO_set_NEON_capable| has been called
* with a non-zero argument. */
OPENSSL_EXPORT void CRYPTO_set_NEON_functional(char neon_functional);
/* CRYPTO_is_ARMv8_AES_capable returns true if the current CPU supports the
* ARMv8 AES instruction. */
int CRYPTO_is_ARMv8_AES_capable(void);
/* CRYPTO_is_ARMv8_PMULL_capable returns true if the current CPU supports the
* ARMv8 PMULL instruction. */
int CRYPTO_is_ARMv8_PMULL_capable(void);
#else
static inline int CRYPTO_is_NEON_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
return 1;
#else
return 0;
#endif
}
static inline int CRYPTO_is_NEON_functional(void) {
return CRYPTO_is_NEON_capable();
}
static inline int CRYPTO_is_ARMv8_AES_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_AES)
return 1;
#else
return 0;
#endif
}
static inline int CRYPTO_is_ARMv8_PMULL_capable(void) {
#if defined(OPENSSL_STATIC_ARMCAP_PMULL)
return 1;
#else
return 0;
#endif
}
#endif /* OPENSSL_STATIC_ARMCAP */
#endif /* OPENSSL_ARM */