diff --git a/kernel/src/arch/riscv64/init.rs b/kernel/src/arch/riscv64/init.rs index 2b130ed..72c2010 100644 --- a/kernel/src/arch/riscv64/init.rs +++ b/kernel/src/arch/riscv64/init.rs @@ -2,7 +2,7 @@ use core::{arch::asm, ops::Range}; use crate::{ arch::{asm, csr, interrupts, paging, wait}, - fdt::FDT, + dev::fdt::FDT, start, }; @@ -70,5 +70,8 @@ pub unsafe fn init() -> ! { end: raw_mem_range.end(), }; to_supervisor(); - start(heap_mem, fdt) + start(crate::StartInfo { + mem_range: heap_mem, + dt: fdt, + }) } diff --git a/kernel/src/fdt.rs b/kernel/src/dev/fdt.rs similarity index 90% rename from kernel/src/fdt.rs rename to kernel/src/dev/fdt.rs index 256a310..89a1843 100644 --- a/kernel/src/fdt.rs +++ b/kernel/src/dev/fdt.rs @@ -1,15 +1,19 @@ // garbage .1% finished FDT implementation +use alloc::format; + use crate::{ println, - util::{bits::{u32_from_bytes, Be}, lazy::LazyConst}, + util::bits::{u32_from_bytes, Be}, }; use core::{ - fmt::Debug, mem::{size_of, transmute}, ops::Range, slice + fmt::Debug, + mem::{size_of, transmute}, + ops::Range, + slice, }; const MAGIC: u32 = 0xd00dfeed; -pub static DT: LazyConst = LazyConst::new(); #[repr(u32)] #[derive(Clone, Copy, Debug)] @@ -20,7 +24,9 @@ enum Token { Nop, End, } + const TOKEN_SIZE: usize = size_of::(); + impl Token { pub fn from_bytes(bytes: &[u8]) -> Option { let val = u32_from_bytes(bytes)?.to_be(); @@ -63,6 +69,15 @@ pub struct Prop { pub data: &'static [u8], } +impl Debug for Prop { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Prop") + .field("name", &self.name) + .field("data_len", &self.data) + .finish() + } +} + impl Prop { pub fn full_len(&self) -> usize { return PROP_SIZE + self.data.len(); @@ -213,6 +228,16 @@ pub struct Node { pub props: &'static [u8], } +impl Debug for Node { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let props: alloc::vec::Vec<_> = self.into_iter().map(|p| format!("{:?}", p)).collect(); + f.debug_struct("Node") + .field("name", &self.name) + .field("props", &props) + .finish() + } +} + impl IntoIterator for &Node { type Item = Prop; type IntoIter = PropIter; diff --git a/kernel/src/dev/mod.rs b/kernel/src/dev/mod.rs index 8c20360..4c4ceb3 100644 --- a/kernel/src/dev/mod.rs +++ b/kernel/src/dev/mod.rs @@ -1 +1,2 @@ pub mod uart; +pub mod fdt; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index fc5d006..8bc9178 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -9,13 +9,12 @@ use crate::mem::alloc::ALLOCATOR; use core::ops::Range; -use fdt::{DT, FDT}; +use dev::fdt::FDT; extern crate alloc; pub mod arch; pub mod dev; -pub mod fdt; pub mod log; pub mod mem; pub mod qemu; @@ -23,20 +22,31 @@ pub mod qemu; mod test; pub mod util; -pub fn start(heap_mem: Range<*mut u8>, fdt: FDT) -> ! { - DT.init(fdt); - unsafe { - ALLOCATOR.init(heap_mem); - } +pub struct StartInfo { + mem_range: Range<*mut u8>, + dt: FDT +} + +pub fn start(info: StartInfo) -> ! { #[cfg(test)] - test_main(); + { + // un... un bro momento.. + test::init(info); + test_main(); + } #[cfg(not(test))] - main(); + main(info); qemu::exit(0) } -pub fn main() { +pub fn main(info: StartInfo) { println!("we out here vibin"); + unsafe { + ALLOCATOR.init(&info.mem_range); + } + for dev in info.dt.into_iter() { + println!("{:?}", dev); + } } #[panic_handler] diff --git a/kernel/src/mem/alloc.rs b/kernel/src/mem/alloc.rs index ee334e0..9a279bd 100644 --- a/kernel/src/mem/alloc.rs +++ b/kernel/src/mem/alloc.rs @@ -14,9 +14,12 @@ impl Allocator { pub const fn empty() -> Self { Self(Mutex::new(Heap::empty())) } - pub unsafe fn init(&self, range: Range<*mut u8>) { + pub unsafe fn init(&self, range: &Range<*mut u8>) { self.0.lock().init(range); } + pub unsafe fn reset(&self, range: &Range<*mut u8>) { + self.0.lock().reset(range); + } pub fn print(&self) { self.0.lock().print(); } diff --git a/kernel/src/mem/heap.rs b/kernel/src/mem/heap.rs index fdbefbf..c70e42c 100644 --- a/kernel/src/mem/heap.rs +++ b/kernel/src/mem/heap.rs @@ -15,11 +15,12 @@ use crate::println; const ALIGN: usize = 0b1000; const ALIGN_MASK: usize = !(ALIGN - 1); +#[repr(C)] pub struct BlockInfo(usize); impl BlockInfo { - pub const fn new(prev_used: bool, size: usize) -> Self { - Self(prev_used as usize | size) + pub const fn new(size: usize) -> Self { + Self(true as usize | size) } pub fn prev_used(&self) -> bool { self.0 & 1 == 1 @@ -37,6 +38,7 @@ impl BlockInfo { pub type BlockPointer = *mut BlockInfo; +#[repr(C)] pub struct FreeBlockInfo { info: BlockInfo, prev: FreePointer, @@ -62,6 +64,8 @@ pub struct Heap { head: FreeBlockInfo, start: *mut u8, end: *mut u8, + #[cfg(debug_assertions)] + pub debug: bool, } impl Heap { @@ -74,17 +78,24 @@ impl Heap { }, start: null_mut(), end: null_mut(), + #[cfg(debug_assertions)] + debug: false, } } - pub unsafe fn init(&mut self, range: Range<*mut u8>) { + pub unsafe fn reset(&mut self, range: &Range<*mut u8>) { + *self = Self::empty(); + self.init(range); + } + + pub unsafe fn init(&mut self, range: &Range<*mut u8>) { let head = self.head(); let first = range.start as FreePointer; let size = range.end as usize - range.start as usize; create_free( first, FreeBlockInfo { - info: BlockInfo::new(true, size), + info: BlockInfo::new(size), next: head, prev: head, }, @@ -108,38 +119,41 @@ impl Heap { let free_size = (*free).info.size(); // free block found if free_size >= size { + #[cfg(debug_assertions)] + { + if self.debug { + println!( + "-------- \x1b[92malloc\x1b[0m: {:?}; size 0x{:x}", + free, size + ); + } + } // deal with leftover space let leftover = free_size - size; if leftover < FREE_SIZE { + // consume if not enough space for another free block size = free_size; let mut next_used = free.byte_add(size) as BlockPointer; if next_used as *mut u8 == self.end { next_used = &mut self.head.info; } (*next_used).set_prev_used(); - let prev = (*free).prev; - let next = (*free).next; - (*prev).next = next; - (*next).prev = prev; + remove_free(free); } else { + // otherwise create another free let new_free = free.byte_add(size); - let prev = (*free).prev; - let next = (*free).next; - create_free( - new_free, - FreeBlockInfo { - info: BlockInfo::new(true, leftover), - prev, - next, - }, - ); - (*prev).next = new_free; - (*next).prev = new_free; + self.insert_free((*free).prev, (*free).next, new_free, leftover); } // create block let used = free as BlockPointer; - (*used) = BlockInfo::new(true, size); + (*used) = BlockInfo::new(size); let data = used.byte_add(USED_SIZE) as *mut u8; + #[cfg(debug_assertions)] + { + if self.debug { + self.print(); + } + } return data; } } @@ -148,43 +162,79 @@ impl Heap { pub unsafe fn dealloc(&mut self, ptr: *mut u8, _: core::alloc::Layout) { let used = ptr.byte_sub(USED_SIZE) as BlockPointer; + #[cfg(debug_assertions)] + { + if self.debug { + println!("-------- \x1b[91mdealloc\x1b[0m: {:?}", used); + } + } let mut size = (*used).size(); - let old_size = size; let mut addr = used as FreePointer; - let mut prev = self.head(); - let mut next = self.head.next; + let next = self.next(used); + // merge with behind if free if !(*used).prev_used() { - let prev_free = *(used.byte_sub(PTR_SIZE) as *mut FreePointer); - addr = prev_free; - size += (*prev_free).info.size(); - prev = (*prev_free).prev; - next = (*prev_free).next; + let prev = *(used.byte_sub(PTR_SIZE) as *mut FreePointer); + addr = prev; + size += (*prev).info.size(); + remove_free(prev); } - let mut n_block = used.byte_add(old_size); - if n_block as *mut u8 != self.end { - let mut nn_block = n_block.byte_add((*n_block).size()); - if nn_block as *mut u8 == self.end { - nn_block = &mut self.head.info; - } - if !(*nn_block).prev_used() { - size += (*n_block).size(); - next = (*next).next; + // merge with after if free + if !self.is_end(next) && self.is_free(next) { + size += (*next).size(); + let ahead = next as FreePointer; + remove_free(ahead); + } + // create & insert + let head = self.head(); + self.insert_free(head, self.head.next, addr, size); + (*next).unset_prev_used(); + + #[cfg(debug_assertions)] + { + if self.debug { + self.print(); } } + } + + unsafe fn insert_free( + &mut self, + prev: FreePointer, + next: FreePointer, + addr: FreePointer, + size: usize, + ) { create_free( addr, FreeBlockInfo { - info: BlockInfo::new(true, size), + info: BlockInfo::new(size), prev, next, }, ); (*prev).next = addr; (*next).prev = addr; - if n_block as *mut u8 == self.end { - n_block = &mut self.head.info; + } + + unsafe fn next(&mut self, block: BlockPointer) -> BlockPointer { + let mut next = block.byte_add((*block).size()); + // head is "end" of list + if next as *mut u8 == self.end { + next = &mut self.head.info; } - (*n_block).unset_prev_used(); + next + } + + unsafe fn is_end(&self, block: BlockPointer) -> bool { + block as *mut u8 == self.end + } + + unsafe fn is_used(&mut self, block: BlockPointer) -> bool { + (*self.next(block)).prev_used() + } + + unsafe fn is_free(&mut self, block: BlockPointer) -> bool { + !self.is_used(block) } pub fn iter_free(&mut self) -> FreeBlockIter { @@ -206,21 +256,35 @@ impl Heap { pub fn print(&mut self) { unsafe { - println!("heap: {:?} -> {:?}", self.start, self.end); + println!("heap: {:?} -> {:?}", self.start, self.end,); + let ptyp = if self.head.prev_used() { + "used" + } else { + "free" + }; + println!(" - {:?}: head, prev is {}", self.head(), ptyp); + println!( + " L prev: {:?}, next: {:?}", + self.head.prev, self.head.next + ); for block in self.iter_block() { let size = (*block).size(); let mut n_block = block.byte_add(size); if n_block as *mut u8 == self.end { n_block = &mut self.head.info; } - let used = if (*n_block).prev_used() { - "used" - } else { - "free" - }; - println!(" - {:?}: {}, size 0x{:x}", block, used, size); + let used = (*n_block).prev_used(); + let typ = if used { "used" } else { "free" }; + let ptyp = if (*block).prev_used() { "used" } else { "free" }; + println!( + " - {:?}: {}, prev is {}, size 0x{:x}", + block, typ, ptyp, size + ); + if !used { + let block = block as FreePointer; + println!(" L prev: {:?}, next: {:?}", (*block).prev, (*block).next); + } } - println!(); } } } @@ -232,6 +296,13 @@ unsafe fn create_free(addr: FreePointer, info: FreeBlockInfo) { *end = addr; } +unsafe fn remove_free(block: FreePointer) { + let next = (*block).next; + let prev = (*block).prev; + (*next).prev = prev; + (*prev).next = next; +} + pub struct FreeBlockIter { end: FreePointer, prev: FreePointer, diff --git a/kernel/src/test/mem.rs b/kernel/src/test/mem.rs index 9f1285b..12ce3ff 100644 --- a/kernel/src/test/mem.rs +++ b/kernel/src/test/mem.rs @@ -1,7 +1,12 @@ -use crate::ALLOCATOR; +use crate::{StartInfo, ALLOCATOR}; #[test_case] -fn memory1() { +fn init(_: &StartInfo) { + check_empty(); +} + +#[test_case] +fn vec(_: &StartInfo) { let mut test = alloc::vec![1, 2, 3]; assert_eq!(test[0], 1); assert_eq!(test[1], 2); @@ -11,7 +16,7 @@ fn memory1() { assert_eq!(test[1], 2); assert_eq!(test[2], 3); assert_eq!(test[3], 3); - // check allocator + check_used(1); let test2 = alloc::vec![-1, -2, -3, -4]; assert_eq!(test2[0], -1); @@ -23,15 +28,16 @@ fn memory1() { assert_eq!(test[1], 2); assert_eq!(test[2], 3); assert_eq!(test[3], 3); - // check allocator + check_used(2); drop(test2); + check_used(1); drop(test); - // check allocator + check_empty(); } #[test_case] -fn memory2() { +fn vec_vec(_: &StartInfo) { let mut test = alloc::vec::Vec::new(); for i in 0..4 { let n = i * 4; @@ -44,20 +50,43 @@ fn memory2() { assert_eq!(test[i][2], n + 2); assert_eq!(test[i][3], n + 3); } - // check allocator + check_used(5); drop(test); - // check allocator + check_empty(); } #[test_case] -fn memory_reuse() { - for _ in 0..1000 { - let _: alloc::vec::Vec = alloc::vec::Vec::with_capacity(10_000_0000); +fn reuse(info: &StartInfo) { + let size = info.mem_range.end as usize - info.mem_range.start as usize; + for _ in 0..10 { + let _: alloc::vec::Vec = alloc::vec::Vec::with_capacity(size / 2); } - // check allocator + check_empty(); } -pub fn check_alloc_empty() { - ALLOCATOR.heap(); +pub fn check_empty() { + let mut free = 0; + for _ in ALLOCATOR.heap().iter_free() { + free += 1; + } + let mut total = 0; + for _ in ALLOCATOR.heap().iter_block() { + total += 1; + } + let used = total - free; + assert_eq!((free, used), (1, 0), "(free, used)"); +} + +pub fn check_used(num: usize) { + let mut free = 0; + for _ in ALLOCATOR.heap().iter_free() { + free += 1; + } + let mut total = 0; + for _ in ALLOCATOR.heap().iter_block() { + total += 1; + } + let used = total - free; + assert_eq!(used, num); } diff --git a/kernel/src/test/mod.rs b/kernel/src/test/mod.rs index d1bbcf8..a0b2eed 100644 --- a/kernel/src/test/mod.rs +++ b/kernel/src/test/mod.rs @@ -1,4 +1,6 @@ -use crate::{print, println, qemu}; +use core::mem::MaybeUninit; + +use crate::{mem::alloc::ALLOCATOR, print, println, qemu, StartInfo}; mod mem; @@ -8,30 +10,58 @@ static mut TESTS: &[&dyn Testable] = &[]; static mut TEST: usize = 0; static mut FAILED: usize = 0; +static mut START_INFO: MaybeUninit = MaybeUninit::uninit(); + pub trait Testable { - fn run(&self) -> (); + fn run(&self, info: &StartInfo) -> (); } -impl Testable for T { - fn run(&self) { - print!("test {}... ", core::any::type_name::()); - self(); +// bruh... + +// impl Testable for T { +// fn run(&self, _: &StartInfo) { +// // TODO: very temp solution that fails if names are changed lmao +// const START: &str = "kernel::test::"; +// let name = &core::any::type_name::()[START.len()..]; +// print!("test {}... ", name); +// self(); +// println!("\x1b[92mok\x1b[0m"); +// } +// } + +impl Testable for T { + fn run(&self, info: &StartInfo) { + // TODO: very temp solution that fails if names are changed lmao + const START: &str = "kernel::test::"; + let name = &core::any::type_name::()[START.len()..]; + print!("test {}... ", name); + self(info); println!("\x1b[92mok\x1b[0m"); } } +pub fn init(info: StartInfo) { + unsafe { + *START_INFO.as_mut_ptr() = info; + } +} + pub fn test_runner(tests: &[&dyn Testable]) { - unsafe { TESTS = core::mem::transmute(tests) }; + unsafe { + TESTS = core::mem::transmute(tests); + } println!("Running {} tests", tests.len()); run_tests(); } pub fn run_tests() -> ! { + let info = unsafe {START_INFO.assume_init_ref()}; unsafe { for i in TEST..TESTS.len() { let test = TESTS[i]; TEST += 1; - test.run(); + prepare(info); + test.run(info); } print!( "results: {}. {} passed; {} failed", @@ -48,6 +78,12 @@ pub fn run_tests() -> ! { qemu::exit(0) } +fn prepare(info: &StartInfo) { + unsafe { + ALLOCATOR.reset(&info.mem_range); + } +} + pub fn test_panic(info: &core::panic::PanicInfo) -> ! { println!("\x1b[91mFAILED\x1b[0m"); println!("\x1b[93m{}\x1b[0m", info); diff --git a/kernel/src/util/lazy.rs b/kernel/src/util/lazy.rs index 7564be1..7ee6333 100644 --- a/kernel/src/util/lazy.rs +++ b/kernel/src/util/lazy.rs @@ -1,40 +1,39 @@ -use core::{mem::zeroed, ops::Deref}; +use core::{mem::MaybeUninit, ops::Deref}; pub struct LazyConst { - #[cfg(not(debug_assertions))] value: T, #[cfg(debug_assertions)] - value: Option, + state: u8, } impl Deref for LazyConst { type Target = T; fn deref(&self) -> &Self::Target { - #[cfg(not(debug_assertions))] - { - &self.value - } #[cfg(debug_assertions)] - { - self.value.as_ref().expect("Value was not assigned") + if self.state == 0 { + panic!("Lazy const for {} not assigned", core::any::type_name::()); } + &self.value } } impl LazyConst { pub const fn new() -> Self { - unsafe { Self { value: zeroed() } } + unsafe { + Self { + value: MaybeUninit::zeroed().assume_init(), + #[cfg(debug_assertions)] + state: 0, + } + } } - pub fn init(&self, value: T) { - #[cfg(not(debug_assertions))] - unsafe { - as_mut(self).value = value - } + pub unsafe fn init(&self, value: T) { + as_mut(self).value = value; #[cfg(debug_assertions)] - unsafe { - as_mut(self).value = Some(value) + { + as_mut(self).state = 1; } } }