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
pub fn read_reg(base: usize, offset: usize) -> u32 {
    let ptr = (base + offset) as *const u32;
    unsafe { core::ptr::read_volatile(ptr) }
}

pub fn write_reg(base: usize, offset: usize, val: u32) {
    let ptr = (base + offset) as *mut u32;
    unsafe { core::ptr::write_volatile(ptr, val) }
}

pub fn read_reg64(base: usize, offset: usize) -> u64 {
    let lo = read_reg(base, offset) as u64;
    let hi = read_reg(base, offset + 4) as u64;
    (hi << 32) | lo
}

pub fn write_reg64(base: usize, offset: usize, val: u64) {
    write_reg(base, offset, val as u32);
    write_reg(base, offset + 4, (val >> 32) as u32);
}

pub const AHCI_CAP: usize = 0x00;
pub const AHCI_GHC: usize = 0x04;
pub const AHCI_IS: usize = 0x08;
pub const AHCI_PI: usize = 0x0C;
pub const AHCI_VS: usize = 0x10;
pub const AHCI_PORT_BASE: usize = 0x100;
pub const AHCI_PORT_SIZE: usize = 0x80;

pub const NVME_CAP: usize = 0x00;
pub const NVME_VS: usize = 0x08;
pub const NVME_CC: usize = 0x14;
pub const NVME_CSTS: usize = 0x1C;
pub const NVME_AQA: usize = 0x24;
pub const NVME_ASQ: usize = 0x28;
pub const NVME_ACQ: usize = 0x30;

pub fn ahci_port_count(base: usize) -> u8 {
    let cap = read_reg(base, AHCI_CAP);
    ((cap & 0x1F) + 1) as u8
}

pub fn ahci_ports_implemented(base: usize) -> u32 {
    read_reg(base, AHCI_PI)
}

pub fn ahci_enable(base: usize) {
    let ghc = read_reg(base, AHCI_GHC);
    write_reg(base, AHCI_GHC, ghc | (1 << 31));
}

pub fn ahci_port_offset(port: u8) -> usize {
    AHCI_PORT_BASE + (port as usize) * AHCI_PORT_SIZE
}

pub fn nvme_version(base: usize) -> (u16, u8, u8) {
    let vs = read_reg(base, NVME_VS);
    let major = ((vs >> 16) & 0xFFFF) as u16;
    let minor = ((vs >> 8) & 0xFF) as u8;
    let ter = (vs & 0xFF) as u8;
    (major, minor, ter)
}

pub fn nvme_enable(base: usize) {
    let cc = read_reg(base, NVME_CC);
    write_reg(base, NVME_CC, cc | 1);
}

pub fn nvme_disable(base: usize) {
    let cc = read_reg(base, NVME_CC);
    write_reg(base, NVME_CC, cc & !1);
}

pub fn nvme_ready(base: usize) -> bool {
    (read_reg(base, NVME_CSTS) & 1) != 0
}