#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
#[cfg(target_arch = "x86")]
use core::arch::x86::{__cpuid, __cpuid_count};
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::{__cpuid, __cpuid_count};
#[no_mangle]
pub static mut OPENSSL_ia32cap_P: [u32; 5] = [0; 5];
pub static INITIALIZED: AtomicBool = AtomicBool::new(false);
#[inline(always)]
#[cfg(target_arch = "x86_64")]
unsafe fn xgetbv(index: u32) -> u64 {
let eax: u32;
let edx: u32;
core::arch::asm!(
"xgetbv",
in("ecx") index,
out("eax") eax,
out("edx") edx,
options(nomem, nostack, preserves_flags)
);
((edx as u64) << 32) | (eax as u64)
}
#[inline(always)]
#[cfg(target_arch = "x86")]
unsafe fn xgetbv(index: u32) -> u64 {
let eax: u32;
let edx: u32;
core::arch::asm!(
".byte 0x0f, 0x01, 0xd0", in("ecx") index,
out("eax") eax,
out("edx") edx,
options(nomem, nostack, preserves_flags)
);
((edx as u64) << 32) | (eax as u64)
}
pub fn init() {
if INITIALIZED.swap(true, Ordering::Relaxed) {
return;
}
unsafe {
let c1 = __cpuid(1);
let c7 = __cpuid_count(7, 0);
let eax1 = c1.eax;
let ebx1 = c1.ebx;
let mut ecx1 = c1.ecx;
let edx1 = c1.edx;
let mut ebx7 = c7.ebx;
let ecx7 = c7.ecx;
let edx7 = c7.edx;
let has_osxsave = (ecx1 & (1 << 27)) != 0;
let has_avx = (ecx1 & (1 << 28)) != 0;
if has_osxsave && has_avx {
let xcr0 = xgetbv(0);
let xmm_enabled = (xcr0 & 0x2) != 0;
let ymm_enabled = (xcr0 & 0x4) != 0;
if !(xmm_enabled && ymm_enabled) {
ecx1 &= !(1 << 28); ebx7 &= !(1 << 5); }
} else {
ecx1 &= !(1 << 28);
ebx7 &= !(1 << 5);
}
let avx512_enabled = if has_osxsave {
let xcr0 = xgetbv(0);
(xcr0 & 0xe0) == 0xe0 } else {
false
};
if !avx512_enabled {
ebx7 &= !(1 << 16); ebx7 &= !(1 << 17); ebx7 &= !(1 << 21); ebx7 &= !(1 << 26); ebx7 &= !(1 << 27); ebx7 &= !(1 << 28); ebx7 &= !(1 << 30); ebx7 &= !(1 << 31); }
OPENSSL_ia32cap_P[0] = edx1;
OPENSSL_ia32cap_P[1] = ecx1;
OPENSSL_ia32cap_P[2] = ebx7;
OPENSSL_ia32cap_P[3] = ecx7;
OPENSSL_ia32cap_P[4] = edx7;
OPENSSL_ia32cap_P[0] |= 1 << 10;
}
INITIALIZED.store(true, Ordering::Release);
}