1 /* $OpenBSD: crypto_cpu_caps.c,v 1.4 2024/11/16 13:05:35 jsing Exp $ */ 2 /* 3 * Copyright (c) 2024 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <stdio.h> 19 20 #include <openssl/crypto.h> 21 22 #include "crypto_arch.h" 23 #include "x86_arch.h" 24 25 /* Legacy architecture specific capabilities, used by perlasm. */ 26 uint64_t OPENSSL_ia32cap_P; 27 28 /* Machine dependent CPU capabilities. */ 29 uint64_t crypto_cpu_caps_amd64; 30 31 /* Machine independent CPU capabilities. */ 32 extern uint64_t crypto_cpu_caps; 33 34 static inline void 35 cpuid(uint32_t eax, uint32_t *out_eax, uint32_t *out_ebx, uint32_t *out_ecx, 36 uint32_t *out_edx) 37 { 38 uint32_t ebx = 0, ecx = 0, edx = 0; 39 40 #ifndef OPENSSL_NO_ASM 41 __asm__ ("cpuid": "+a"(eax), "+b"(ebx), "+c"(ecx), "+d"(edx)); 42 #else 43 eax = 0; 44 #endif 45 46 if (out_eax != NULL) 47 *out_eax = eax; 48 if (out_ebx != NULL) 49 *out_ebx = ebx; 50 if (out_ecx != NULL) 51 *out_ecx = ecx; 52 if (out_edx != NULL) 53 *out_edx = edx; 54 } 55 56 static inline void 57 xgetbv(uint32_t ecx, uint32_t *out_eax, uint32_t *out_edx) 58 { 59 uint32_t eax = 0, edx = 0; 60 61 #ifndef OPENSSL_NO_ASM 62 __asm__ ("xgetbv": "+a"(eax), "+c"(ecx), "+d"(edx)); 63 #endif 64 65 if (out_eax != NULL) 66 *out_eax = eax; 67 if (out_edx != NULL) 68 *out_edx = edx; 69 } 70 71 void 72 crypto_cpu_caps_init(void) 73 { 74 uint32_t eax, ebx, ecx, edx, max_cpuid; 75 uint64_t caps = 0; 76 77 cpuid(0, &eax, &ebx, &ecx, &edx); 78 79 max_cpuid = eax; 80 81 /* "GenuineIntel" in little endian. */ 82 if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) 83 caps |= CPUCAP_MASK_INTEL; 84 85 if (max_cpuid < 1) 86 return; 87 88 cpuid(1, &eax, NULL, &ecx, &edx); 89 90 if ((edx & IA32CAP_MASK0_FXSR) != 0) 91 caps |= CPUCAP_MASK_FXSR; 92 if ((edx & IA32CAP_MASK0_HT) != 0) 93 caps |= CPUCAP_MASK_HT; 94 if ((edx & IA32CAP_MASK0_MMX) != 0) 95 caps |= CPUCAP_MASK_MMX; 96 if ((edx & IA32CAP_MASK0_SSE) != 0) 97 caps |= CPUCAP_MASK_SSE; 98 if ((edx & IA32CAP_MASK0_SSE2) != 0) 99 caps |= CPUCAP_MASK_SSE2; 100 101 if ((ecx & IA32CAP_MASK1_AESNI) != 0) 102 caps |= CPUCAP_MASK_AESNI; 103 if ((ecx & IA32CAP_MASK1_PCLMUL) != 0) 104 caps |= CPUCAP_MASK_PCLMUL; 105 if ((ecx & IA32CAP_MASK1_SSSE3) != 0) 106 caps |= CPUCAP_MASK_SSSE3; 107 108 /* AVX requires OSXSAVE and XMM/YMM state to be enabled. */ 109 if ((ecx & IA32CAP_MASK1_OSXSAVE) != 0) { 110 xgetbv(0, &eax, NULL); 111 if (((eax >> 1) & 3) == 3 && (ecx & IA32CAP_MASK1_AVX) != 0) 112 caps |= CPUCAP_MASK_AVX; 113 } 114 115 if (max_cpuid >= 7) { 116 cpuid(7, NULL, &ebx, NULL, NULL); 117 118 /* Intel SHA extensions feature bit - ebx[29]. */ 119 if (((ebx >> 29) & 1) != 0) 120 crypto_cpu_caps_amd64 |= CRYPTO_CPU_CAPS_AMD64_SHA; 121 } 122 123 /* Set machine independent CPU capabilities. */ 124 if ((caps & CPUCAP_MASK_AESNI) != 0) 125 crypto_cpu_caps |= CRYPTO_CPU_CAPS_ACCELERATED_AES; 126 127 OPENSSL_ia32cap_P = caps; 128 } 129 130 uint64_t 131 crypto_cpu_caps_ia32(void) 132 { 133 return OPENSSL_ia32cap_P; 134 } 135