aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2014-06-01 17:21:06 +0200
committerAndy Polyakov <appro@openssl.org>2014-06-01 17:21:06 +0200
commite8d93e342b4b7d43c73e955e81e227c514d389d9 (patch)
treeefbe9abfc0cdcea810358ae088284fc2ddd0a3fc /crypto
parent992bba11d53985c8d4cbcb5dd95034dbe92d3671 (diff)
downloadopenssl-e8d93e342b4b7d43c73e955e81e227c514d389d9.tar.gz
Add linux-aarch64 taget.
armcap.c is shared between 32- and 64-bit builds and features link-time detection of getauxval. Submitted by: Ard Biesheuvel.
Diffstat (limited to 'crypto')
-rw-r--r--crypto/arm64cpuid.S46
-rw-r--r--crypto/arm_arch.h15
-rw-r--r--crypto/armcap.c71
3 files changed, 121 insertions, 11 deletions
diff --git a/crypto/arm64cpuid.S b/crypto/arm64cpuid.S
new file mode 100644
index 0000000000..4778ac1dea
--- /dev/null
+++ b/crypto/arm64cpuid.S
@@ -0,0 +1,46 @@
+#include "arm_arch.h"
+
+.text
+.arch armv8-a+crypto
+
+.align 5
+.global _armv7_neon_probe
+.type _armv7_neon_probe,%function
+_armv7_neon_probe:
+ orr v15.16b, v15.16b, v15.16b
+ ret
+.size _armv7_neon_probe,.-_armv7_neon_probe
+
+.global _armv7_tick
+.type _armv7_tick,%function
+_armv7_tick:
+ mrs x0, CNTVCT_EL0
+ ret
+.size _armv7_tick,.-_armv7_tick
+
+.global _armv8_aes_probe
+.type _armv8_aes_probe,%function
+_armv8_aes_probe:
+ aese v0.16b, v0.16b
+ ret
+.size _armv8_aes_probe,.-_armv8_aes_probe
+
+.global _armv8_sha1_probe
+.type _armv8_sha1_probe,%function
+_armv8_sha1_probe:
+ sha1h s0, s0
+ ret
+.size _armv8_sha1_probe,.-_armv8_sha1_probe
+
+.global _armv8_sha256_probe
+.type _armv8_sha256_probe,%function
+_armv8_sha256_probe:
+ sha256su0 v0.4s, v0.4s
+ ret
+.size _armv8_sha256_probe,.-_armv8_sha256_probe
+.global _armv8_pmull_probe
+.type _armv8_pmull_probe,%function
+_armv8_pmull_probe:
+ pmull v0.1q, v0.1d, v0.1d
+ ret
+.size _armv8_pmull_probe,.-_armv8_pmull_probe
diff --git a/crypto/arm_arch.h b/crypto/arm_arch.h
index d68318c851..6fa87244d1 100644
--- a/crypto/arm_arch.h
+++ b/crypto/arm_arch.h
@@ -10,13 +10,24 @@
# define __ARMEL__
# endif
# elif defined(__GNUC__)
+# if defined(__aarch64__)
+# define __ARM_ARCH__ 8
+# if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define __ARMEB__
+# else
+# define __ARMEL__
+# endif
/*
* Why doesn't gcc define __ARM_ARCH__? Instead it defines
* bunch of below macros. See all_architectires[] table in
* gcc/config/arm/arm.c. On a side note it defines
* __ARMEL__/__ARMEB__ for little-/big-endian.
*/
-# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
+# elif defined(__ARM_ARCH)
+# define __ARM_ARCH__ __ARM_ARCH
+# elif defined(__ARM_ARCH_8A__)
+# define __ARM_ARCH__ 8
+# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
defined(__ARM_ARCH_7EM__)
# define __ARM_ARCH__ 7
@@ -43,6 +54,7 @@
#if !__ASSEMBLER__
extern unsigned int OPENSSL_armcap_P;
+#endif
#define ARMV7_NEON (1<<0)
#define ARMV7_TICK (1<<1)
@@ -50,6 +62,5 @@ extern unsigned int OPENSSL_armcap_P;
#define ARMV8_SHA1 (1<<3)
#define ARMV8_SHA256 (1<<4)
#define ARMV8_PMULL (1<<5)
-#endif
#endif
diff --git a/crypto/armcap.c b/crypto/armcap.c
index 550414425d..7e46d07a32 100644
--- a/crypto/armcap.c
+++ b/crypto/armcap.c
@@ -23,9 +23,9 @@ void _armv8_aes_probe(void);
void _armv8_sha1_probe(void);
void _armv8_sha256_probe(void);
void _armv8_pmull_probe(void);
-unsigned int _armv7_tick(void);
+unsigned long _armv7_tick(void);
-unsigned int OPENSSL_rdtsc(void)
+unsigned long OPENSSL_rdtsc(void)
{
if (OPENSSL_armcap_P & ARMV7_TICK)
return _armv7_tick();
@@ -33,9 +33,41 @@ unsigned int OPENSSL_rdtsc(void)
return 0;
}
+/*
+ * Use a weak reference to getauxval() so we can use it if it is available but
+ * don't break the build if it is not.
+ */
#if defined(__GNUC__) && __GNUC__>=2
void OPENSSL_cpuid_setup(void) __attribute__((constructor));
+extern unsigned long getauxval(unsigned long type) __attribute__((weak));
+#else
+static unsigned long (*getauxval)(unsigned long) = NULL;
#endif
+
+/*
+ * ARM puts the the feature bits for Crypto Extensions in AT_HWCAP2, whereas
+ * AArch64 used AT_HWCAP.
+ */
+#if defined(__arm__) || defined (__arm)
+# define HWCAP 16 /* AT_HWCAP */
+# define HWCAP_NEON (1 << 12)
+
+# define HWCAP_CE 26 /* AT_HWCAP2 */
+# define HWCAP_CE_AES (1 << 0)
+# define HWCAP_CE_PMULL (1 << 1)
+# define HWCAP_CE_SHA1 (1 << 2)
+# define HWCAP_CE_SHA256 (1 << 3)
+#elif defined(__aarch64__)
+# define HWCAP 16 /* AT_HWCAP */
+# define HWCAP_NEON (1 << 1)
+
+# define HWCAP_CE HWCAP
+# define HWCAP_CE_AES (1 << 3)
+# define HWCAP_CE_PMULL (1 << 4)
+# define HWCAP_CE_SHA1 (1 << 5)
+# define HWCAP_CE_SHA256 (1 << 6)
+#endif
+
void OPENSSL_cpuid_setup(void)
{
char *e;
@@ -48,7 +80,7 @@ void OPENSSL_cpuid_setup(void)
if ((e=getenv("OPENSSL_armcap")))
{
- OPENSSL_armcap_P=strtoul(e,NULL,0);
+ OPENSSL_armcap_P=(unsigned int)strtoul(e,NULL,0);
return;
}
@@ -68,12 +100,38 @@ void OPENSSL_cpuid_setup(void)
sigprocmask(SIG_SETMASK,&ill_act.sa_mask,&oset);
sigaction(SIGILL,&ill_act,&ill_oact);
- if (sigsetjmp(ill_jmp,1) == 0)
+ if (getauxval != NULL)
+ {
+ if (getauxval(HWCAP) & HWCAP_NEON)
+ {
+ unsigned long hwcap = getauxval(HWCAP_CE);
+
+ OPENSSL_armcap_P |= ARMV7_NEON;
+
+ if (hwcap & HWCAP_CE_AES)
+ OPENSSL_armcap_P |= ARMV8_AES;
+
+ if (hwcap & HWCAP_CE_PMULL)
+ OPENSSL_armcap_P |= ARMV8_PMULL;
+
+ if (hwcap & HWCAP_CE_SHA1)
+ OPENSSL_armcap_P |= ARMV8_SHA1;
+
+ if (hwcap & HWCAP_CE_SHA256)
+ OPENSSL_armcap_P |= ARMV8_SHA256;
+ }
+ }
+ else if (sigsetjmp(ill_jmp,1) == 0)
{
_armv7_neon_probe();
OPENSSL_armcap_P |= ARMV7_NEON;
if (sigsetjmp(ill_jmp,1) == 0)
{
+ _armv8_pmull_probe();
+ OPENSSL_armcap_P |= ARMV8_PMULL|ARMV8_AES;
+ }
+ else if (sigsetjmp(ill_jmp,1) == 0)
+ {
_armv8_aes_probe();
OPENSSL_armcap_P |= ARMV8_AES;
}
@@ -87,11 +145,6 @@ void OPENSSL_cpuid_setup(void)
_armv8_sha256_probe();
OPENSSL_armcap_P |= ARMV8_SHA256;
}
- if (sigsetjmp(ill_jmp,1) == 0)
- {
- _armv8_pmull_probe();
- OPENSSL_armcap_P |= ARMV8_PMULL;
- }
}
if (sigsetjmp(ill_jmp,1) == 0)
{