1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <setjmp.h>
5#include <signal.h>
6#include <crypto.h>
7
8#include "arm_arch.h"
9
10unsigned int OPENSSL_armcap_P;
11
12static sigset_t all_masked;
13
14static sigjmp_buf ill_jmp;
15static void ill_handler (int sig) { siglongjmp(ill_jmp,sig); }
16
17/*
18 * Following subroutines could have been inlined, but it's not all
19 * ARM compilers support inline assembler...
20 */
21void _armv7_neon_probe(void);
22void _armv8_aes_probe(void);
23void _armv8_sha1_probe(void);
24void _armv8_sha256_probe(void);
25void _armv8_pmull_probe(void);
26unsigned long _armv7_tick(void);
27
28unsigned long OPENSSL_rdtsc(void)
29	{
30	if (OPENSSL_armcap_P & ARMV7_TICK)
31		return _armv7_tick();
32	else
33		return 0;
34	}
35
36/*
37 * Use a weak reference to getauxval() so we can use it if it is available but
38 * don't break the build if it is not.
39 */
40#if defined(__GNUC__) && __GNUC__>=2
41void OPENSSL_cpuid_setup(void) __attribute__((constructor));
42extern unsigned long getauxval(unsigned long type) __attribute__((weak));
43#else
44static unsigned long (*getauxval)(unsigned long) = NULL;
45#endif
46
47/*
48 * ARM puts the the feature bits for Crypto Extensions in AT_HWCAP2, whereas
49 * AArch64 used AT_HWCAP.
50 */
51#if defined(__arm__) || defined (__arm)
52# define HWCAP			16	/* AT_HWCAP */
53# define HWCAP_NEON		(1 << 12)
54
55# define HWCAP_CE		26	/* AT_HWCAP2 */
56# define HWCAP_CE_AES		(1 << 0)
57# define HWCAP_CE_PMULL		(1 << 1)
58# define HWCAP_CE_SHA1		(1 << 2)
59# define HWCAP_CE_SHA256	(1 << 3)
60#elif defined(__aarch64__)
61# define HWCAP			16	/* AT_HWCAP */
62# define HWCAP_NEON		(1 << 1)
63
64# define HWCAP_CE		HWCAP
65# define HWCAP_CE_AES		(1 << 3)
66# define HWCAP_CE_PMULL		(1 << 4)
67# define HWCAP_CE_SHA1		(1 << 5)
68# define HWCAP_CE_SHA256	(1 << 6)
69#endif
70
71void OPENSSL_cpuid_setup(void)
72	{
73	char *e;
74	struct sigaction	ill_oact,ill_act;
75	sigset_t		oset;
76	static int trigger=0;
77
78	if (trigger) return;
79	trigger=1;
80
81	if ((e=getenv("OPENSSL_armcap")))
82		{
83		OPENSSL_armcap_P=(unsigned int)strtoul(e,NULL,0);
84		return;
85		}
86
87	sigfillset(&all_masked);
88	sigdelset(&all_masked,SIGILL);
89	sigdelset(&all_masked,SIGTRAP);
90	sigdelset(&all_masked,SIGFPE);
91	sigdelset(&all_masked,SIGBUS);
92	sigdelset(&all_masked,SIGSEGV);
93
94	OPENSSL_armcap_P = 0;
95
96	memset(&ill_act,0,sizeof(ill_act));
97	ill_act.sa_handler = ill_handler;
98	ill_act.sa_mask    = all_masked;
99
100	sigprocmask(SIG_SETMASK,&ill_act.sa_mask,&oset);
101	sigaction(SIGILL,&ill_act,&ill_oact);
102
103	if (getauxval != NULL)
104		{
105		if (getauxval(HWCAP) & HWCAP_NEON)
106			{
107			unsigned long hwcap = getauxval(HWCAP_CE);
108
109			OPENSSL_armcap_P |= ARMV7_NEON;
110
111			if (hwcap & HWCAP_CE_AES)
112				OPENSSL_armcap_P |= ARMV8_AES;
113
114			if (hwcap & HWCAP_CE_PMULL)
115				OPENSSL_armcap_P |= ARMV8_PMULL;
116
117			if (hwcap & HWCAP_CE_SHA1)
118				OPENSSL_armcap_P |= ARMV8_SHA1;
119
120			if (hwcap & HWCAP_CE_SHA256)
121				OPENSSL_armcap_P |= ARMV8_SHA256;
122			}
123		}
124	else if (sigsetjmp(ill_jmp,1) == 0)
125		{
126		_armv7_neon_probe();
127		OPENSSL_armcap_P |= ARMV7_NEON;
128		if (sigsetjmp(ill_jmp,1) == 0)
129			{
130			_armv8_pmull_probe();
131			OPENSSL_armcap_P |= ARMV8_PMULL|ARMV8_AES;
132			}
133		else if (sigsetjmp(ill_jmp,1) == 0)
134			{
135			_armv8_aes_probe();
136			OPENSSL_armcap_P |= ARMV8_AES;
137			}
138		if (sigsetjmp(ill_jmp,1) == 0)
139			{
140			_armv8_sha1_probe();
141			OPENSSL_armcap_P |= ARMV8_SHA1;
142			}
143		if (sigsetjmp(ill_jmp,1) == 0)
144			{
145			_armv8_sha256_probe();
146			OPENSSL_armcap_P |= ARMV8_SHA256;
147			}
148		}
149	if (sigsetjmp(ill_jmp,1) == 0)
150		{
151		_armv7_tick();
152		OPENSSL_armcap_P |= ARMV7_TICK;
153		}
154
155	sigaction (SIGILL,&ill_oact,NULL);
156	sigprocmask(SIG_SETMASK,&oset,NULL);
157	}
158