hardware 0.0.7

A no_std bare-metal hardware abstraction layer — all port I/O, memory and swap allocations are guarded at runtime. Do not consider this dependency stable before x.1.x
Documentation
use crate::arch::Architecture;
use core::sync::atomic::{AtomicUsize, Ordering};

static CPUID_MMIO: AtomicUsize = AtomicUsize::new(0);

pub fn set_cpuid_mmio(addr: usize) {
    CPUID_MMIO.store(addr, Ordering::Release);
}

pub fn cpuid_count(leaf: u32, subleaf: u32) -> (u32, u32, u32, u32) {
    let base = CPUID_MMIO.load(Ordering::Acquire);
    if base != 0 {
        unsafe {
            core::ptr::write_volatile(base as *mut u32, leaf);
            core::ptr::write_volatile((base + 4) as *mut u32, subleaf);
            (
                core::ptr::read_volatile((base + 8) as *const u32),
                core::ptr::read_volatile((base + 12) as *const u32),
                core::ptr::read_volatile((base + 16) as *const u32),
                core::ptr::read_volatile((base + 20) as *const u32),
            )
        }
    } else {
        native_cpuid(leaf, subleaf)
    }
}

#[used]
#[link_section = ".text"]
static X86_64_CPUID_BLOB: [u8; 27] = [
    0x53, 0x89, 0xF8, 0x89, 0xF1, 0x49, 0x89, 0xD0, 0x0F, 0xA2, 0x41, 0x89, 0x00, 0x41, 0x89, 0x58,
    0x04, 0x41, 0x89, 0x48, 0x08, 0x41, 0x89, 0x50, 0x0C, 0x5B, 0xC3,
];

fn native_cpuid(leaf: u32, subleaf: u32) -> (u32, u32, u32, u32) {
    match crate::arch::shim::arch_cached() {
        Some(Architecture::X86_64) => {
            let mut out = [0u32; 4];
            unsafe {
                type CpuidBlobFn = unsafe extern "C" fn(u32, u32, *mut u32);
                let f: CpuidBlobFn = core::mem::transmute(X86_64_CPUID_BLOB.as_ptr());
                f(leaf, subleaf, out.as_mut_ptr());
            }
            (out[0], out[1], out[2], out[3])
        }
        _ => (0, 0, 0, 0),
    }
}