Home | History | Annotate | Line # | Download | only in sodium
      1 #include <stddef.h>
      2 #include <stdint.h>
      3 #ifdef HAVE_ANDROID_GETCPUFEATURES
      4 # include <cpu-features.h>
      5 #endif
      6 
      7 #include "private/common.h"
      8 #include "runtime.h"
      9 
     10 typedef struct CPUFeatures_ {
     11     int initialized;
     12     int has_neon;
     13     int has_sse2;
     14     int has_sse3;
     15     int has_ssse3;
     16     int has_sse41;
     17     int has_avx;
     18     int has_avx2;
     19     int has_avx512f;
     20     int has_pclmul;
     21     int has_aesni;
     22     int has_rdrand;
     23 } CPUFeatures;
     24 
     25 static CPUFeatures _cpu_features;
     26 
     27 #define CPUID_EBX_AVX2    0x00000020
     28 #define CPUID_EBX_AVX512F 0x00010000
     29 
     30 #define CPUID_ECX_SSE3    0x00000001
     31 #define CPUID_ECX_PCLMUL  0x00000002
     32 #define CPUID_ECX_SSSE3   0x00000200
     33 #define CPUID_ECX_SSE41   0x00080000
     34 #define CPUID_ECX_AESNI   0x02000000
     35 #define CPUID_ECX_XSAVE   0x04000000
     36 #define CPUID_ECX_OSXSAVE 0x08000000
     37 #define CPUID_ECX_AVX     0x10000000
     38 #define CPUID_ECX_RDRAND  0x40000000
     39 
     40 #define CPUID_EDX_SSE2    0x04000000
     41 
     42 #define XCR0_SSE 0x00000002
     43 #define XCR0_AVX 0x00000004
     44 
     45 static int
     46 _sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features)
     47 {
     48 #ifndef __arm__
     49     cpu_features->has_neon = 0;
     50     return -1;
     51 #else
     52 # ifdef __APPLE__
     53 #  ifdef __ARM_NEON__
     54     cpu_features->has_neon = 1;
     55 #  else
     56     cpu_features->has_neon = 0;
     57 #  endif
     58 # elif defined(HAVE_ANDROID_GETCPUFEATURES) && \
     59     defined(ANDROID_CPU_ARM_FEATURE_NEON)
     60     cpu_features->has_neon =
     61         (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0;
     62 # else
     63     cpu_features->has_neon = 0;
     64 # endif
     65     return 0;
     66 #endif
     67 }
     68 
     69 static void
     70 _cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type)
     71 {
     72 #if defined(_MSC_VER) && \
     73     (defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86))
     74     __cpuid((int *) cpu_info, cpu_info_type);
     75 #elif defined(HAVE_CPUID)
     76     cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
     77 # ifdef __i386__
     78     __asm__ __volatile__(
     79         "pushfl; pushfl; "
     80         "popl %0; "
     81         "movl %0, %1; xorl %2, %0; "
     82         "pushl %0; "
     83         "popfl; pushfl; popl %0; popfl"
     84         : "=&r"(cpu_info[0]), "=&r"(cpu_info[1])
     85         : "i"(0x200000));
     86     if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) {
     87         return; /* LCOV_EXCL_LINE */
     88     }
     89 # endif
     90 # ifdef __i386__
     91     __asm__ __volatile__("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1"
     92                          : "=a"(cpu_info[0]), "=&r"(cpu_info[1]),
     93                            "=c"(cpu_info[2]), "=d"(cpu_info[3])
     94                          : "0"(cpu_info_type), "2"(0U));
     95 # elif defined(__x86_64__)
     96     __asm__ __volatile__("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1"
     97                          : "=a"(cpu_info[0]), "=&r"(cpu_info[1]),
     98                            "=c"(cpu_info[2]), "=d"(cpu_info[3])
     99                          : "0"(cpu_info_type), "2"(0U));
    100 # else
    101     __asm__ __volatile__("cpuid"
    102                          : "=a"(cpu_info[0]), "=b"(cpu_info[1]),
    103                            "=c"(cpu_info[2]), "=d"(cpu_info[3])
    104                          : "0"(cpu_info_type), "2"(0U));
    105 # endif
    106 #else
    107     (void) cpu_info_type;
    108     cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
    109 #endif
    110 }
    111 
    112 static int
    113 _sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features)
    114 {
    115     unsigned int cpu_info[4];
    116     unsigned int id;
    117 
    118     _cpuid(cpu_info, 0x0);
    119     if ((id = cpu_info[0]) == 0U) {
    120         return -1; /* LCOV_EXCL_LINE */
    121     }
    122     _cpuid(cpu_info, 0x00000001);
    123 #ifdef HAVE_EMMINTRIN_H
    124     cpu_features->has_sse2 = ((cpu_info[3] & CPUID_EDX_SSE2) != 0x0);
    125 #else
    126     cpu_features->has_sse2   = 0;
    127 #endif
    128 
    129 #ifdef HAVE_PMMINTRIN_H
    130     cpu_features->has_sse3 = ((cpu_info[2] & CPUID_ECX_SSE3) != 0x0);
    131 #else
    132     cpu_features->has_sse3   = 0;
    133 #endif
    134 
    135 #ifdef HAVE_TMMINTRIN_H
    136     cpu_features->has_ssse3 = ((cpu_info[2] & CPUID_ECX_SSSE3) != 0x0);
    137 #else
    138     cpu_features->has_ssse3  = 0;
    139 #endif
    140 
    141 #ifdef HAVE_SMMINTRIN_H
    142     cpu_features->has_sse41 = ((cpu_info[2] & CPUID_ECX_SSE41) != 0x0);
    143 #else
    144     cpu_features->has_sse41  = 0;
    145 #endif
    146 
    147     cpu_features->has_avx = 0;
    148 #ifdef HAVE_AVXINTRIN_H
    149     if ((cpu_info[2] & (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) ==
    150         (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) {
    151         uint32_t xcr0 = 0U;
    152 # if defined(HAVE__XGETBV) || \
    153         (defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) && _MSC_FULL_VER >= 160040219)
    154         xcr0 = (uint32_t) _xgetbv(0);
    155 # elif defined(_MSC_VER) && defined(_M_IX86)
    156         __asm {
    157             xor ecx, ecx
    158             _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
    159             mov xcr0, eax
    160         }
    161 # elif defined(HAVE_AVX_ASM)
    162         __asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" /* XGETBV */
    163                              : "=a"(xcr0)
    164                              : "c"((uint32_t) 0U)
    165                              : "%edx");
    166 # endif
    167         if ((xcr0 & (XCR0_SSE | XCR0_AVX)) == (XCR0_SSE | XCR0_AVX)) {
    168             cpu_features->has_avx = 1;
    169         }
    170     }
    171 #endif
    172 
    173     cpu_features->has_avx2 = 0;
    174 #ifdef HAVE_AVX2INTRIN_H
    175     if (cpu_features->has_avx) {
    176         unsigned int cpu_info7[4];
    177 
    178         _cpuid(cpu_info7, 0x00000007);
    179         cpu_features->has_avx2 = ((cpu_info7[1] & CPUID_EBX_AVX2) != 0x0);
    180     }
    181 #endif
    182 
    183     cpu_features->has_avx512f = 0;
    184 #ifdef HAVE_AVX512FINTRIN_H
    185     if (cpu_features->has_avx2) {
    186         unsigned int cpu_info7[4];
    187 
    188         _cpuid(cpu_info7, 0x00000007);
    189         cpu_features->has_avx512f = ((cpu_info7[1] & CPUID_EBX_AVX512F) != 0x0);
    190     }
    191 #endif
    192 
    193 #ifdef HAVE_WMMINTRIN_H
    194     cpu_features->has_pclmul = ((cpu_info[2] & CPUID_ECX_PCLMUL) != 0x0);
    195     cpu_features->has_aesni  = ((cpu_info[2] & CPUID_ECX_AESNI) != 0x0);
    196 #else
    197     cpu_features->has_pclmul = 0;
    198     cpu_features->has_aesni  = 0;
    199 #endif
    200 
    201 #ifdef HAVE_RDRAND
    202     cpu_features->has_rdrand = ((cpu_info[2] & CPUID_ECX_RDRAND) != 0x0);
    203 #else
    204     cpu_features->has_rdrand = 0;
    205 #endif
    206 
    207     return 0;
    208 }
    209 
    210 int
    211 _sodium_runtime_get_cpu_features(void)
    212 {
    213     int ret = -1;
    214 
    215     ret &= _sodium_runtime_arm_cpu_features(&_cpu_features);
    216     ret &= _sodium_runtime_intel_cpu_features(&_cpu_features);
    217     _cpu_features.initialized = 1;
    218 
    219     return ret;
    220 }
    221 
    222 int
    223 sodium_runtime_has_neon(void)
    224 {
    225     return _cpu_features.has_neon;
    226 }
    227 
    228 int
    229 sodium_runtime_has_sse2(void)
    230 {
    231     return _cpu_features.has_sse2;
    232 }
    233 
    234 int
    235 sodium_runtime_has_sse3(void)
    236 {
    237     return _cpu_features.has_sse3;
    238 }
    239 
    240 int
    241 sodium_runtime_has_ssse3(void)
    242 {
    243     return _cpu_features.has_ssse3;
    244 }
    245 
    246 int
    247 sodium_runtime_has_sse41(void)
    248 {
    249     return _cpu_features.has_sse41;
    250 }
    251 
    252 int
    253 sodium_runtime_has_avx(void)
    254 {
    255     return _cpu_features.has_avx;
    256 }
    257 
    258 int
    259 sodium_runtime_has_avx2(void)
    260 {
    261     return _cpu_features.has_avx2;
    262 }
    263 
    264 int
    265 sodium_runtime_has_avx512f(void)
    266 {
    267     return _cpu_features.has_avx512f;
    268 }
    269 
    270 int
    271 sodium_runtime_has_pclmul(void)
    272 {
    273     return _cpu_features.has_pclmul;
    274 }
    275 
    276 int
    277 sodium_runtime_has_aesni(void)
    278 {
    279     return _cpu_features.has_aesni;
    280 }
    281 
    282 int
    283 sodium_runtime_has_rdrand(void)
    284 {
    285     return _cpu_features.has_rdrand;
    286 }
    287