5f40dd158c
Having a weak getauxval() and only depending on GNU C without looking at the library we build against meant that it got picked up where not really expected. So we change this to check for the glibc version, and since we know it exists from that version, there's no real need to make it weak. Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de> (Merged from https://github.com/openssl/openssl/pull/8028)
214 lines
5.5 KiB
C
214 lines
5.5 KiB
C
/*
|
|
* Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <openssl/crypto.h>
|
|
#include "internal/cryptlib.h"
|
|
|
|
#include "arm_arch.h"
|
|
|
|
unsigned int OPENSSL_armcap_P = 0;
|
|
|
|
#if __ARM_MAX_ARCH__<7
|
|
void OPENSSL_cpuid_setup(void)
|
|
{
|
|
}
|
|
|
|
uint32_t OPENSSL_rdtsc(void)
|
|
{
|
|
return 0;
|
|
}
|
|
#else
|
|
static sigset_t all_masked;
|
|
|
|
static sigjmp_buf ill_jmp;
|
|
static void ill_handler(int sig)
|
|
{
|
|
siglongjmp(ill_jmp, sig);
|
|
}
|
|
|
|
/*
|
|
* Following subroutines could have been inlined, but it's not all
|
|
* ARM compilers support inline assembler...
|
|
*/
|
|
void _armv7_neon_probe(void);
|
|
void _armv8_aes_probe(void);
|
|
void _armv8_sha1_probe(void);
|
|
void _armv8_sha256_probe(void);
|
|
void _armv8_pmull_probe(void);
|
|
# ifdef __aarch64__
|
|
void _armv8_sha512_probe(void);
|
|
# endif
|
|
uint32_t _armv7_tick(void);
|
|
|
|
uint32_t OPENSSL_rdtsc(void)
|
|
{
|
|
if (OPENSSL_armcap_P & ARMV7_TICK)
|
|
return _armv7_tick();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
# if defined(__GNUC__) && __GNUC__>=2
|
|
void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
|
|
# endif
|
|
|
|
# if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
|
|
# if __GLIBC_PREREQ(2, 16)
|
|
# include <sys/auxv.h>
|
|
# define OSSL_IMPLEMENT_GETAUXVAL
|
|
# endif
|
|
# endif
|
|
|
|
/*
|
|
* ARM puts 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)
|
|
# define HWCAP_CE_SHA512 (1 << 21)
|
|
# endif
|
|
|
|
void OPENSSL_cpuid_setup(void)
|
|
{
|
|
const char *e;
|
|
struct sigaction ill_oact, ill_act;
|
|
sigset_t oset;
|
|
static int trigger = 0;
|
|
|
|
if (trigger)
|
|
return;
|
|
trigger = 1;
|
|
|
|
if ((e = getenv("OPENSSL_armcap"))) {
|
|
OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0);
|
|
return;
|
|
}
|
|
|
|
# if defined(__APPLE__) && !defined(__aarch64__)
|
|
/*
|
|
* Capability probing by catching SIGILL appears to be problematic
|
|
* on iOS. But since Apple universe is "monocultural", it's actually
|
|
* possible to simply set pre-defined processor capability mask.
|
|
*/
|
|
if (1) {
|
|
OPENSSL_armcap_P = ARMV7_NEON;
|
|
return;
|
|
}
|
|
/*
|
|
* One could do same even for __aarch64__ iOS builds. It's not done
|
|
* exclusively for reasons of keeping code unified across platforms.
|
|
* Unified code works because it never triggers SIGILL on Apple
|
|
* devices...
|
|
*/
|
|
# endif
|
|
|
|
OPENSSL_armcap_P = 0;
|
|
|
|
# ifdef OSSL_IMPLEMENT_GETAUXVAL
|
|
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;
|
|
|
|
# ifdef __aarch64__
|
|
if (hwcap & HWCAP_CE_SHA512)
|
|
OPENSSL_armcap_P |= ARMV8_SHA512;
|
|
# endif
|
|
}
|
|
# endif
|
|
|
|
sigfillset(&all_masked);
|
|
sigdelset(&all_masked, SIGILL);
|
|
sigdelset(&all_masked, SIGTRAP);
|
|
sigdelset(&all_masked, SIGFPE);
|
|
sigdelset(&all_masked, SIGBUS);
|
|
sigdelset(&all_masked, SIGSEGV);
|
|
|
|
memset(&ill_act, 0, sizeof(ill_act));
|
|
ill_act.sa_handler = ill_handler;
|
|
ill_act.sa_mask = all_masked;
|
|
|
|
sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
|
|
sigaction(SIGILL, &ill_act, &ill_oact);
|
|
|
|
/* If we used getauxval, we already have all the values */
|
|
# ifndef OSSL_IMPLEMENT_GETAUXVAL
|
|
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;
|
|
}
|
|
if (sigsetjmp(ill_jmp, 1) == 0) {
|
|
_armv8_sha1_probe();
|
|
OPENSSL_armcap_P |= ARMV8_SHA1;
|
|
}
|
|
if (sigsetjmp(ill_jmp, 1) == 0) {
|
|
_armv8_sha256_probe();
|
|
OPENSSL_armcap_P |= ARMV8_SHA256;
|
|
}
|
|
# if defined(__aarch64__) && !defined(__APPLE__)
|
|
if (sigsetjmp(ill_jmp, 1) == 0) {
|
|
_armv8_sha512_probe();
|
|
OPENSSL_armcap_P |= ARMV8_SHA512;
|
|
}
|
|
# endif
|
|
}
|
|
# endif
|
|
|
|
/* Things that getauxval didn't tell us */
|
|
if (sigsetjmp(ill_jmp, 1) == 0) {
|
|
_armv7_tick();
|
|
OPENSSL_armcap_P |= ARMV7_TICK;
|
|
}
|
|
|
|
sigaction(SIGILL, &ill_oact, NULL);
|
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
|
}
|
|
#endif
|