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

const MAX_IOMMU_MAPPINGS: usize = 64;

static MAPPING_COUNT: AtomicUsize = AtomicUsize::new(0);
static MAP_IOVA: [AtomicUsize; MAX_IOMMU_MAPPINGS] =
    [const { AtomicUsize::new(0) }; MAX_IOMMU_MAPPINGS];
static MAP_PHYS: [AtomicUsize; MAX_IOMMU_MAPPINGS] =
    [const { AtomicUsize::new(0) }; MAX_IOMMU_MAPPINGS];
static MAP_SIZE: [AtomicUsize; MAX_IOMMU_MAPPINGS] =
    [const { AtomicUsize::new(0) }; MAX_IOMMU_MAPPINGS];

pub fn map_iommu() {
    let count = MAPPING_COUNT.load(Ordering::Acquire);
    if count == 0 {
        add_mapping(0x0000_0000, 0x0000_0000, 0x1000);
    }
}

pub fn add_mapping(iova: usize, phys: usize, size: usize) -> bool {
    let idx = MAPPING_COUNT.fetch_add(1, Ordering::AcqRel);
    if idx >= MAX_IOMMU_MAPPINGS {
        MAPPING_COUNT.fetch_sub(1, Ordering::Release);
        return false;
    }
    MAP_IOVA[idx].store(iova, Ordering::Release);
    MAP_PHYS[idx].store(phys, Ordering::Release);
    MAP_SIZE[idx].store(size, Ordering::Release);
    true
}

pub fn translate(iova: usize) -> Option<usize> {
    let count = MAPPING_COUNT.load(Ordering::Acquire);
    let mut idx = 0;
    while idx < count && idx < MAX_IOMMU_MAPPINGS {
        let base = MAP_IOVA[idx].load(Ordering::Acquire);
        let size = MAP_SIZE[idx].load(Ordering::Acquire);
        if iova >= base && iova < base + size {
            let phys = MAP_PHYS[idx].load(Ordering::Acquire);
            return Some(phys + (iova - base));
        }
        idx += 1;
    }
    None
}

pub fn mapping_count() -> usize {
    MAPPING_COUNT.load(Ordering::Acquire)
}