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 super::hal::{
    BootHal, BusHal, DiscoveryHal, DmaHal, FirmwareHal, HardwareAccessHal, InterruptHal, IommuHal,
    MemoryHal, SecurityHal,
};
use super::handle::{self, AccelHandle, AcceleratorKind};
use super::monitor;
use super::platform::{self, Platform};
use super::resources;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

static SYSTEM_READY: AtomicBool = AtomicBool::new(false);

pub struct SystemStatus {
    pub arch: crate::arch::Architecture,
    pub gpu_present: bool,
    pub tpu_present: bool,
    pub lpu_present: bool,
    pub dma_allocated: usize,
    pub mem_allocated: usize,
    pub irq_registered: usize,
    pub limits_enforced: bool,
    pub total_ram: usize,
}

pub struct System {
    arch: crate::arch::Architecture,
    platform: Platform,
}

impl System {
    pub fn init() -> Self {
        crate::init::init_shims();
        crate::init::init();

        let arch = crate::arch::detect_arch();

        match arch {
            crate::arch::Architecture::X86_64 => {
                if crate::arch::x86_64::gpu::is_initialized() {
                    handle::register_gpu(
                        crate::arch::x86_64::gpu::gpu_mmio_base(),
                        crate::arch::x86_64::gpu::gpu_mmio_size(),
                        0,
                        0,
                    );
                }
                if crate::arch::x86_64::tpu::is_initialized() {
                    handle::register_tpu(0, 0, 0, 0);
                }
                if crate::arch::x86_64::lpu::is_initialized() {
                    handle::register_lpu(0, 0, 0, 0);
                }
            }
            crate::arch::Architecture::AArch64 => {
                if crate::arch::aarch64::gpu::is_initialized() {
                    let (gb, gs, _) =
                        crate::firmware::devicetree::find_device_by_compatible(b"arm,gpu")
                            .unwrap_or((0, 0, 0));
                    handle::register_gpu(gb, gs, 0, 0);
                }
                if crate::arch::aarch64::tpu::is_initialized() {
                    let (tb, ts, _) =
                        crate::firmware::devicetree::find_device_by_compatible(b"arm,tpu")
                            .unwrap_or((0, 0, 0));
                    handle::register_tpu(tb, ts, 0, 0);
                }
                if crate::arch::aarch64::lpu::is_initialized() {
                    let (lb, ls, _) =
                        crate::firmware::devicetree::find_device_by_compatible(b"arm,lpu")
                            .unwrap_or((0, 0, 0));
                    handle::register_lpu(lb, ls, 0, 0);
                }
            }
            _ => {}
        }

        if handle::gpu_handle().is_none() {
            let mut gpus = [crate::gpu::GpuDevice {
                bus: 0,
                device: 0,
                function: 0,
                vendor_id: 0,
                device_id: 0,
                class: 0,
                subclass: 0,
                prog_if: 0,
                bar0: 0,
            }; 8];
            let count = crate::gpu::detect_gpus(&mut gpus);
            if count > 0 {
                let g = &gpus[0];
                let bar_size =
                    crate::bus::pci::api::probe_bar_size(g.bus, g.device, g.function, 0x10)
                        .unwrap_or(0);
                handle::register_gpu(
                    g.bar0 as usize,
                    bar_size,
                    g.vendor_id as usize,
                    g.device_id as usize,
                );
            }
        }

        SYSTEM_READY.store(true, Ordering::Release);

        let platform = platform::detect();

        System { arch, platform }
    }

    pub fn is_ready(&self) -> bool {
        SYSTEM_READY.load(Ordering::Acquire)
    }

    pub fn arch(&self) -> crate::arch::Architecture {
        self.arch
    }

    pub fn gpu(&self) -> Option<AccelHandle> {
        handle::gpu_handle()
    }

    pub fn tpu(&self) -> Option<AccelHandle> {
        handle::tpu_handle()
    }

    pub fn lpu(&self) -> Option<AccelHandle> {
        handle::lpu_handle()
    }

    pub fn status(&self) -> SystemStatus {
        let snap = resources::snapshot();
        SystemStatus {
            arch: self.arch,
            gpu_present: handle::gpu_handle().is_some(),
            tpu_present: handle::tpu_handle().is_some(),
            lpu_present: handle::lpu_handle().is_some(),
            dma_allocated: snap.dma_allocated,
            mem_allocated: snap.mem_allocated,
            irq_registered: snap.irq_registered,
            limits_enforced: snap.limits_enforced,
            total_ram: crate::boot::total_usable_ram(),
        }
    }

    pub fn set_dma_limit(&self, bytes: usize) {
        resources::set_dma_limit(bytes);
    }

    pub fn set_memory_limit(&self, bytes: usize) {
        resources::set_memory_limit(bytes);
    }

    pub fn set_irq_limit(&self, max: usize) {
        resources::set_irq_limit(max);
    }

    pub fn enforce_limits(&self, enable: bool) {
        resources::enforce_limits(enable);
    }

    pub fn try_alloc_dma(&self, bytes: usize) -> bool {
        resources::try_alloc_dma(bytes)
    }

    pub fn free_dma(&self, bytes: usize) {
        resources::free_dma(bytes);
    }

    pub fn try_alloc_memory(&self, bytes: usize) -> bool {
        resources::try_alloc_memory(bytes)
    }

    pub fn free_memory(&self, bytes: usize) {
        resources::free_memory(bytes);
    }

    pub fn try_alloc_swap(&self, bytes: usize) -> bool {
        resources::try_alloc_swap(bytes)
    }

    pub fn free_swap(&self, bytes: usize) {
        resources::free_swap(bytes);
    }

    pub fn resources(&self) -> resources::ResourceSnapshot {
        resources::snapshot()
    }

    pub fn spawn_workers(&self) -> usize {
        super::worker::spawn_workers()
    }

    pub fn stop_workers(&self) {
        super::worker::stop_workers()
    }

    pub fn worker_count(&self) -> usize {
        super::worker::worker_count()
    }

    pub fn workers_running(&self) -> bool {
        super::worker::is_running()
    }

    pub fn worker_snapshot(&self, comp: monitor::Component) -> super::worker::WorkerSnapshot {
        super::worker::snapshot(comp)
    }

    pub fn all_worker_snapshots(&self) -> [super::worker::WorkerSnapshot; 5] {
        super::worker::all_snapshots()
    }

    pub fn shutdown(&self) {
        super::worker::stop_workers();
        resources::reset_counters();
        SYSTEM_READY.store(false, Ordering::Release);
    }

    pub fn accel_count(&self) -> usize {
        let mut n = 0;
        if handle::gpu_handle().is_some() {
            n += 1;
        }
        if handle::tpu_handle().is_some() {
            n += 1;
        }
        if handle::lpu_handle().is_some() {
            n += 1;
        }
        n
    }

    pub fn for_each_accel<F: FnMut(&AccelHandle)>(&self, mut f: F) {
        if let Some(ref g) = handle::gpu_handle() {
            f(g);
        }
        if let Some(ref t) = handle::tpu_handle() {
            f(t);
        }
        if let Some(ref l) = handle::lpu_handle() {
            f(l);
        }
    }

    pub fn accel_by_kind(&self, kind: AcceleratorKind) -> Option<AccelHandle> {
        match kind {
            AcceleratorKind::Gpu => handle::gpu_handle(),
            AcceleratorKind::Tpu => handle::tpu_handle(),
            AcceleratorKind::Lpu => handle::lpu_handle(),
        }
    }

    pub fn read_temperature(&self, comp: monitor::Component) -> u32 {
        monitor::read_temperature(comp)
    }

    pub fn set_temp_limit(&self, comp: monitor::Component, millideg: u32) {
        monitor::set_temp_limit(comp, millideg);
    }

    pub fn is_throttled(&self, comp: monitor::Component) -> bool {
        monitor::is_throttled(comp)
    }

    pub fn set_frequency(&self, comp: monitor::Component, hz: usize) {
        monitor::set_frequency(comp, hz);
    }

    pub fn frequency(&self, comp: monitor::Component) -> usize {
        monitor::frequency(comp)
    }

    pub fn set_freq_bounds(&self, comp: monitor::Component, min_hz: usize, max_hz: usize) {
        monitor::set_freq_bounds(comp, min_hz, max_hz);
    }

    pub fn read_cycles(&self, comp: monitor::Component) -> usize {
        monitor::read_cycles(comp)
    }

    pub fn record_ops(&self, comp: monitor::Component, count: usize) {
        monitor::record_ops(comp, count);
    }

    pub fn read_ops(&self, comp: monitor::Component) -> usize {
        monitor::read_ops(comp)
    }

    pub fn set_precision(&self, comp: monitor::Component, prec: monitor::Precision) {
        monitor::set_precision(comp, prec);
    }

    pub fn precision(&self, comp: monitor::Component) -> monitor::Precision {
        monitor::precision(comp)
    }

    pub fn component_snapshot(&self, comp: monitor::Component) -> monitor::ComponentSnapshot {
        monitor::snapshot(comp)
    }

    pub fn all_snapshots(&self) -> [monitor::ComponentSnapshot; 5] {
        monitor::snapshot_all()
    }

    pub fn platform(&self) -> Platform {
        self.platform
    }

    pub fn is_bare_metal(&self) -> bool {
        self.platform == Platform::BareMetal
    }

    pub fn is_hosted(&self) -> bool {
        self.platform == Platform::Hosted
    }

    pub fn memory(&self) -> MemoryHal {
        MemoryHal
    }

    pub fn interrupts(&self) -> InterruptHal {
        InterruptHal
    }

    pub fn bus(&self) -> BusHal {
        BusHal
    }

    pub fn dma(&self) -> DmaHal {
        DmaHal
    }

    pub fn iommu(&self) -> IommuHal {
        IommuHal
    }

    pub fn firmware(&self) -> FirmwareHal {
        FirmwareHal
    }

    pub fn discovery(&self) -> DiscoveryHal {
        DiscoveryHal
    }

    pub fn boot(&self) -> BootHal {
        BootHal
    }

    pub fn security(&self) -> SecurityHal {
        SecurityHal
    }

    pub fn hardware_access(&self) -> HardwareAccessHal {
        HardwareAccessHal
    }
}

static SYSTEM_SIG: AtomicUsize = AtomicUsize::new(0);

pub fn system_signature() -> usize {
    SYSTEM_SIG.load(Ordering::Acquire)
}

pub fn set_system_signature(sig: usize) {
    SYSTEM_SIG.store(sig, Ordering::Release);
}