108 lines
3.1 KiB
Rust
108 lines
3.1 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
|
|
mod board;
|
|
mod boot;
|
|
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<kernel::Kernel<platform::RiscVPlatform>> = KernelCell::uninit();
|
|
|
|
fn kern_mut() -> &'static mut kernel::Kernel<platform::RiscVPlatform> {
|
|
// 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<platform::RiscVPlatform> {
|
|
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();
|
|
// Both come from the kernel image; init starts everything else from disk.
|
|
let init = boot::loader::load_init(&uart);
|
|
let storage = boot::loader::load_storage(&uart, init.pid);
|
|
|
|
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") };
|
|
}
|
|
}
|