#![no_std] #![no_main] mod board; mod boot; mod boot_fs; mod devices; mod entry; mod hw; mod kernel_cell; mod mmu; mod platform; mod smp; mod trap; use hw::uart::Uart; use kernel_cell::KernelCell; static KERNEL: KernelCell> = KernelCell::uninit(); fn kern_mut() -> &'static mut kernel::Kernel { // SAFETY: boot runs with the kernel lock held and before any other // hart has started. unsafe { &mut *kernel_ptr() } } pub fn kernel_ptr() -> *mut kernel::Kernel { KERNEL.as_ptr() } #[unsafe(no_mangle)] extern "C" fn kmain(hart: usize) -> ! { let uart = Uart::new(); uart.write_str("k-os: booted on RISC-V\n"); boot::hardware::init(&uart, hart); // Not before init: zeroing .bss resets the lock. smp::lock(); let mut blk = boot::hardware::probe_block_device(&uart).unwrap_or_else(|| halt(&uart, "no block device")); let init = boot::loader::load_init(&uart, &mut blk); // Init needs storage to load anything else; the rest is init's to start. let storage = boot::loader::load_server(&uart, &mut blk, init.pid, b"storage.elf", "storage"); let board = board::devices().unwrap_or_else(|| halt(&uart, "bad board table")); kern_mut() .register_board(init.pid, &board) .unwrap_or_else(|_| halt(&uart, "board registration failed")); boot::caps::grant_all(&uart, init.pid, storage.pid); // After grant_all: init already relies on those slots. let mut placed = [None; board::BOARD_DEVICES]; let boot_caps = kern_mut() .grant_boot_authority(init.pid, &board, &mut placed) .unwrap_or_else(|_| halt(&uart, "boot authority failed")); devices::boot_info(&uart, init.pid, &board, &board::kinds(), &placed, boot_caps); start_other_harts(&uart, hart); uart.write_str("k-os: entering userspace\n"); trap::enter_first(); } fn start_other_harts(uart: &Uart, boot: usize) { unsafe extern "C" { fn _secondary_start(); } // Harts start with the MMU off, so at the entry's physical address. let entry = mmu::virt_to_phys(_secondary_start as *const () as usize); for hart in (0..smp::num_harts()).filter(|h| *h != boot) { if !smp::sbi_hart_start(hart, entry) { halt(uart, "could not start a hart"); } } uart.write_str("k-os: "); uart.write_dec(smp::num_harts()); uart.write_str(" harts\n"); } /// Where every hart but the boot hart starts, on its own stack. #[unsafe(no_mangle)] extern "C" fn kmain_secondary(_hart: usize) -> ! { trap::init(); hw::timer::init(); mmu::activate(mmu::page_table::table_at(smp::kernel_root())); smp::lock(); trap::enter_first(); } pub fn halt(uart: &Uart, msg: &str) -> ! { uart.write_str("k-os: FATAL — "); uart.write_str(msg); uart.put_char(b'\n'); loop { unsafe { core::arch::asm!("wfi") }; } } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { let uart = Uart::new(); uart.write_str("PANIC: "); if let Some(location) = info.location() { uart.write_str(location.file()); uart.put_char(b':'); uart.write_dec(location.line() as usize); } uart.put_char(b'\n'); loop { unsafe { core::arch::asm!("wfi") }; } }