diff --git a/.cargo/config.toml b/.cargo/config.toml index e800c83..d9fa1ac 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,3 @@ [target.riscv64gc-unknown-none-elf] runner = "qemu-system-riscv64 -machine virt -nographic -bios default -kernel" -rustflags = ["-C", "link-arg=-Tcrates/adapter-riscv/linker.ld", "-C", "panic=abort"] +rustflags = ["-C", "panic=abort"] diff --git a/crates/adapter-riscv/build.rs b/crates/adapter-riscv/build.rs new file mode 100644 index 0000000..c0935ae --- /dev/null +++ b/crates/adapter-riscv/build.rs @@ -0,0 +1,5 @@ +fn main() { + let ld = std::path::Path::new("linker.ld").canonicalize().unwrap(); + println!("cargo:rustc-link-arg=-T{}", ld.display()); + println!("cargo:rerun-if-changed=linker.ld"); +} diff --git a/crates/adapter-riscv/src/main.rs b/crates/adapter-riscv/src/main.rs index 6a6c2db..f48c644 100644 --- a/crates/adapter-riscv/src/main.rs +++ b/crates/adapter-riscv/src/main.rs @@ -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}", diff --git a/crates/adapter-riscv/src/platform.rs b/crates/adapter-riscv/src/platform.rs index 0c5f76a..4ce0e4a 100644 --- a/crates/adapter-riscv/src/platform.rs +++ b/crates/adapter-riscv/src/platform.rs @@ -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 { diff --git a/crates/init/src/lib.rs b/crates/init/src/lib.rs index c248684..d72a966 100644 --- a/crates/init/src/lib.rs +++ b/crates/init/src/lib.rs @@ -7,10 +7,6 @@ pub mod shutdown; pub mod supervisor; pub fn run() -> ! { - let create_cap = types::bounded::CapSlot::new(0) - .unwrap_or_else(|| unreachable!()); - - let result = boot::boot(&manifest::SNAKE_MANIFEST, create_cap); - let mut sup = boot::create_supervisor(&manifest::SNAKE_MANIFEST, &result); - sup.run(create_cap); + // Phase 1: just prove we can run from disk and exit cleanly + userspace::syscall::exit(); } diff --git a/crates/userspace-rt/build.rs b/crates/userspace-rt/build.rs new file mode 100644 index 0000000..c0935ae --- /dev/null +++ b/crates/userspace-rt/build.rs @@ -0,0 +1,5 @@ +fn main() { + let ld = std::path::Path::new("linker.ld").canonicalize().unwrap(); + println!("cargo:rustc-link-arg=-T{}", ld.display()); + println!("cargo:rerun-if-changed=linker.ld"); +} diff --git a/crates/userspace-rt/linker.ld b/crates/userspace-rt/linker.ld new file mode 100644 index 0000000..5d2bb0c --- /dev/null +++ b/crates/userspace-rt/linker.ld @@ -0,0 +1,25 @@ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +SECTIONS { + . = 0x10000; + + .text : { + *(.text.entry) + *(.text .text.*) + } + + . = ALIGN(4096); + .rodata : { *(.rodata .rodata.*) } + + . = ALIGN(4096); + .data : { *(.data .data.*) } + + . = ALIGN(4096); + .bss : { + *(.bss .bss.*) + *(.sbss .sbss.*) + } + + /DISCARD/ : { *(.eh_frame) } +}