sparreal-kernel 0.15.2

Sparreal OS kernel
Documentation
use alloc::boxed::Box;
use byte_unit::{Byte, UnitType};
use kernutil::memory::MemoryType;
use num_align::NumAlign;
use spin::Mutex;

use crate::{
    hal::al::*,
    os::mem::{__kimage_va, __percpu, __va},
};

static KERNEL_TABLE: Mutex<Option<Box<dyn PageTable>>> = Mutex::new(None);

pub fn init() {
    info!("Setting up MMU and page tables");

    let mut pt = memory::page_table_new().unwrap();
    map_regions(&mut pt);
    let pt_addr = pt.addr();
    {
        let mut g = KERNEL_TABLE.lock();
        *g = Some(pt);
    }
    debug!("Setting kernel page table to {pt_addr:?}");
    memory::set_kernel_page_table(pt_addr);
}

fn map_regions(pt: &mut Box<dyn PageTable>) {
    for region in memory::memory_map() {
        let phys = PhysAddr::from(region.physical_start);
        let fmt = Byte::from(region.size_in_bytes).get_appropriate_unit(UnitType::Binary);
        let virt;
        let access;
        let attrs;
        let mut size = region.size_in_bytes;
        match region.memory_type {
            MemoryType::KImage => {
                virt = __kimage_va(phys);
                access = AccessFlags::READ | AccessFlags::WRITE | AccessFlags::EXECUTE;
                attrs = MemAttributes::Normal;
                size = size.align_up(2 * 1024 * 1024);
            }
            MemoryType::Mmio => {
                virt = __va(phys);
                access = AccessFlags::READ | AccessFlags::WRITE;
                attrs = MemAttributes::Device;
            }
            MemoryType::PerCpuData => {
                virt = __percpu(phys);
                access = AccessFlags::READ | AccessFlags::WRITE | AccessFlags::EXECUTE;
                attrs = MemAttributes::PerCpu;
            }
            _ => {
                virt = __va(phys);
                access = AccessFlags::READ | AccessFlags::WRITE | AccessFlags::EXECUTE;
                attrs = MemAttributes::Normal;
            }
        }
        let config = MemConfig { access, attrs };
        debug!(
            "Mapping `{}`: [0x{:>016x}, 0x{:>016x}) -> [0x{:>016x}, 0x{:>016x}) {} ({:#.2})",
            region.memory_type,
            virt.raw(),
            (virt.raw() + size),
            phys.raw(),
            (phys.raw() + size),
            config,
            fmt
        );
        pt.map(virt.raw().into(), phys.raw().into(), size, config, false)
            .expect("Failed to map memory region");
    }

    #[cfg(target_arch = "x86_64")]
    {
        let lapic_phys = PhysAddr::from(0xfee0_0000usize);
        let lapic_virt = crate::os::mem::__io(lapic_phys);
        let config = MemConfig {
            access: AccessFlags::READ | AccessFlags::WRITE,
            attrs: MemAttributes::Device,
        };
        let _ = pt.unmap(lapic_virt, memory::page_size());
        debug!(
            "Mapping `LAPIC`: [0x{:>016x}, 0x{:>016x}) -> [0x{:>016x}, 0x{:>016x}) {} (4 KiB)",
            lapic_virt.raw(),
            lapic_virt.raw() + memory::page_size(),
            lapic_phys.raw(),
            lapic_phys.raw() + memory::page_size(),
            config,
        );
        pt.map(lapic_virt, lapic_phys, memory::page_size(), config, false)
            .expect("Failed to map x86_64 LAPIC page");
    }
}

pub fn ioremap(phys_start: PhysAddr, size: usize) -> Result<IoMemAddr, PagingError> {
    let mut g = KERNEL_TABLE.lock();
    let pt = g.as_mut().expect("Kernel page table not initialized");
    pt.ioremap(phys_start, size, true)
}

pub fn iounmap(mmio: &mmio_api::MmioRaw) -> Result<(), PagingError> {
    let phys_start = PhysAddr::from(mmio.phys_addr().as_usize());
    let virt = crate::os::mem::__io(phys_start);
    let end = virt + mmio.size();
    let virt_start = virt.align_down(memory::page_size());
    let virt_end = end.align_up(memory::page_size());
    let size = virt_end - virt_start;

    let mut g = KERNEL_TABLE.lock();
    let pt = g.as_mut().expect("Kernel page table not initialized");
    pt.unmap(virt_start.raw().into(), size)
}