xref: /openbsd-src/lib/libcrypto/arch/amd64/crypto_cpu_caps.c (revision e045734c6461b648f36a4cbeed4bd7082a607e47)
1*e045734cSjsing /*	$OpenBSD: crypto_cpu_caps.c,v 1.4 2024/11/16 13:05:35 jsing Exp $ */
29b1106c6Sjsing /*
39b1106c6Sjsing  * Copyright (c) 2024 Joel Sing <jsing@openbsd.org>
49b1106c6Sjsing  *
59b1106c6Sjsing  * Permission to use, copy, modify, and distribute this software for any
69b1106c6Sjsing  * purpose with or without fee is hereby granted, provided that the above
79b1106c6Sjsing  * copyright notice and this permission notice appear in all copies.
89b1106c6Sjsing  *
99b1106c6Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109b1106c6Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119b1106c6Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129b1106c6Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139b1106c6Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149b1106c6Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159b1106c6Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169b1106c6Sjsing  */
179b1106c6Sjsing 
189b1106c6Sjsing #include <stdio.h>
199b1106c6Sjsing 
209b1106c6Sjsing #include <openssl/crypto.h>
219b1106c6Sjsing 
22*e045734cSjsing #include "crypto_arch.h"
239b1106c6Sjsing #include "x86_arch.h"
249b1106c6Sjsing 
259b1106c6Sjsing /* Legacy architecture specific capabilities, used by perlasm. */
2629a830a1Sjsing uint64_t OPENSSL_ia32cap_P;
279b1106c6Sjsing 
28*e045734cSjsing /* Machine dependent CPU capabilities. */
29*e045734cSjsing uint64_t crypto_cpu_caps_amd64;
30*e045734cSjsing 
319b1106c6Sjsing /* Machine independent CPU capabilities. */
329b1106c6Sjsing extern uint64_t crypto_cpu_caps;
339b1106c6Sjsing 
349b1106c6Sjsing static inline void
359b1106c6Sjsing cpuid(uint32_t eax, uint32_t *out_eax, uint32_t *out_ebx, uint32_t *out_ecx,
369b1106c6Sjsing     uint32_t *out_edx)
379b1106c6Sjsing {
389b1106c6Sjsing 	uint32_t ebx = 0, ecx = 0, edx = 0;
399b1106c6Sjsing 
409b1106c6Sjsing #ifndef OPENSSL_NO_ASM
419b1106c6Sjsing 	__asm__ ("cpuid": "+a"(eax), "+b"(ebx), "+c"(ecx), "+d"(edx));
429b1106c6Sjsing #else
439b1106c6Sjsing 	eax = 0;
449b1106c6Sjsing #endif
459b1106c6Sjsing 
469b1106c6Sjsing 	if (out_eax != NULL)
479b1106c6Sjsing 		*out_eax = eax;
489b1106c6Sjsing 	if (out_ebx != NULL)
499b1106c6Sjsing 		*out_ebx = ebx;
5072d4bfd9Sjsing 	if (out_ecx != NULL)
519b1106c6Sjsing 		*out_ecx = ecx;
529b1106c6Sjsing 	if (out_edx != NULL)
539b1106c6Sjsing 		*out_edx = edx;
549b1106c6Sjsing }
559b1106c6Sjsing 
569b1106c6Sjsing static inline void
579b1106c6Sjsing xgetbv(uint32_t ecx, uint32_t *out_eax, uint32_t *out_edx)
589b1106c6Sjsing {
599b1106c6Sjsing 	uint32_t eax = 0, edx = 0;
609b1106c6Sjsing 
619b1106c6Sjsing #ifndef OPENSSL_NO_ASM
629b1106c6Sjsing 	__asm__ ("xgetbv": "+a"(eax), "+c"(ecx), "+d"(edx));
639b1106c6Sjsing #endif
649b1106c6Sjsing 
659b1106c6Sjsing 	if (out_eax != NULL)
669b1106c6Sjsing 		*out_eax = eax;
679b1106c6Sjsing 	if (out_edx != NULL)
689b1106c6Sjsing 		*out_edx = edx;
699b1106c6Sjsing }
709b1106c6Sjsing 
719b1106c6Sjsing void
729b1106c6Sjsing crypto_cpu_caps_init(void)
739b1106c6Sjsing {
74*e045734cSjsing 	uint32_t eax, ebx, ecx, edx, max_cpuid;
759b1106c6Sjsing 	uint64_t caps = 0;
769b1106c6Sjsing 
779b1106c6Sjsing 	cpuid(0, &eax, &ebx, &ecx, &edx);
789b1106c6Sjsing 
79*e045734cSjsing 	max_cpuid = eax;
80*e045734cSjsing 
819b1106c6Sjsing 	/* "GenuineIntel" in little endian. */
829b1106c6Sjsing 	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
839b1106c6Sjsing 		caps |= CPUCAP_MASK_INTEL;
849b1106c6Sjsing 
85*e045734cSjsing 	if (max_cpuid < 1)
869b1106c6Sjsing 		return;
879b1106c6Sjsing 
88*e045734cSjsing 	cpuid(1, &eax, NULL, &ecx, &edx);
899b1106c6Sjsing 
909b1106c6Sjsing 	if ((edx & IA32CAP_MASK0_FXSR) != 0)
919b1106c6Sjsing 		caps |= CPUCAP_MASK_FXSR;
929b1106c6Sjsing 	if ((edx & IA32CAP_MASK0_HT) != 0)
939b1106c6Sjsing 		caps |= CPUCAP_MASK_HT;
949b1106c6Sjsing 	if ((edx & IA32CAP_MASK0_MMX) != 0)
959b1106c6Sjsing 		caps |= CPUCAP_MASK_MMX;
969b1106c6Sjsing 	if ((edx & IA32CAP_MASK0_SSE) != 0)
979b1106c6Sjsing 		caps |= CPUCAP_MASK_SSE;
989b1106c6Sjsing 	if ((edx & IA32CAP_MASK0_SSE2) != 0)
999b1106c6Sjsing 		caps |= CPUCAP_MASK_SSE2;
1009b1106c6Sjsing 
1019b1106c6Sjsing 	if ((ecx & IA32CAP_MASK1_AESNI) != 0)
1029b1106c6Sjsing 		caps |= CPUCAP_MASK_AESNI;
1039b1106c6Sjsing 	if ((ecx & IA32CAP_MASK1_PCLMUL) != 0)
1049b1106c6Sjsing 		caps |= CPUCAP_MASK_PCLMUL;
1059b1106c6Sjsing 	if ((ecx & IA32CAP_MASK1_SSSE3) != 0)
1069b1106c6Sjsing 		caps |= CPUCAP_MASK_SSSE3;
1079b1106c6Sjsing 
1089b1106c6Sjsing 	/* AVX requires OSXSAVE and XMM/YMM state to be enabled. */
1099b1106c6Sjsing 	if ((ecx & IA32CAP_MASK1_OSXSAVE) != 0) {
1109b1106c6Sjsing 		xgetbv(0, &eax, NULL);
1119b1106c6Sjsing 		if (((eax >> 1) & 3) == 3 && (ecx & IA32CAP_MASK1_AVX) != 0)
1129b1106c6Sjsing 			caps |= CPUCAP_MASK_AVX;
1139b1106c6Sjsing 	}
1149b1106c6Sjsing 
115*e045734cSjsing 	if (max_cpuid >= 7) {
116*e045734cSjsing 		cpuid(7, NULL, &ebx, NULL, NULL);
117*e045734cSjsing 
118*e045734cSjsing 		/* Intel SHA extensions feature bit - ebx[29]. */
119*e045734cSjsing 		if (((ebx >> 29) & 1) != 0)
120*e045734cSjsing 			crypto_cpu_caps_amd64 |= CRYPTO_CPU_CAPS_AMD64_SHA;
121*e045734cSjsing 	}
122*e045734cSjsing 
1239b1106c6Sjsing 	/* Set machine independent CPU capabilities. */
1249b1106c6Sjsing 	if ((caps & CPUCAP_MASK_AESNI) != 0)
1259b1106c6Sjsing 		crypto_cpu_caps |= CRYPTO_CPU_CAPS_ACCELERATED_AES;
1269b1106c6Sjsing 
1279b1106c6Sjsing 	OPENSSL_ia32cap_P = caps;
1289b1106c6Sjsing }
12929a830a1Sjsing 
13029a830a1Sjsing uint64_t
13129a830a1Sjsing crypto_cpu_caps_ia32(void)
13229a830a1Sjsing {
13329a830a1Sjsing 	return OPENSSL_ia32cap_P;
13429a830a1Sjsing }
135