use vck_common::cpu::has_aes_ni;
use crate::vck_log;
const CR0_MP: u64 = 1 << 1;
const CR0_EM: u64 = 1 << 2;
const CR4_OSFXSR: u64 = 1 << 9;
const CR4_OSXMMEXCPT: u64 = 1 << 10;
#[inline]
fn read_cr0() -> u64 {
let v: u64;
unsafe {
core::arch::asm!("mov {}, cr0", out(reg) v, options(nomem, nostack, preserves_flags));
}
v
}
#[inline]
fn read_cr4() -> u64 {
let v: u64;
unsafe {
core::arch::asm!("mov {}, cr4", out(reg) v, options(nomem, nostack, preserves_flags));
}
v
}
#[inline]
fn write_cr0(v: u64) {
unsafe {
core::arch::asm!("mov cr0, {}", in(reg) v, options(nostack, preserves_flags));
}
}
#[inline]
fn write_cr4(v: u64) {
unsafe {
core::arch::asm!("mov cr4, {}", in(reg) v, options(nostack, preserves_flags));
}
}
#[inline]
fn bit(v: u64, b: u64) -> u32 {
((v & b) != 0) as u32
}
pub fn report_and_enable_xmm() {
let aes = has_aes_ni();
vck_log!(
"cpu: AES-NI {}",
if aes { "supported" } else { "not supported" }
);
let cr0 = read_cr0();
let cr4 = read_cr4();
vck_log!(
"cpu: current CR0.MP[1]={} CR0.EM[2]={} CR4.OSFXSR[9]={} CR4.OSXMMEXCPT[10]={}",
bit(cr0, CR0_MP),
bit(cr0, CR0_EM),
bit(cr4, CR4_OSFXSR),
bit(cr4, CR4_OSXMMEXCPT),
);
if !aes {
return;
}
let new_cr0 = (cr0 | CR0_MP) & !CR0_EM;
let new_cr4 = cr4 | CR4_OSFXSR | CR4_OSXMMEXCPT;
if new_cr0 != cr0 {
write_cr0(new_cr0);
}
if new_cr4 != cr4 {
write_cr4(new_cr4);
}
vck_log!(
"cpu: enabled XMM CR0 {:#x}->{:#x} CR4 {:#x}->{:#x} (MP=1 EM=0 OSFXSR=1 OSXMMEXCPT=1)",
cr0,
new_cr0,
cr4,
new_cr4,
);
}