armcap.c revision 296341
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)
16{
17    siglongjmp(ill_jmp, sig);
18}
19
20/*
21 * Following subroutines could have been inlined, but it's not all
22 * ARM compilers support inline assembler...
23 */
24void _armv7_neon_probe(void);
25unsigned int _armv7_tick(void);
26
27unsigned int OPENSSL_rdtsc(void)
28{
29    if (OPENSSL_armcap_P & ARMV7_TICK)
30        return _armv7_tick();
31    else
32        return 0;
33}
34
35#if defined(__GNUC__) && __GNUC__>=2
36void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
37#endif
38void OPENSSL_cpuid_setup(void)
39{
40    char *e;
41    struct sigaction ill_oact, ill_act;
42    sigset_t oset;
43    static int trigger = 0;
44
45    if (trigger)
46        return;
47    trigger = 1;
48
49    if ((e = getenv("OPENSSL_armcap"))) {
50        OPENSSL_armcap_P = strtoul(e, NULL, 0);
51        return;
52    }
53
54    sigfillset(&all_masked);
55    sigdelset(&all_masked, SIGILL);
56    sigdelset(&all_masked, SIGTRAP);
57    sigdelset(&all_masked, SIGFPE);
58    sigdelset(&all_masked, SIGBUS);
59    sigdelset(&all_masked, SIGSEGV);
60
61    OPENSSL_armcap_P = 0;
62
63    memset(&ill_act, 0, sizeof(ill_act));
64    ill_act.sa_handler = ill_handler;
65    ill_act.sa_mask = all_masked;
66
67    sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
68    sigaction(SIGILL, &ill_act, &ill_oact);
69
70    if (sigsetjmp(ill_jmp, 1) == 0) {
71        _armv7_neon_probe();
72        OPENSSL_armcap_P |= ARMV7_NEON;
73    }
74    if (sigsetjmp(ill_jmp, 1) == 0) {
75        _armv7_tick();
76        OPENSSL_armcap_P |= ARMV7_TICK;
77    }
78
79    sigaction(SIGILL, &ill_oact, NULL);
80    sigprocmask(SIG_SETMASK, &oset, NULL);
81}
82