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::common::once::OnceCopy;
use core::sync::atomic::{AtomicU8, Ordering};

type CpuidFn = fn(u32, u32) -> Option<(u32, u32, u32, u32)>;
type ReadMsrFn = fn(u32) -> Option<u64>;
type MmioRead32Fn = fn(usize) -> Option<u32>;
type MmioWrite32Fn = fn(usize, u32) -> bool;
type ReadAarch64MidrFn = fn() -> Option<u64>;
type ExitFn = fn(i32) -> !;
type MkdirFn = fn(&[u8], u32) -> i64;
type ScanDirFn = fn(&[u8], &mut [crate::sys::DirEntry]) -> usize;

static CPUID_FN: OnceCopy<CpuidFn> = OnceCopy::new();
static READ_MSR_FN: OnceCopy<ReadMsrFn> = OnceCopy::new();
static MMIO_READ32_FN: OnceCopy<MmioRead32Fn> = OnceCopy::new();
static MMIO_WRITE32_FN: OnceCopy<MmioWrite32Fn> = OnceCopy::new();
static READ_AARCH64_MIDR_FN: OnceCopy<ReadAarch64MidrFn> = OnceCopy::new();
static EXIT_FN: OnceCopy<ExitFn> = OnceCopy::new();
static MKDIR_FN: OnceCopy<MkdirFn> = OnceCopy::new();
static SCAN_DIR_FN: OnceCopy<ScanDirFn> = OnceCopy::new();

static SHIMS_INIT: AtomicU8 = AtomicU8::new(0);

pub fn init_shims() {
    if SHIMS_INIT
        .compare_exchange(0, 1, Ordering::AcqRel, Ordering::Acquire)
        .is_err()
    {
        return;
    }
    crate::arch::x86_64::init_shim();
    crate::arch::aarch64::init_shim();
    super::syscall::register_native_syscall();
}

fn default_cpuid(l: u32, s: u32) -> Option<(u32, u32, u32, u32)> {
    init_shims();
    if let Some(f) = CPUID_FN.get() {
        return f(l, s);
    }
    None
}

fn default_read_msr(msr: u32) -> Option<u64> {
    init_shims();
    if let Some(f) = READ_MSR_FN.get() {
        return f(msr);
    }
    None
}

fn default_mmio_read32(addr: usize) -> Option<u32> {
    init_shims();
    if let Some(f) = MMIO_READ32_FN.get() {
        return f(addr);
    }
    None
}

fn default_mmio_write32(addr: usize, val: u32) -> bool {
    init_shims();
    if let Some(f) = MMIO_WRITE32_FN.get() {
        return f(addr, val);
    }
    false
}

fn default_read_aarch64_midr() -> Option<u64> {
    init_shims();
    if let Some(f) = READ_AARCH64_MIDR_FN.get() {
        return f();
    }
    None
}

pub fn set_cpuid_fn(f: CpuidFn) {
    CPUID_FN.set(f);
}
pub fn set_read_msr_fn(f: ReadMsrFn) {
    READ_MSR_FN.set(f);
}
pub fn set_mmio_read32_fn(f: MmioRead32Fn) {
    MMIO_READ32_FN.set(f);
}
pub fn set_mmio_write32_fn(f: MmioWrite32Fn) {
    MMIO_WRITE32_FN.set(f);
}
pub fn set_read_aarch64_midr_fn(f: ReadAarch64MidrFn) {
    READ_AARCH64_MIDR_FN.set(f);
}

pub fn set_exit_fn(f: ExitFn) {
    EXIT_FN.set(f);
}
pub fn set_mkdir_fn(f: MkdirFn) {
    MKDIR_FN.set(f);
}
pub fn set_scan_dir_fn(f: ScanDirFn) {
    SCAN_DIR_FN.set(f);
}

pub fn cpuid_count(leaf: u32, subleaf: u32) -> Option<(u32, u32, u32, u32)> {
    if let Some(f) = CPUID_FN.get() {
        return f(leaf, subleaf);
    }
    default_cpuid(leaf, subleaf)
}

pub fn read_msr(msr: u32) -> Option<u64> {
    if let Some(f) = READ_MSR_FN.get() {
        f(msr)
    } else {
        default_read_msr(msr)
    }
}

pub fn mmio_read32(addr: usize) -> Option<u32> {
    if let Some(f) = MMIO_READ32_FN.get() {
        f(addr)
    } else {
        default_mmio_read32(addr)
    }
}

pub fn mmio_write32(addr: usize, val: u32) -> bool {
    if let Some(f) = MMIO_WRITE32_FN.get() {
        f(addr, val)
    } else {
        default_mmio_write32(addr, val)
    }
}

pub fn read_aarch64_midr() -> Option<u64> {
    if let Some(f) = READ_AARCH64_MIDR_FN.get() {
        f()
    } else {
        default_read_aarch64_midr()
    }
}

pub fn arch_exit(code: i32) -> ! {
    if let Some(f) = EXIT_FN.get() {
        f(code);
    }
    init_shims();
    if let Some(f) = EXIT_FN.get() {
        f(code);
    }
    loop {
        core::hint::spin_loop();
    }
}

pub fn mkdir(path: &[u8], mode: u32) -> i64 {
    if let Some(f) = MKDIR_FN.get() {
        return f(path, mode);
    }
    crate::common::error::ERR_NOT_IMPLEMENTED
}

pub fn scan_dir_dispatch(path: &[u8], out: &mut [crate::sys::DirEntry]) -> usize {
    if let Some(f) = SCAN_DIR_FN.get() {
        return f(path, out);
    }
    0
}