hardware 0.0.9

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 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)
    }
}

#[repr(C, align(4))]
struct AlignedBlob<const N: usize>([u8; N]);

#[used]
#[link_section = ".text"]
static X86_64_CPUID_BLOB: AlignedBlob<27> = AlignedBlob([
    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) {
    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.0.as_ptr());
        f(leaf, subleaf, out.as_mut_ptr());
    }
    (out[0], out[1], out[2], out[3])
}