xref: /openbsd-src/lib/libcrypto/arch/i386/crypto_cpu_caps.c (revision 72d4bfd9b536f29625818f407df98cdffd1e3082)
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