refactor(adapter-riscv): split kmain into boot/, devices/ modules

kmain is now 20 lines — six function calls:

  hardware::init        → BSS, MMU, traps, timer, PLIC, kernel
  loader::load_init     → read init.elf, create process, map ELF
  loader::load_server   → read server ELF, create process, map ELF
  storage_setup         → VirtIO block re-init, shared buffer, phys-info
  gpu_setup             → VirtIO GPU init, framebuffer alloc, phys-info
  caps::grant_all       → endpoints, capability grants

New modules:
  boot/hardware.rs   — hardware init (BSS, MMU, traps, kernel)
  boot/loader.rs     — ELF loading, thread setup, enter_userspace
  boot/caps.rs       — endpoint creation, capability grants
  devices/storage_setup.rs — VirtIO block for storage server
  devices/gpu_setup.rs     — VirtIO GPU for display server

All unsafe contained in hw/, mmu/, trap/. Boot and device
modules call safe wrappers.
This commit is contained in:
2026-10-18 13:19:16 +02:00
parent 5766c6f7f7
commit 8d53fa9ac5
8 changed files with 495 additions and 461 deletions

View File

@@ -0,0 +1,76 @@
use crate::hw::uart::Uart;
use crate::hw::virtio_gpu::VirtioGpu;
use crate::{kernel_ref, mmu};
use types::id::ProcessId;
const GPU_VA: usize = 0x20000;
const VQUEUE_VA: usize = 0x21000;
const CMDBUF_VA: usize = 0x23000;
const PHYSINFO_VA: usize = 0x24000;
const FB_VA: usize = 0x100000;
const FB_WIDTH: u32 = 640;
const FB_HEIGHT: u32 = 480;
const FB_BPP: usize = 4;
const FB_PAGES: usize = (FB_WIDTH as usize * FB_HEIGHT as usize * FB_BPP + 4095) / 4096;
pub fn configure(uart: &Uart, display_pid: ProcessId) {
let gpu = match VirtioGpu::probe() {
Some(g) => g,
None => {
uart.write_str("k-os: no GPU (headless)\n");
return;
}
};
let pt_addr = kernel_ref().platform_mut().page_table_for(display_pid);
let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) };
map_page(pt, GPU_VA, gpu.base());
let vq_phys = alloc_contiguous(2);
map_range(pt, VQUEUE_VA, vq_phys, 2);
let cmd_phys = mmu::allocator::alloc_zeroed_page();
map_page(pt, CMDBUF_VA, cmd_phys);
let fb_phys = alloc_contiguous(FB_PAGES);
map_range(pt, FB_VA, fb_phys, FB_PAGES);
let info_phys = mmu::allocator::alloc_zeroed_page();
map_page(pt, PHYSINFO_VA, info_phys);
unsafe {
let info = info_phys as *mut u64;
core::ptr::write_volatile(info, cmd_phys as u64);
core::ptr::write_volatile(info.add(1), (cmd_phys + 512) as u64);
core::ptr::write_volatile(info.add(2), fb_phys as u64);
core::ptr::write_volatile(info.add(3), FB_WIDTH as u64);
core::ptr::write_volatile(info.add(4), FB_HEIGHT as u64);
}
gpu.init_device(vq_phys);
gpu.setup_framebuffer(cmd_phys, vq_phys, fb_phys, FB_WIDTH, FB_HEIGHT);
uart.write_str("k-os: VirtIO GPU configured\n");
}
fn map_page(pt: &mut mmu::PageTable, va: usize, pa: usize) {
mmu::map(pt, mmu::Mapping {
va: types::address::VirtualAddress::from_raw(va),
pa: types::address::PhysicalAddress::from_raw(pa),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
});
}
fn map_range(pt: &mut mmu::PageTable, va_base: usize, pa_base: usize, count: usize) {
for i in 0..count {
map_page(pt, va_base + i * 4096, pa_base + i * 4096);
}
}
fn alloc_contiguous(pages: usize) -> usize {
let first = mmu::allocator::alloc_zeroed_page();
for _ in 1..pages {
mmu::allocator::alloc_zeroed_page();
}
first
}

View File

@@ -0,0 +1,2 @@
pub mod gpu_setup;
pub mod storage_setup;

View File

@@ -0,0 +1,125 @@
use crate::hw::uart::Uart;
use crate::hw::virtio_blk::{mmio_read, mmio_write};
use crate::{kernel_ref, mmu};
use types::id::ProcessId;
const VIRTIO_VA: usize = 0x20000;
const VQUEUE_VA: usize = 0x21000;
const REQHDR_VA: usize = 0x23000;
const PHYSINFO_VA: usize = 0x24000;
const SHARED_BUF_VA: usize = 0x30000;
const SHARED_BUF_PAGES: usize = 16;
pub fn configure(
uart: &Uart,
init_pid: ProcessId,
storage_pid: ProcessId,
virtio_base: usize,
) {
let storage_pt = get_pt(storage_pid);
let init_pt = get_pt(init_pid);
map_virtio_mmio(storage_pt, virtio_base);
let vqueue_phys = alloc_and_map_virtqueue(storage_pt);
let reqhdr_phys = alloc_and_map_reqhdr(storage_pt);
write_phys_info(storage_pt, reqhdr_phys);
reinit_device(virtio_base, vqueue_phys);
uart.write_str("k-os: VirtIO configured for storage\n");
map_shared_buffer(init_pt, storage_pt);
uart.write_str("k-os: shared buffer mapped\n");
}
fn get_pt(pid: ProcessId) -> &'static mut mmu::PageTable {
let addr = kernel_ref().platform_mut().page_table_for(pid);
unsafe { &mut *(addr as *mut mmu::PageTable) }
}
fn map_virtio_mmio(pt: &mut mmu::PageTable, virtio_base: usize) {
mmu::map(pt, mmu::Mapping {
va: types::address::VirtualAddress::from_raw(VIRTIO_VA),
pa: types::address::PhysicalAddress::from_raw(virtio_base),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
});
}
fn alloc_and_map_virtqueue(pt: &mut mmu::PageTable) -> usize {
let phys = mmu::allocator::alloc_zeroed_page();
mmu::allocator::alloc_zeroed_page();
for i in 0..2usize {
mmu::map(pt, mmu::Mapping {
va: types::address::VirtualAddress::from_raw(VQUEUE_VA + i * 4096),
pa: types::address::PhysicalAddress::from_raw(phys + i * 4096),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
});
}
phys
}
fn alloc_and_map_reqhdr(pt: &mut mmu::PageTable) -> usize {
let phys = mmu::allocator::alloc_zeroed_page();
mmu::map(pt, mmu::Mapping {
va: types::address::VirtualAddress::from_raw(REQHDR_VA),
pa: types::address::PhysicalAddress::from_raw(phys),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
});
phys
}
fn write_phys_info(pt: &mut mmu::PageTable, reqhdr_phys: usize) {
let phys = mmu::allocator::alloc_zeroed_page();
mmu::map(pt, mmu::Mapping {
va: types::address::VirtualAddress::from_raw(PHYSINFO_VA),
pa: types::address::PhysicalAddress::from_raw(phys),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
});
unsafe {
let info = phys as *mut u64;
core::ptr::write_volatile(info, reqhdr_phys as u64);
core::ptr::write_volatile(info.add(1), (reqhdr_phys + 16) as u64);
core::ptr::write_volatile(info.add(2), (reqhdr_phys + 32) as u64);
}
}
fn reinit_device(base: usize, vqueue_phys: usize) {
mmio_write(base, 0x070, 0);
while mmio_read(base, 0x070) != 0 {}
mmio_write(base, 0x070, 1);
mmio_write(base, 0x070, mmio_read(base, 0x070) | 2);
mmio_write(base, 0x028, 4096);
mmio_write(base, 0x014, 0);
mmio_write(base, 0x024, 0);
mmio_write(base, 0x020, 0);
mmio_write(base, 0x030, 0);
let queue_max = mmio_read(base, 0x034);
mmio_write(base, 0x038, 8u32.min(queue_max));
mmio_write(base, 0x040, (vqueue_phys / 4096) as u32);
mmio_write(base, 0x070, mmio_read(base, 0x070) | 4);
}
fn map_shared_buffer(init_pt: &mut mmu::PageTable, storage_pt: &mut mmu::PageTable) {
for i in 0..SHARED_BUF_PAGES {
let page = mmu::allocator::alloc_zeroed_page();
let va = SHARED_BUF_VA + i * 4096;
let mapping = mmu::Mapping {
va: types::address::VirtualAddress::from_raw(va),
pa: types::address::PhysicalAddress::from_raw(page),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
};
mmu::map(init_pt, mapping);
mmu::map(storage_pt, mmu::Mapping {
va: types::address::VirtualAddress::from_raw(va),
pa: types::address::PhysicalAddress::from_raw(page),
pages: 1,
flags: mmu::Sv39Flags::user_rw(),
});
}
}