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>
diff --git a/BUILDING.md b/BUILDING.md
index 65e88e8..99adbfd 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -91,6 +91,30 @@
     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
diff --git a/crypto/aes/aes.c b/crypto/aes/aes.c
index 1813eae..8823919 100644
--- a/crypto/aes/aes.c
+++ b/crypto/aes/aes.c
@@ -51,6 +51,8 @@
 #include <assert.h>
 #include <stdlib.h>
 
+#include <openssl/cpu.h>
+
 #include "internal.h"
 
 
@@ -1059,10 +1061,9 @@
 #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,
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index 7d44462..74f3223 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -121,7 +121,7 @@
 
 #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 @@
 #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
diff --git a/crypto/cpu-arm.c b/crypto/cpu-arm.c
index 6e037ab..14ad2ee 100644
--- a/crypto/cpu-arm.c
+++ b/crypto/cpu-arm.c
@@ -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 @@
   }
 }
 
-#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 @@
   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 @@
   }
 }
 
-#endif  /* defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) */
+#endif  /* (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) &&
+           !defined(OPENSSL_STATIC_ARMCAP) */
diff --git a/crypto/crypto.c b/crypto/crypto.c
index 34d04b4..26fbd70 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -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 @@
 
 #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;
diff --git a/crypto/modes/gcm.c b/crypto/modes/gcm.c
index 593dce8..b597f45 100644
--- a/crypto/modes/gcm.c
+++ b/crypto/modes/gcm.c
@@ -355,7 +355,7 @@
 #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]);
diff --git a/include/openssl/arm_arch.h b/include/openssl/arm_arch.h
index 123a890..1471db9 100644
--- a/include/openssl/arm_arch.h
+++ b/include/openssl/arm_arch.h
@@ -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)
 
diff --git a/include/openssl/cpu.h b/include/openssl/cpu.h
index 981d246..bda5347 100644
--- a/include/openssl/cpu.h
+++ b/include/openssl/cpu.h
@@ -94,6 +94,9 @@
 #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 @@
  * 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 */