refactor(adapter-riscv): replace hardcoded demo with proper init launch via ELF parsing
Adapter now: parses init binary (ELF or raw), allocates pages, creates user page table, sets thread entry point in SavedContext, enters U-mode. Init takes over from there — no more IPC demo hardcoded in the adapter.
This commit is contained in:
@@ -11,6 +11,7 @@ bench = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
types = { workspace = true }
|
types = { workspace = true }
|
||||||
domain = { workspace = true }
|
domain = { workspace = true }
|
||||||
|
elf = { workspace = true }
|
||||||
platform = { workspace = true }
|
platform = { workspace = true }
|
||||||
kernel = { workspace = true }
|
kernel = { workspace = true }
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ mod trap;
|
|||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
use hw::uart::Uart;
|
use hw::uart::Uart;
|
||||||
use kernel_cell::KernelCell;
|
use kernel_cell::KernelCell;
|
||||||
|
use ::platform::Platform;
|
||||||
|
|
||||||
static KERNEL: KernelCell<kernel::Kernel<platform::RiscVPlatform>> = KernelCell::uninit();
|
static KERNEL: KernelCell<kernel::Kernel<platform::RiscVPlatform>> = KernelCell::uninit();
|
||||||
|
|
||||||
@@ -46,6 +47,16 @@ fn zero_bss() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Embedded init binary — in production this comes from the boot image.
|
||||||
|
// For now, a minimal program: call SYS_EXIT and loop.
|
||||||
|
static INIT_BINARY: [u8; 12] = [
|
||||||
|
0x93, 0x08, 0x00, 0x01, // addi a7, zero, 16 (SYS_EXIT)
|
||||||
|
0x73, 0x00, 0x00, 0x00, // ecall
|
||||||
|
0x6f, 0xf0, 0xdf, 0xff, // j -4
|
||||||
|
];
|
||||||
|
|
||||||
|
const INIT_LOAD_VA: usize = 0x10000;
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn kmain() -> ! {
|
extern "C" fn kmain() -> ! {
|
||||||
zero_bss();
|
zero_bss();
|
||||||
@@ -70,57 +81,53 @@ extern "C" fn kmain() -> ! {
|
|||||||
board::USER_POOL_PAGES,
|
board::USER_POOL_PAGES,
|
||||||
);
|
);
|
||||||
KERNEL.init(kernel::Kernel::new(riscv_platform, pool));
|
KERNEL.init(kernel::Kernel::new(riscv_platform, pool));
|
||||||
let kern = kernel_ref();
|
|
||||||
|
|
||||||
let (_pid, _tid) = kern
|
launch_init(&uart, kernel_pt);
|
||||||
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
|
||||||
.unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; });
|
|
||||||
uart.write_str("k-os: kernel started\n");
|
|
||||||
|
|
||||||
userspace_demo(&uart, kernel_pt);
|
|
||||||
|
|
||||||
uart.write_str("k-os: demo complete\n");
|
|
||||||
loop {
|
|
||||||
unsafe { core::arch::asm!("wfi") };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static USER_EXIT_PROGRAM: [u8; 12] = [
|
fn launch_init(uart: &Uart, kernel_pt: &mmu::PageTable) -> ! {
|
||||||
0x93, 0x08, 0x00, 0x01, // addi a7, zero, 16 (SYS_EXIT)
|
let kern = kernel_ref();
|
||||||
0x73, 0x00, 0x00, 0x00, // ecall
|
|
||||||
0x6f, 0xf0, 0xdf, 0xff, // j -4
|
|
||||||
];
|
|
||||||
|
|
||||||
const USER_VA_RAW: usize = 0x10000;
|
let entry_va = load_init_binary(kernel_pt, uart);
|
||||||
|
|
||||||
fn userspace_demo(uart: &Uart, kernel_pt: &mmu::PageTable) {
|
let (pid, tid) = kern
|
||||||
uart.write_str("k-os: --- userspace demo ---\n");
|
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
uart.write_str("k-os: FATAL — boot failed\n");
|
||||||
|
loop { unsafe { core::arch::asm!("wfi") }; }
|
||||||
|
});
|
||||||
|
|
||||||
let program_page = mmu::allocator::alloc_zeroed_page();
|
// Set init thread's entry point to the loaded binary
|
||||||
unsafe {
|
if let Some(ctx) = kern.thread_context_mut(tid) {
|
||||||
core::ptr::copy_nonoverlapping(
|
ctx.set_pc(entry_va);
|
||||||
USER_EXIT_PROGRAM.as_ptr(),
|
ctx.registers_mut()[2] = INIT_LOAD_VA - 4096; // sp below program
|
||||||
program_page as *mut u8,
|
// Set sstatus for U-mode return
|
||||||
USER_EXIT_PROGRAM.len(),
|
let mut sstatus: usize = 0;
|
||||||
);
|
sstatus |= 1 << 5; // SPIE — enable interrupts after sret
|
||||||
|
// SPP = 0 (U-mode) — bit 8 stays clear
|
||||||
|
ctx.set_status(sstatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_pt = mmu::create_user_page_table(
|
uart.write_str("k-os: init loaded at ");
|
||||||
kernel_pt,
|
uart.write_hex(entry_va);
|
||||||
types::address::PhysicalAddress::from_raw(program_page),
|
uart.write_str(", entering U-mode (pid=");
|
||||||
1,
|
uart.write_dec(pid.raw() as usize);
|
||||||
types::address::VirtualAddress::from_raw(USER_VA_RAW),
|
uart.write_str(")\n");
|
||||||
);
|
|
||||||
|
|
||||||
uart.write_str("k-os: user page table created, entering U-mode\n");
|
// Activate init's page table
|
||||||
|
let init_pt_addr = kern.platform_mut().page_table_for(pid);
|
||||||
mmu::activate(user_pt);
|
if init_pt_addr != 0 {
|
||||||
|
let pt = unsafe { &*(init_pt_addr as *const mmu::PageTable) };
|
||||||
|
mmu::activate(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set kernel stack in sscratch for trap handler
|
||||||
let kernel_sp: usize;
|
let kernel_sp: usize;
|
||||||
unsafe { core::arch::asm!("mv {0}, sp", out(reg) kernel_sp) };
|
unsafe { core::arch::asm!("mv {0}, sp", out(reg) kernel_sp) };
|
||||||
trap::set_kernel_stack(kernel_sp);
|
trap::set_kernel_stack(kernel_sp);
|
||||||
|
|
||||||
let user_stack = USER_VA_RAW - 8;
|
// Enter user mode via sret
|
||||||
|
let user_sp = INIT_LOAD_VA - 4096;
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"csrc sstatus, {spp}",
|
"csrc sstatus, {spp}",
|
||||||
@@ -130,13 +137,82 @@ fn userspace_demo(uart: &Uart, kernel_pt: &mmu::PageTable) {
|
|||||||
"sret",
|
"sret",
|
||||||
spp = in(reg) 1usize << 8,
|
spp = in(reg) 1usize << 8,
|
||||||
spie = in(reg) 1usize << 5,
|
spie = in(reg) 1usize << 5,
|
||||||
entry = in(reg) USER_VA_RAW,
|
entry = in(reg) entry_va,
|
||||||
stack = in(reg) user_stack,
|
stack = in(reg) user_sp,
|
||||||
options(noreturn),
|
options(noreturn),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_init_binary(kernel_pt: &mmu::PageTable, uart: &Uart) -> usize {
|
||||||
|
// Try to parse as ELF
|
||||||
|
if let Ok(elf_info) = elf::parse(&INIT_BINARY) {
|
||||||
|
uart.write_str("k-os: init is ELF, entry=");
|
||||||
|
uart.write_hex(elf_info.entry_point);
|
||||||
|
uart.put_char(b'\n');
|
||||||
|
|
||||||
|
for segment in elf_info.segments() {
|
||||||
|
let pages = (segment.mem_size + 4095) / 4096;
|
||||||
|
for p in 0..pages {
|
||||||
|
let page = mmu::allocator::alloc_zeroed_page();
|
||||||
|
let src_offset = segment.file_offset + p * 4096;
|
||||||
|
let copy_len = if p * 4096 < segment.file_size {
|
||||||
|
(segment.file_size - p * 4096).min(4096)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
if copy_len > 0 && src_offset + copy_len <= INIT_BINARY.len() {
|
||||||
|
unsafe {
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
INIT_BINARY.as_ptr().add(src_offset),
|
||||||
|
page as *mut u8,
|
||||||
|
copy_len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let kern = kernel_ref();
|
||||||
|
kern.platform_mut().configure_protection(
|
||||||
|
types::id::ProcessId::from_raw(0),
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
|
elf_info.entry_point
|
||||||
|
} else {
|
||||||
|
// Raw binary — copy to a page and map at INIT_LOAD_VA
|
||||||
|
uart.write_str("k-os: init is raw binary, loading at ");
|
||||||
|
uart.write_hex(INIT_LOAD_VA);
|
||||||
|
uart.put_char(b'\n');
|
||||||
|
|
||||||
|
let program_page = mmu::allocator::alloc_zeroed_page();
|
||||||
|
unsafe {
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
INIT_BINARY.as_ptr(),
|
||||||
|
program_page as *mut u8,
|
||||||
|
INIT_BINARY.len(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _user_pt = mmu::create_user_page_table(
|
||||||
|
kernel_pt,
|
||||||
|
types::address::PhysicalAddress::from_raw(program_page),
|
||||||
|
1,
|
||||||
|
types::address::VirtualAddress::from_raw(INIT_LOAD_VA),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Store the page table for init (pid 0)
|
||||||
|
let kern = kernel_ref();
|
||||||
|
kern.platform_mut().configure_protection(
|
||||||
|
types::id::ProcessId::from_raw(0),
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
|
INIT_LOAD_VA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
let uart = Uart::new();
|
let uart = Uart::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user