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 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 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 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_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) -> ! {
    init_shims();
    unsafe {
        super::syscall::raw_syscall(super::syscall::nr_exit(), code as u64, 0, 0, 0, 0, 0);
    }
    loop {
        core::hint::spin_loop();
    }
}

pub fn mkdir(path: &[u8], mode: u32) -> i64 {
    if let Some(f) = MKDIR_FN.get() {
        return f(path, mode);
    }
    let nr = super::syscall::nr_mkdirat();
    if nr == crate::common::error::ERR_NOT_IMPLEMENTED {
        return crate::common::error::ERR_NOT_IMPLEMENTED;
    }
    unsafe {
        super::syscall::raw_syscall(
            nr,
            super::os::os_at_fdcwd() as u64,
            path.as_ptr() as u64,
            mode as u64,
            0,
            0,
            0,
        )
    }
}

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
}