diff options
Diffstat (limited to 'crates/kernel/src/lib.rs')
-rw-r--r-- | crates/kernel/src/lib.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs new file mode 100644 index 0000000..eff6d36 --- /dev/null +++ b/crates/kernel/src/lib.rs @@ -0,0 +1,101 @@ +//! The static library that forms the core of the kernel. +#![no_std] + +use crate::arch::{sleep_forever, PAGE_SIZE}; +use log::{debug, info, warn}; +use vernos_alloc_physmem_free_list::FreeListAllocator; +use vernos_device_tree::FlattenedDeviceTree; +use vernos_utils::dbg; + +#[cfg(target_os = "none")] +mod panic; + +pub mod arch; + +/// 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. +/// - Any other harts must not be running concurrently with us. TODO: Define their state. +#[no_mangle] +pub unsafe extern "C" fn hart0_boot(device_tree: *const u8) -> ! { + // Set up the logger. + // + // TODO: This should really be named something better than console. + // console::init(); + + // Parse the DeviceTree. + let flattened_device_tree = + unsafe { FlattenedDeviceTree::from_ptr(device_tree) }.expect("invalid DeviceTree"); + + // Find the available physical memory areas and initialize the physical memory + // free-list. + let mut physical_memory_free_list = FreeListAllocator::<PAGE_SIZE>::new(); + dbg!(physical_memory_free_list); + + /* + flattened_device_tree + .for_each_node(|node| { + if node.is_unit(&["", "memory"]) { + // Get the memory ranges. + let Some(reg) = node.get_reg_usize() else { + warn!("{}reg was not valid", node.name()); + return Ok(()); + }; + + for (addr, size) in reg { + physical_memory_free_list.add_range(addr..addr + size); + } + } + Ok(()) + }) + .unwrap_or_else(|err| void::unreachable(err)); + + // Log the physical memory we found. + debug!( + "found {} usable regions of physical memory{}", + physical_memory_free_list.len(), + if physical_memory_free_list.is_empty() { + "" + } else { + ":" + } + ); + for region in physical_memory_free_list.drain() { + debug!( + "{:p}..{:p} ({} byte{})", + region.start as *const u8, + region.end as *const u8, + region.len(), + if region.len() == 1 { "" } else { "s" } + ) + } + */ + + // After this point, everything else is for debugging. + #[cfg(target_arch = "riscv64")] + { + flattened_device_tree + .for_each_node(|node| { + if node.is_unit(&["", "cpus"]) { + if let Some(timebase_frequency) = node.get_prop_u32("timebase-frequency") { + // SAFETY: Other harts are not concurrently running, so they can't be + // concurrently accessing or modifying this. + unsafe { + vernos_driver_riscv_timer::TIMEBASE_FREQUENCY = timebase_frequency; + } + } + } + Ok(()) + }) + .unwrap_or_else(|err| void::unreachable(err)); + arch::interrupts::example_timer(); + } + info!("sleeping forever..."); + sleep_forever(); +} |