sparreal-kernel 0.1.6

Sparreal OS kernel
Documentation
use core::ptr::NonNull;

use page_table_generic::{err::PagingResult, Access, AccessSetting, CacheSetting, MapConfig};

use crate::{dbg, dbg_hex, dbg_hexln, dbgln, kernel::BootConfig};

use super::{table::PageTableRef, PageAllocator};

pub fn new_boot_table(config: BootConfig) -> PagingResult<usize> {
    let heap_size =
        (config.main_memory.size - config.main_memory_heap_offset - config.hart_stack_size) / 2;
    let heap_start = config.main_memory.start + config.main_memory_heap_offset + heap_size;

    let mut access = unsafe {
        PageAllocator::new(
            NonNull::new_unchecked(heap_start.as_usize() as _),
            heap_size,
        )
    };

    let mut table = PageTableRef::create_empty(&mut access)?;
    dbg_hexln!(config.va_offset);

    unsafe {
        map_boot_region(
            "main memory",
            &mut table,
            config.main_memory.start.into(),
            config.main_memory.size,
            AccessSetting::Read | AccessSetting::Write | AccessSetting::Execute,
            CacheSetting::Normal,
            &mut access,
            config.va_offset,
        )?;

        for rsv in config.reserved_memory {
            if let Some(rsv) = rsv {
                map_boot_region(
                    rsv.name,
                    &mut table,
                    rsv.start.into(),
                    rsv.size,
                    rsv.access,
                    rsv.cache,
                    &mut access,
                    config.va_offset,
                )?;
            }
        }
    }
    Ok(table.paddr())
}

unsafe fn map_boot_region(
    name: &str,
    table: &mut PageTableRef<'_>,
    paddr: usize,
    size: usize,
    access_setting: AccessSetting,
    cache_setting: CacheSetting,
    access: &mut impl Access,
    va_offset: usize,
) -> PagingResult<()> {
    map_boot_region_once(
        name,
        table,
        paddr,
        paddr,
        size,
        access_setting,
        cache_setting,
        access,
    )?;

    map_boot_region_once(
        name,
        table,
        paddr + va_offset,
        paddr,
        size,
        access_setting,
        cache_setting,
        access,
    )?;

    Ok(())
}

unsafe fn map_boot_region_once(
    name: &str,
    table: &mut PageTableRef<'_>,
    vaddr: usize,
    paddr: usize,
    size: usize,
    access_setting: AccessSetting,
    cache_setting: CacheSetting,
    access: &mut impl Access,
) -> PagingResult<()> {
    let name_count = name.chars().count();
    let name_space = 12;
    let space = if name_space > name_count {
        name_space - name_count
    } else {
        0
    };
    dbg!("Map [");
    dbg!(name);
    for _ in 0..space {
        dbg!(" ");
    }
    dbg!("]: [");
    dbg_hex!(vaddr);
    dbg!(", ");
    dbg_hex!(vaddr + size);
    dbg!(") -> [");
    dbg_hex!(paddr);
    dbg!(", ");
    dbg_hex!(paddr + size);
    dbgln!(")");

    table.map_region(
        MapConfig::new(vaddr as _, paddr, access_setting, cache_setting),
        size,
        true,
        access,
    )
}