1238384Sjkim#include <stdio.h>
2238384Sjkim#include <stdlib.h>
3238384Sjkim#include <string.h>
4238384Sjkim#include <setjmp.h>
5238384Sjkim#include <signal.h>
6238384Sjkim#include <crypto.h>
7238384Sjkim
8352193Sjkim#include "cryptlib.h"
9238384Sjkim#include "arm_arch.h"
10238384Sjkim
11325334Sjkim__attribute__ ((visibility("hidden")))
12290207Sjkimunsigned int OPENSSL_armcap_P = 0;
13238384Sjkim
14290207Sjkim#if __ARM_MAX_ARCH__<7
15290207Sjkimvoid OPENSSL_cpuid_setup(void)
16290207Sjkim{
17290207Sjkim}
18290207Sjkim
19290207Sjkimunsigned long OPENSSL_rdtsc(void)
20290207Sjkim{
21290207Sjkim    return 0;
22290207Sjkim}
23290207Sjkim#else
24238384Sjkimstatic sigset_t all_masked;
25238384Sjkim
26238384Sjkimstatic sigjmp_buf ill_jmp;
27280297Sjkimstatic void ill_handler(int sig)
28280297Sjkim{
29280297Sjkim    siglongjmp(ill_jmp, sig);
30280297Sjkim}
31238384Sjkim
32238384Sjkim/*
33238384Sjkim * Following subroutines could have been inlined, but it's not all
34238384Sjkim * ARM compilers support inline assembler...
35238384Sjkim */
36238384Sjkimvoid _armv7_neon_probe(void);
37290207Sjkimvoid _armv8_aes_probe(void);
38290207Sjkimvoid _armv8_sha1_probe(void);
39290207Sjkimvoid _armv8_sha256_probe(void);
40290207Sjkimvoid _armv8_pmull_probe(void);
41290207Sjkimunsigned long _armv7_tick(void);
42238384Sjkim
43290207Sjkimunsigned long OPENSSL_rdtsc(void)
44280297Sjkim{
45280297Sjkim    if (OPENSSL_armcap_P & ARMV7_TICK)
46280297Sjkim        return _armv7_tick();
47280297Sjkim    else
48280297Sjkim        return 0;
49280297Sjkim}
50238384Sjkim
51290207Sjkim/*
52290207Sjkim * Use a weak reference to getauxval() so we can use it if it is available but
53290207Sjkim * don't break the build if it is not.
54290207Sjkim */
55290207Sjkim# if defined(__GNUC__) && __GNUC__>=2
56280297Sjkimvoid OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
57290207Sjkimextern unsigned long getauxval(unsigned long type) __attribute__ ((weak));
58290207Sjkim# else
59290207Sjkimstatic unsigned long (*getauxval) (unsigned long) = NULL;
60290207Sjkim# endif
61290207Sjkim
62290207Sjkim/*
63290207Sjkim * ARM puts the the feature bits for Crypto Extensions in AT_HWCAP2, whereas
64290207Sjkim * AArch64 used AT_HWCAP.
65290207Sjkim */
66290207Sjkim# if defined(__arm__) || defined (__arm)
67290207Sjkim#  define HWCAP                  16
68290207Sjkim                                  /* AT_HWCAP */
69290207Sjkim#  define HWCAP_NEON             (1 << 12)
70290207Sjkim
71290207Sjkim#  define HWCAP_CE               26
72290207Sjkim                                  /* AT_HWCAP2 */
73290207Sjkim#  define HWCAP_CE_AES           (1 << 0)
74290207Sjkim#  define HWCAP_CE_PMULL         (1 << 1)
75290207Sjkim#  define HWCAP_CE_SHA1          (1 << 2)
76290207Sjkim#  define HWCAP_CE_SHA256        (1 << 3)
77290207Sjkim# elif defined(__aarch64__)
78290207Sjkim#  define HWCAP                  16
79290207Sjkim                                  /* AT_HWCAP */
80290207Sjkim#  define HWCAP_NEON             (1 << 1)
81290207Sjkim
82290207Sjkim#  define HWCAP_CE               HWCAP
83290207Sjkim#  define HWCAP_CE_AES           (1 << 3)
84290207Sjkim#  define HWCAP_CE_PMULL         (1 << 4)
85290207Sjkim#  define HWCAP_CE_SHA1          (1 << 5)
86290207Sjkim#  define HWCAP_CE_SHA256        (1 << 6)
87290207Sjkim# endif
88290207Sjkim
89238384Sjkimvoid OPENSSL_cpuid_setup(void)
90280297Sjkim{
91280297Sjkim    char *e;
92280297Sjkim    struct sigaction ill_oact, ill_act;
93280297Sjkim    sigset_t oset;
94280297Sjkim    static int trigger = 0;
95238384Sjkim
96280297Sjkim    if (trigger)
97280297Sjkim        return;
98280297Sjkim    trigger = 1;
99238384Sjkim
100280297Sjkim    if ((e = getenv("OPENSSL_armcap"))) {
101290207Sjkim        OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0);
102280297Sjkim        return;
103280297Sjkim    }
104238384Sjkim
105280297Sjkim    sigfillset(&all_masked);
106280297Sjkim    sigdelset(&all_masked, SIGILL);
107280297Sjkim    sigdelset(&all_masked, SIGTRAP);
108280297Sjkim    sigdelset(&all_masked, SIGFPE);
109280297Sjkim    sigdelset(&all_masked, SIGBUS);
110280297Sjkim    sigdelset(&all_masked, SIGSEGV);
111238384Sjkim
112280297Sjkim    OPENSSL_armcap_P = 0;
113238384Sjkim
114280297Sjkim    memset(&ill_act, 0, sizeof(ill_act));
115280297Sjkim    ill_act.sa_handler = ill_handler;
116280297Sjkim    ill_act.sa_mask = all_masked;
117238384Sjkim
118280297Sjkim    sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
119280297Sjkim    sigaction(SIGILL, &ill_act, &ill_oact);
120238384Sjkim
121290207Sjkim    if (getauxval != NULL) {
122290207Sjkim        if (getauxval(HWCAP) & HWCAP_NEON) {
123290207Sjkim            unsigned long hwcap = getauxval(HWCAP_CE);
124290207Sjkim
125290207Sjkim            OPENSSL_armcap_P |= ARMV7_NEON;
126290207Sjkim
127290207Sjkim            if (hwcap & HWCAP_CE_AES)
128290207Sjkim                OPENSSL_armcap_P |= ARMV8_AES;
129290207Sjkim
130290207Sjkim            if (hwcap & HWCAP_CE_PMULL)
131290207Sjkim                OPENSSL_armcap_P |= ARMV8_PMULL;
132290207Sjkim
133290207Sjkim            if (hwcap & HWCAP_CE_SHA1)
134290207Sjkim                OPENSSL_armcap_P |= ARMV8_SHA1;
135290207Sjkim
136290207Sjkim            if (hwcap & HWCAP_CE_SHA256)
137290207Sjkim                OPENSSL_armcap_P |= ARMV8_SHA256;
138290207Sjkim        }
139290207Sjkim    } else if (sigsetjmp(ill_jmp, 1) == 0) {
140280297Sjkim        _armv7_neon_probe();
141280297Sjkim        OPENSSL_armcap_P |= ARMV7_NEON;
142290207Sjkim        if (sigsetjmp(ill_jmp, 1) == 0) {
143290207Sjkim            _armv8_pmull_probe();
144290207Sjkim            OPENSSL_armcap_P |= ARMV8_PMULL | ARMV8_AES;
145290207Sjkim        } else if (sigsetjmp(ill_jmp, 1) == 0) {
146290207Sjkim            _armv8_aes_probe();
147290207Sjkim            OPENSSL_armcap_P |= ARMV8_AES;
148290207Sjkim        }
149290207Sjkim        if (sigsetjmp(ill_jmp, 1) == 0) {
150290207Sjkim            _armv8_sha1_probe();
151290207Sjkim            OPENSSL_armcap_P |= ARMV8_SHA1;
152290207Sjkim        }
153290207Sjkim        if (sigsetjmp(ill_jmp, 1) == 0) {
154290207Sjkim            _armv8_sha256_probe();
155290207Sjkim            OPENSSL_armcap_P |= ARMV8_SHA256;
156290207Sjkim        }
157280297Sjkim    }
158280297Sjkim    if (sigsetjmp(ill_jmp, 1) == 0) {
159280297Sjkim        _armv7_tick();
160280297Sjkim        OPENSSL_armcap_P |= ARMV7_TICK;
161280297Sjkim    }
162280297Sjkim
163280297Sjkim    sigaction(SIGILL, &ill_oact, NULL);
164280297Sjkim    sigprocmask(SIG_SETMASK, &oset, NULL);
165280297Sjkim}
166290207Sjkim#endif
167