1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdio.h>
11e1051a39Sopenharmony_ci#include <stdlib.h>
12e1051a39Sopenharmony_ci#include <string.h>
13e1051a39Sopenharmony_ci#include <setjmp.h>
14e1051a39Sopenharmony_ci#include <signal.h>
15e1051a39Sopenharmony_ci#include <sys/time.h>
16e1051a39Sopenharmony_ci#include <unistd.h>
17e1051a39Sopenharmony_ci#include <openssl/bn.h>
18e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
19e1051a39Sopenharmony_ci#include "crypto/sparc_arch.h"
20e1051a39Sopenharmony_ci
21e1051a39Sopenharmony_ci#if defined(__GNUC__) && defined(__linux)
22e1051a39Sopenharmony_ci__attribute__ ((visibility("hidden")))
23e1051a39Sopenharmony_ci#endif
24e1051a39Sopenharmony_ciunsigned int OPENSSL_sparcv9cap_P[2] = { SPARCV9_TICK_PRIVILEGED, 0 };
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_ciunsigned long _sparcv9_rdtick(void);
27e1051a39Sopenharmony_civoid _sparcv9_vis1_probe(void);
28e1051a39Sopenharmony_ciunsigned long _sparcv9_vis1_instrument(void);
29e1051a39Sopenharmony_civoid _sparcv9_vis2_probe(void);
30e1051a39Sopenharmony_civoid _sparcv9_fmadd_probe(void);
31e1051a39Sopenharmony_ciunsigned long _sparcv9_rdcfr(void);
32e1051a39Sopenharmony_civoid _sparcv9_vis3_probe(void);
33e1051a39Sopenharmony_civoid _sparcv9_fjaesx_probe(void);
34e1051a39Sopenharmony_ciunsigned long _sparcv9_random(void);
35e1051a39Sopenharmony_cisize_t _sparcv9_vis1_instrument_bus(unsigned int *, size_t);
36e1051a39Sopenharmony_cisize_t _sparcv9_vis1_instrument_bus2(unsigned int *, size_t, size_t);
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ciuint32_t OPENSSL_rdtsc(void)
39e1051a39Sopenharmony_ci{
40e1051a39Sopenharmony_ci    if (OPENSSL_sparcv9cap_P[0] & SPARCV9_TICK_PRIVILEGED)
41e1051a39Sopenharmony_ci#if defined(__sun) && defined(__SVR4)
42e1051a39Sopenharmony_ci        return gethrtime();
43e1051a39Sopenharmony_ci#else
44e1051a39Sopenharmony_ci        return 0;
45e1051a39Sopenharmony_ci#endif
46e1051a39Sopenharmony_ci    else
47e1051a39Sopenharmony_ci        return _sparcv9_rdtick();
48e1051a39Sopenharmony_ci}
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_cisize_t OPENSSL_instrument_bus(unsigned int *out, size_t cnt)
51e1051a39Sopenharmony_ci{
52e1051a39Sopenharmony_ci    if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
53e1051a39Sopenharmony_ci        SPARCV9_BLK)
54e1051a39Sopenharmony_ci        return _sparcv9_vis1_instrument_bus(out, cnt);
55e1051a39Sopenharmony_ci    else
56e1051a39Sopenharmony_ci        return 0;
57e1051a39Sopenharmony_ci}
58e1051a39Sopenharmony_ci
59e1051a39Sopenharmony_cisize_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
60e1051a39Sopenharmony_ci{
61e1051a39Sopenharmony_ci    if ((OPENSSL_sparcv9cap_P[0] & (SPARCV9_TICK_PRIVILEGED | SPARCV9_BLK)) ==
62e1051a39Sopenharmony_ci        SPARCV9_BLK)
63e1051a39Sopenharmony_ci        return _sparcv9_vis1_instrument_bus2(out, cnt, max);
64e1051a39Sopenharmony_ci    else
65e1051a39Sopenharmony_ci        return 0;
66e1051a39Sopenharmony_ci}
67e1051a39Sopenharmony_ci
68e1051a39Sopenharmony_cistatic sigjmp_buf common_jmp;
69e1051a39Sopenharmony_cistatic void common_handler(int sig)
70e1051a39Sopenharmony_ci{
71e1051a39Sopenharmony_ci    siglongjmp(common_jmp, sig);
72e1051a39Sopenharmony_ci}
73e1051a39Sopenharmony_ci
74e1051a39Sopenharmony_ci#if defined(__sun) && defined(__SVR4)
75e1051a39Sopenharmony_ci# if defined(__GNUC__) && __GNUC__>=2
76e1051a39Sopenharmony_ciextern unsigned int getisax(unsigned int vec[], unsigned int sz) __attribute__ ((weak));
77e1051a39Sopenharmony_ci# elif defined(__SUNPRO_C)
78e1051a39Sopenharmony_ci#pragma weak getisax
79e1051a39Sopenharmony_ciextern unsigned int getisax(unsigned int vec[], unsigned int sz);
80e1051a39Sopenharmony_ci# else
81e1051a39Sopenharmony_cistatic unsigned int (*getisax) (unsigned int vec[], unsigned int sz) = NULL;
82e1051a39Sopenharmony_ci# endif
83e1051a39Sopenharmony_ci#endif
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_civoid OPENSSL_cpuid_setup(void)
86e1051a39Sopenharmony_ci{
87e1051a39Sopenharmony_ci    char *e;
88e1051a39Sopenharmony_ci    struct sigaction common_act, ill_oact, bus_oact;
89e1051a39Sopenharmony_ci    sigset_t all_masked, oset;
90e1051a39Sopenharmony_ci    static int trigger = 0;
91e1051a39Sopenharmony_ci
92e1051a39Sopenharmony_ci    if (trigger)
93e1051a39Sopenharmony_ci        return;
94e1051a39Sopenharmony_ci    trigger = 1;
95e1051a39Sopenharmony_ci
96e1051a39Sopenharmony_ci    if ((e = getenv("OPENSSL_sparcv9cap"))) {
97e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] = strtoul(e, NULL, 0);
98e1051a39Sopenharmony_ci        if ((e = strchr(e, ':')))
99e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[1] = strtoul(e + 1, NULL, 0);
100e1051a39Sopenharmony_ci        return;
101e1051a39Sopenharmony_ci    }
102e1051a39Sopenharmony_ci
103e1051a39Sopenharmony_ci#if defined(__sun) && defined(__SVR4)
104e1051a39Sopenharmony_ci    if (getisax != NULL) {
105e1051a39Sopenharmony_ci        unsigned int vec[2] = { 0, 0 };
106e1051a39Sopenharmony_ci
107e1051a39Sopenharmony_ci        if (getisax (vec,2)) {
108e1051a39Sopenharmony_ci            if (vec[0]&0x00020) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1;
109e1051a39Sopenharmony_ci            if (vec[0]&0x00040) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
110e1051a39Sopenharmony_ci            if (vec[0]&0x00080) OPENSSL_sparcv9cap_P[0] |= SPARCV9_BLK;
111e1051a39Sopenharmony_ci            if (vec[0]&0x00100) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
112e1051a39Sopenharmony_ci            if (vec[0]&0x00400) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
113e1051a39Sopenharmony_ci            if (vec[0]&0x01000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJHPCACE;
114e1051a39Sopenharmony_ci            if (vec[0]&0x02000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJDESX;
115e1051a39Sopenharmony_ci            if (vec[0]&0x08000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_IMA;
116e1051a39Sopenharmony_ci            if (vec[0]&0x10000) OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
117e1051a39Sopenharmony_ci            if (vec[1]&0x00008) OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS4;
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ci            /* reconstruct %cfr copy */
120e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[1] = (vec[0]>>17)&0x3ff;
121e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[1] |= (OPENSSL_sparcv9cap_P[1]&CFR_MONTMUL)<<1;
122e1051a39Sopenharmony_ci            if (vec[0]&0x20000000) OPENSSL_sparcv9cap_P[1] |= CFR_CRC32C;
123e1051a39Sopenharmony_ci            if (vec[1]&0x00000020) OPENSSL_sparcv9cap_P[1] |= CFR_XMPMUL;
124e1051a39Sopenharmony_ci            if (vec[1]&0x00000040)
125e1051a39Sopenharmony_ci                OPENSSL_sparcv9cap_P[1] |= CFR_XMONTMUL|CFR_XMONTSQR;
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ci            /* Some heuristics */
128e1051a39Sopenharmony_ci            /* all known VIS2-capable CPUs have unprivileged tick counter */
129e1051a39Sopenharmony_ci            if (OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS2)
130e1051a39Sopenharmony_ci                OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[0] |= SPARCV9_PREFER_FPU;
133e1051a39Sopenharmony_ci
134e1051a39Sopenharmony_ci            /* detect UltraSPARC-Tx, see sparccpud.S for details... */
135e1051a39Sopenharmony_ci            if ((OPENSSL_sparcv9cap_P[0]&SPARCV9_VIS1) &&
136e1051a39Sopenharmony_ci                _sparcv9_vis1_instrument() >= 12)
137e1051a39Sopenharmony_ci                OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
138e1051a39Sopenharmony_ci        }
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci        if (sizeof(size_t) == 8)
141e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
142e1051a39Sopenharmony_ci
143e1051a39Sopenharmony_ci        return;
144e1051a39Sopenharmony_ci    }
145e1051a39Sopenharmony_ci#endif
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ci    /* Initial value, fits UltraSPARC-I&II... */
148e1051a39Sopenharmony_ci    OPENSSL_sparcv9cap_P[0] = SPARCV9_PREFER_FPU | SPARCV9_TICK_PRIVILEGED;
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_ci    sigfillset(&all_masked);
151e1051a39Sopenharmony_ci    sigdelset(&all_masked, SIGILL);
152e1051a39Sopenharmony_ci    sigdelset(&all_masked, SIGTRAP);
153e1051a39Sopenharmony_ci# ifdef SIGEMT
154e1051a39Sopenharmony_ci    sigdelset(&all_masked, SIGEMT);
155e1051a39Sopenharmony_ci# endif
156e1051a39Sopenharmony_ci    sigdelset(&all_masked, SIGFPE);
157e1051a39Sopenharmony_ci    sigdelset(&all_masked, SIGBUS);
158e1051a39Sopenharmony_ci    sigdelset(&all_masked, SIGSEGV);
159e1051a39Sopenharmony_ci    sigprocmask(SIG_SETMASK, &all_masked, &oset);
160e1051a39Sopenharmony_ci
161e1051a39Sopenharmony_ci    memset(&common_act, 0, sizeof(common_act));
162e1051a39Sopenharmony_ci    common_act.sa_handler = common_handler;
163e1051a39Sopenharmony_ci    common_act.sa_mask = all_masked;
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_ci    sigaction(SIGILL, &common_act, &ill_oact);
166e1051a39Sopenharmony_ci    sigaction(SIGBUS, &common_act, &bus_oact); /* T1 fails 16-bit ldda [on
167e1051a39Sopenharmony_ci                                                * Linux] */
168e1051a39Sopenharmony_ci
169e1051a39Sopenharmony_ci    if (sigsetjmp(common_jmp, 1) == 0) {
170e1051a39Sopenharmony_ci        _sparcv9_rdtick();
171e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] &= ~SPARCV9_TICK_PRIVILEGED;
172e1051a39Sopenharmony_ci    }
173e1051a39Sopenharmony_ci
174e1051a39Sopenharmony_ci    if (sigsetjmp(common_jmp, 1) == 0) {
175e1051a39Sopenharmony_ci        _sparcv9_vis1_probe();
176e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS1 | SPARCV9_BLK;
177e1051a39Sopenharmony_ci        /* detect UltraSPARC-Tx, see sparccpud.S for details... */
178e1051a39Sopenharmony_ci        if (_sparcv9_vis1_instrument() >= 12)
179e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[0] &= ~(SPARCV9_VIS1 | SPARCV9_PREFER_FPU);
180e1051a39Sopenharmony_ci        else {
181e1051a39Sopenharmony_ci            _sparcv9_vis2_probe();
182e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS2;
183e1051a39Sopenharmony_ci        }
184e1051a39Sopenharmony_ci    }
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    if (sigsetjmp(common_jmp, 1) == 0) {
187e1051a39Sopenharmony_ci        _sparcv9_fmadd_probe();
188e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] |= SPARCV9_FMADD;
189e1051a39Sopenharmony_ci    }
190e1051a39Sopenharmony_ci
191e1051a39Sopenharmony_ci    /*
192e1051a39Sopenharmony_ci     * VIS3 flag is tested independently from VIS1, unlike VIS2 that is,
193e1051a39Sopenharmony_ci     * because VIS3 defines even integer instructions.
194e1051a39Sopenharmony_ci     */
195e1051a39Sopenharmony_ci    if (sigsetjmp(common_jmp, 1) == 0) {
196e1051a39Sopenharmony_ci        _sparcv9_vis3_probe();
197e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] |= SPARCV9_VIS3;
198e1051a39Sopenharmony_ci    }
199e1051a39Sopenharmony_ci
200e1051a39Sopenharmony_ci    if (sigsetjmp(common_jmp, 1) == 0) {
201e1051a39Sopenharmony_ci        _sparcv9_fjaesx_probe();
202e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] |= SPARCV9_FJAESX;
203e1051a39Sopenharmony_ci    }
204e1051a39Sopenharmony_ci
205e1051a39Sopenharmony_ci    /*
206e1051a39Sopenharmony_ci     * In wait for better solution _sparcv9_rdcfr is masked by
207e1051a39Sopenharmony_ci     * VIS3 flag, because it goes to uninterruptible endless
208e1051a39Sopenharmony_ci     * loop on UltraSPARC II running Solaris. Things might be
209e1051a39Sopenharmony_ci     * different on Linux...
210e1051a39Sopenharmony_ci     */
211e1051a39Sopenharmony_ci    if ((OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) &&
212e1051a39Sopenharmony_ci        sigsetjmp(common_jmp, 1) == 0) {
213e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[1] = (unsigned int)_sparcv9_rdcfr();
214e1051a39Sopenharmony_ci    }
215e1051a39Sopenharmony_ci
216e1051a39Sopenharmony_ci    sigaction(SIGBUS, &bus_oact, NULL);
217e1051a39Sopenharmony_ci    sigaction(SIGILL, &ill_oact, NULL);
218e1051a39Sopenharmony_ci
219e1051a39Sopenharmony_ci    sigprocmask(SIG_SETMASK, &oset, NULL);
220e1051a39Sopenharmony_ci
221e1051a39Sopenharmony_ci    if (sizeof(size_t) == 8)
222e1051a39Sopenharmony_ci        OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
223e1051a39Sopenharmony_ci# ifdef __linux
224e1051a39Sopenharmony_ci    else {
225e1051a39Sopenharmony_ci        int ret = syscall(340);
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_ci        if (ret >= 0 && ret & 1)
228e1051a39Sopenharmony_ci            OPENSSL_sparcv9cap_P[0] |= SPARCV9_64BIT_STACK;
229e1051a39Sopenharmony_ci    }
230e1051a39Sopenharmony_ci# endif
231e1051a39Sopenharmony_ci}
232