1 /* $OpenBSD: crypto_cpu_caps.c,v 1.3 2024/11/12 13:14:57 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 "x86_arch.h" 23 24 /* Legacy architecture specific capabilities, used by perlasm. */ 25 uint64_t OPENSSL_ia32cap_P; 26 27 /* Machine independent CPU capabilities. */ 28 extern uint64_t crypto_cpu_caps; 29 30 static inline void 31 cpuid(uint32_t eax, uint32_t *out_eax, uint32_t *out_ebx, uint32_t *out_ecx, 32 uint32_t *out_edx) 33 { 34 uint32_t ebx = 0, ecx = 0, edx = 0; 35 36 #ifndef OPENSSL_NO_ASM 37 __asm__ ("cpuid": "+a"(eax), "+b"(ebx), "+c"(ecx), "+d"(edx)); 38 #else 39 eax = 0; 40 #endif 41 42 if (out_eax != NULL) 43 *out_eax = eax; 44 if (out_ebx != NULL) 45 *out_ebx = ebx; 46 if (out_ecx != NULL) 47 *out_ecx = ecx; 48 if (out_edx != NULL) 49 *out_edx = edx; 50 } 51 52 static inline void 53 xgetbv(uint32_t ecx, uint32_t *out_eax, uint32_t *out_edx) 54 { 55 uint32_t eax = 0, edx = 0; 56 57 #ifndef OPENSSL_NO_ASM 58 __asm__ ("xgetbv": "+a"(eax), "+c"(ecx), "+d"(edx)); 59 #endif 60 61 if (out_eax != NULL) 62 *out_eax = eax; 63 if (out_edx != NULL) 64 *out_edx = edx; 65 } 66 67 void 68 crypto_cpu_caps_init(void) 69 { 70 uint32_t eax, ebx, ecx, edx; 71 uint64_t caps = 0; 72 73 cpuid(0, &eax, &ebx, &ecx, &edx); 74 75 /* "GenuineIntel" in little endian. */ 76 if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) 77 caps |= CPUCAP_MASK_INTEL; 78 79 if (eax < 1) 80 return; 81 82 cpuid(1, &eax, &ebx, &ecx, &edx); 83 84 if ((edx & IA32CAP_MASK0_FXSR) != 0) 85 caps |= CPUCAP_MASK_FXSR; 86 if ((edx & IA32CAP_MASK0_HT) != 0) 87 caps |= CPUCAP_MASK_HT; 88 if ((edx & IA32CAP_MASK0_MMX) != 0) 89 caps |= CPUCAP_MASK_MMX; 90 if ((edx & IA32CAP_MASK0_SSE) != 0) 91 caps |= CPUCAP_MASK_SSE; 92 if ((edx & IA32CAP_MASK0_SSE2) != 0) 93 caps |= CPUCAP_MASK_SSE2; 94 95 if ((ecx & IA32CAP_MASK1_AESNI) != 0) 96 caps |= CPUCAP_MASK_AESNI; 97 if ((ecx & IA32CAP_MASK1_PCLMUL) != 0) 98 caps |= CPUCAP_MASK_PCLMUL; 99 if ((ecx & IA32CAP_MASK1_SSSE3) != 0) 100 caps |= CPUCAP_MASK_SSSE3; 101 102 /* AVX requires OSXSAVE and XMM/YMM state to be enabled. */ 103 if ((ecx & IA32CAP_MASK1_OSXSAVE) != 0) { 104 xgetbv(0, &eax, NULL); 105 if (((eax >> 1) & 3) == 3 && (ecx & IA32CAP_MASK1_AVX) != 0) 106 caps |= CPUCAP_MASK_AVX; 107 } 108 109 /* Set machine independent CPU capabilities. */ 110 if ((caps & CPUCAP_MASK_AESNI) != 0) 111 crypto_cpu_caps |= CRYPTO_CPU_CAPS_ACCELERATED_AES; 112 113 OPENSSL_ia32cap_P = caps; 114 } 115 116 uint64_t 117 crypto_cpu_caps_ia32(void) 118 { 119 return OPENSSL_ia32cap_P; 120 } 121