feat: userspace linker script at 0x10000, proper ELF segment loading, full disk boot pipeline working
- Userspace linker script: apps/servers link at 0x10000 (user VA) - Adapter linker script: kernel links at 0x80200000 (S-mode) - Each uses build.rs to emit its own -T flag, global config only sets panic=abort - ELF loader: page-aligns segment mappings, handles non-aligned vaddrs - Stack: 4 pages (16K) mapped below program - SP set to top of stack (0x10000), not bottom - FAT16 disk image forced (mformat was creating FAT32) - End-to-end verified: VirtIO → FAT16 → ELF → userspace → ecall → exit
This commit is contained in:
@@ -113,46 +113,100 @@ fn load_init_from_disk(uart: &Uart, kernel_pt: &mmu::PageTable) -> usize {
|
||||
}
|
||||
};
|
||||
|
||||
// Parse ELF
|
||||
// Parse ELF and map segments
|
||||
let entry_va = match elf::parse(&init_buf[..file_size]) {
|
||||
Ok(elf_info) => {
|
||||
uart.write_str("k-os: ELF entry point = ");
|
||||
uart.write_hex(elf_info.entry_point);
|
||||
uart.put_char(b'\n');
|
||||
|
||||
// Map each segment into user page table
|
||||
let pages = (file_size + 4095) / 4096;
|
||||
let _user_pt = mmu::create_user_page_table(
|
||||
// Create a user page table with kernel mappings
|
||||
let user_pt = mmu::create_user_page_table(
|
||||
kernel_pt,
|
||||
types::address::PhysicalAddress::from_raw(init_base),
|
||||
pages,
|
||||
types::address::VirtualAddress::from_raw(INIT_LOAD_VA),
|
||||
types::address::PhysicalAddress::from_raw(0),
|
||||
0,
|
||||
types::address::VirtualAddress::from_raw(0x10000),
|
||||
);
|
||||
|
||||
use ::platform::Platform;
|
||||
kernel_ref().platform_mut().configure_protection(
|
||||
// Map each PT_LOAD segment at its virtual address
|
||||
for segment in elf_info.segments() {
|
||||
let page_start = segment.vaddr & !0xFFF;
|
||||
let offset_in_page = segment.vaddr & 0xFFF;
|
||||
let total_size = offset_in_page + segment.mem_size;
|
||||
let seg_pages = (total_size + 4095) / 4096;
|
||||
|
||||
for p in 0..seg_pages {
|
||||
let page = mmu::allocator::alloc_zeroed_page();
|
||||
|
||||
let page_va_start = page_start + p * 4096;
|
||||
let seg_start_in_file = if p == 0 { 0 } else { p * 4096 - offset_in_page };
|
||||
let dest_offset = if p == 0 { offset_in_page } else { 0 };
|
||||
let copy_len = if seg_start_in_file < segment.file_size {
|
||||
(segment.file_size - seg_start_in_file).min(4096 - dest_offset)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if copy_len > 0 {
|
||||
let src = segment.file_offset + seg_start_in_file;
|
||||
if src + copy_len <= file_size {
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
init_buf.as_ptr().add(src),
|
||||
(page as *mut u8).add(dest_offset),
|
||||
copy_len,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let flags = if segment.flags.execute {
|
||||
mmu::Sv39Flags::user_rx()
|
||||
} else if segment.flags.write {
|
||||
mmu::Sv39Flags::user_rw()
|
||||
} else {
|
||||
mmu::Sv39Flags::user_rx()
|
||||
};
|
||||
mmu::map(user_pt, mmu::Mapping {
|
||||
va: types::address::VirtualAddress::from_raw(page_va_start),
|
||||
pa: types::address::PhysicalAddress::from_raw(page),
|
||||
pages: 1,
|
||||
flags,
|
||||
});
|
||||
}
|
||||
uart.write_str("k-os: mapped segment at ");
|
||||
uart.write_hex(segment.vaddr);
|
||||
uart.write_str(" (");
|
||||
uart.write_dec(seg_pages);
|
||||
uart.write_str(" pages)\n");
|
||||
}
|
||||
|
||||
// Map stack pages below the lowest segment (4 pages = 16K)
|
||||
let stack_pages = 4;
|
||||
for i in 0..stack_pages {
|
||||
let stack_page = mmu::allocator::alloc_zeroed_page();
|
||||
let stack_va = 0x10000 - (stack_pages - i) * 4096;
|
||||
mmu::map(user_pt, mmu::Mapping {
|
||||
va: types::address::VirtualAddress::from_raw(stack_va),
|
||||
pa: types::address::PhysicalAddress::from_raw(stack_page),
|
||||
pages: 1,
|
||||
flags: mmu::Sv39Flags::user_rw(),
|
||||
});
|
||||
}
|
||||
|
||||
// Store page table for init process
|
||||
let kern = kernel_ref();
|
||||
let pt_addr = user_pt as *const mmu::PageTable as usize;
|
||||
kern.platform_mut().set_page_table(
|
||||
types::id::ProcessId::from_raw(0),
|
||||
&[],
|
||||
pt_addr,
|
||||
);
|
||||
|
||||
elf_info.entry_point
|
||||
}
|
||||
Err(_) => {
|
||||
uart.write_str("k-os: not valid ELF — loading as raw binary\n");
|
||||
let _user_pt = mmu::create_user_page_table(
|
||||
kernel_pt,
|
||||
types::address::PhysicalAddress::from_raw(init_base),
|
||||
(file_size + 4095) / 4096,
|
||||
types::address::VirtualAddress::from_raw(INIT_LOAD_VA),
|
||||
);
|
||||
|
||||
use ::platform::Platform;
|
||||
kernel_ref().platform_mut().configure_protection(
|
||||
types::id::ProcessId::from_raw(0),
|
||||
&[],
|
||||
);
|
||||
|
||||
INIT_LOAD_VA
|
||||
load_fallback_init(kernel_pt)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -209,7 +263,7 @@ fn launch_init(uart: &Uart, entry_va: usize) -> ! {
|
||||
|
||||
if let Some(ctx) = kern.thread_context_mut(tid) {
|
||||
ctx.set_pc(entry_va);
|
||||
ctx.registers_mut()[2] = INIT_LOAD_VA - 4096;
|
||||
ctx.registers_mut()[2] = INIT_LOAD_VA;
|
||||
let mut sstatus: usize = 0;
|
||||
sstatus |= 1 << 5; // SPIE
|
||||
ctx.set_status(sstatus);
|
||||
@@ -229,7 +283,7 @@ fn launch_init(uart: &Uart, entry_va: usize) -> ! {
|
||||
unsafe { core::arch::asm!("mv {0}, sp", out(reg) kernel_sp) };
|
||||
trap::set_kernel_stack(kernel_sp);
|
||||
|
||||
let user_sp = INIT_LOAD_VA - 4096;
|
||||
let user_sp = INIT_LOAD_VA;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"csrc sstatus, {spp}",
|
||||
|
||||
@@ -30,6 +30,10 @@ impl RiscVPlatform {
|
||||
self.page_tables[pid.raw() as usize]
|
||||
}
|
||||
|
||||
pub fn set_page_table(&mut self, pid: ProcessId, addr: usize) {
|
||||
self.page_tables[pid.raw() as usize] = addr;
|
||||
}
|
||||
|
||||
fn ensure_page_table(&mut self, pid: ProcessId) -> &mut mmu::PageTable {
|
||||
let idx = pid.raw() as usize;
|
||||
if self.page_tables[idx] == 0 {
|
||||
|
||||
Reference in New Issue
Block a user