#![no_std] #[macro_use] pub mod util; pub mod allocators; pub mod collections; pub mod console; pub mod device_tree; pub mod drivers; pub mod interrupts; pub mod prelude; #[cfg(not(test))] mod panic; use crate::prelude::*; /// The entrypoint to the kernel. This should be executed by hart0 alone. It performs some early /// boot tasks, then wakes up any other harts. /// /// # Safety /// /// - The `device_tree` pointer must be a valid pointer into physical memory. See /// `device_tree::FlattenedDeviceTree::from_ptr` for the precise requirements. /// - This must be called in supervisor mode with paging and traps disabled, but with all traps /// delegated to supervisor mode. #[no_mangle] pub unsafe extern "C" fn hart0_boot(device_tree: *const u8) -> ! { console::init(); info!("device_tree = {device_tree:?}"); let flattened_device_tree = unsafe { device_tree::FlattenedDeviceTree::from_ptr(device_tree) } .expect("invalid DeviceTree"); for event in flattened_device_tree.struct_events() { let event = event.expect("invalid DeviceTree"); dbg!(event); } // Set up the allocator and the timer subsystem. // // TODO: The timer really oughta be later... flattened_device_tree .for_each_property(|node, prop, value| { if node == ["", "cpus"] && prop == "timebase-frequency" { if value.len() == 4 { let value = [value[0], value[1], value[2], value[3]]; let timebase_frequency = u32::from_be_bytes(value); // SAFETY: Nobody is concurrently running, so they can't be concurrently // modifying this. unsafe { drivers::riscv_timer::TIMEBASE_FREQUENCY = timebase_frequency; } dbg!(timebase_frequency); } else { warn!("/cpus/timebase-frequency was not a 4-byte quantity"); } } else { info!("{node}{prop} = {value:?}"); } Ok(()) }) .map_err(|err| err.left_or_else(|void| void::unreachable(void))) .expect("invalid DeviceTree"); interrupts::example_timer(); info!("sleeping forever..."); loop { unsafe { core::arch::asm!("wfi") } } }