diff --git a/src/boot/args.rs b/src/boot/args.rs new file mode 100644 index 0000000000000000000000000000000000000000..e80327853823285166a8d5223e7480302f1ac77f --- /dev/null +++ b/src/boot/args.rs @@ -0,0 +1,65 @@ +use crate::{ + boot, + log::{self, LogLevel}, +}; +use spin::{Lazy, Once}; + +// + +pub fn get() -> Arguments { + Arguments::get() +} + +// + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct Arguments { + pub log_level: LogLevel, + // log_color: bool, + pub had_unrecognized: bool, + + pub cmdline: &'static str, +} + +// + +impl Arguments { + pub fn parse(s: &'static str) -> Self { + let mut iter = s.split(|c: char| c.is_whitespace() || c == '='); + let mut result = Arguments { + cmdline: s, + ..<_>::default() + }; + + while let Some(item) = iter.next() { + match item { + "log" => { + if let Some(level) = iter.next() { + if let Some(l) = LogLevel::parse(level) { + result.log_level = l + } else { + result.had_unrecognized = true + } + } + } + _ => result.had_unrecognized = true, + } + } + + result + } + + pub fn get() -> Self { + static ARGUMENTS: Lazy<Arguments> = Lazy::new(|| { + boot::cmdline() + .map(Arguments/*Self doesn't work??*/::parse) + .unwrap_or_default() + }); + *ARGUMENTS + } + + pub fn apply(&self) { + log::set_log_level(self.log_level); + // log::set_log_color(self.log_color); + } +} diff --git a/src/boot/limine/cmdline.rs b/src/boot/limine/cmdline.rs index 26c4b5b0c6fb1c18b26c189b3fcbf084b7455188..9d92ae6900e4850953f03b09e90d42c722b1ef42 100644 --- a/src/boot/limine/cmdline.rs +++ b/src/boot/limine/cmdline.rs @@ -1,18 +1,12 @@ -use crate::env::Arguments; use limine::LimineKernelFileRequest; // -pub fn init() { +pub fn cmdline() -> Option<&'static str> { static REQ: LimineKernelFileRequest = LimineKernelFileRequest::new(0); - - if let Some(cmdline) = REQ - .get_response() + REQ.get_response() .get() .and_then(|resp| resp.kernel_file.get()) .and_then(|file| file.cmdline.to_str()) .and_then(|cmdline| cmdline.to_str().ok()) - { - Arguments::parse(cmdline); - } } diff --git a/src/boot/limine/framebuffer.rs b/src/boot/limine/framebuffer.rs index 1238512be3c892fa02aaac7cb0fe8439e49cb5f4..a07ec4c7b508c7cf239185cb7f6b7d8e6085a2e4 100644 --- a/src/boot/limine/framebuffer.rs +++ b/src/boot/limine/framebuffer.rs @@ -1,17 +1,16 @@ use crate::{ debug, - video::framebuffer::{get_fbo, Framebuffer, FramebufferInfo, FBO}, + video::framebuffer::{Framebuffer, FramebufferInfo}, }; use core::slice; use limine::LimineFramebufferRequest; -use spin::Mutex; // -pub fn init() { +pub fn framebuffer() -> Option<Framebuffer> { static FB_REQ: LimineFramebufferRequest = LimineFramebufferRequest::new(0); - let fbo = FB_REQ + FB_REQ .get_response() .get() .into_iter() @@ -22,6 +21,7 @@ pub fn init() { } let buf = unsafe { slice::from_raw_parts_mut(fb.address.as_ptr()?, fb.size()) }; + Some(Framebuffer { buf, info: FramebufferInfo { @@ -30,11 +30,5 @@ pub fn init() { pitch: fb.pitch as _, }, }) - }); - - if let Some(mut fbo) = fbo { - fbo.clear(); - FBO.call_once(|| Mutex::new(fbo)); - } - debug!("Global framebuffer: {:#?}", get_fbo().map(|f| f.info)) + }) } diff --git a/src/boot/limine/mod.rs b/src/boot/limine/mod.rs index f2d6c0db49c328244e07f7be7b16b89dc37218a9..aa6ea11587b1bfeb4a329668dd700d1061288c46 100644 --- a/src/boot/limine/mod.rs +++ b/src/boot/limine/mod.rs @@ -1,3 +1,4 @@ +use super::args; use super::BOOT_NAME; use crate::{arch, kernel_main}; @@ -6,6 +7,8 @@ use crate::{arch, kernel_main}; pub use addr::hhdm_offset; pub use addr::phys_addr; pub use addr::virt_addr; +pub use cmdline::cmdline; +pub use framebuffer::framebuffer; pub use mem::memmap; pub use term::_print; @@ -24,8 +27,7 @@ mod term; pub extern "C" fn _start() -> ! { BOOT_NAME.call_once(|| "Limine"); - framebuffer::init(); - cmdline::init(); + args::get().apply(); arch::early_boot_cpu(); arch::early_per_cpu(); diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 4e7b712fdb9b3928bbc69f90747284474fc80b46..054ee29874739cc6ce7e2670d68fa56ac91aa85d 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -2,6 +2,10 @@ use spin::Once; // +pub use boot::*; + +// + #[cfg(feature = "multiboot1")] #[path = "multiboot1/mod.rs"] #[allow(clippy::module_inception)] @@ -19,9 +23,7 @@ mod boot; #[allow(clippy::module_inception)] mod boot; -// - -pub use boot::*; +pub mod args; // diff --git a/src/env.rs b/src/env.rs index 3ddc7b56e1850f5443e79310b27ee0e123893715..139597f9cb07c5d48bed18984ec4747f4b4f3438 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,63 +1,2 @@ -use crate::log::{self, LogLevel}; -use spin::Once; -// -pub fn args() -> Arguments { - Arguments::get() -} - -// - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct Arguments { - pub log_level: LogLevel, - // log_color: bool, - pub had_unrecognized: bool, - - pub cmdline: &'static str, -} - -// - -impl Arguments { - pub fn parse(s: &'static str) { - ARGUMENTS.call_once(|| { - let mut iter = s.split(|c: char| c.is_whitespace() || c == '='); - let mut result = Arguments { - cmdline: s, - ..<_>::default() - }; - - while let Some(item) = iter.next() { - match item { - "log" => { - if let Some(level) = iter.next() { - if let Some(l) = LogLevel::parse(level) { - result.log_level = l - } else { - result.had_unrecognized = true - } - } - } - _ => result.had_unrecognized = true, - } - } - - result.assign(); - - result - }); - } - - pub fn get() -> Self { - ARGUMENTS.get().copied().unwrap_or(Self::default()) - } - - pub fn assign(&self) { - log::set_log_level(self.log_level); - // log::set_log_color(self.log_color); - } -} - -static ARGUMENTS: Once<Arguments> = Once::new(); diff --git a/src/main.rs b/src/main.rs index 3d8220d647eedf6bc8d144c4c7c023103c911d3d..9451487099efce171bec72756e4fa461adcf0594 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ #![feature(let_chains)] #![test_runner(crate::testfw::test_runner)] #![reexport_test_harness_main = "test_main"] +#![doc = include_str!("../README.md")] // @@ -47,17 +48,25 @@ pub static KERNEL_VERS: &str = env!("CARGO_PKG_VERSION"); // the actual entry exists in [´crate::boot::boot´] fn kernel_main() -> ! { + let args = boot::args::get(); + args.apply(); + debug!("Entering kernel_main"); - debug!("Cmdline: {:?}", env::Arguments::get()); + debug!("Cmdline: {args:?}"); debug!( - "Kernel addr: {:?}, {:?}, HDDM Offset: {:#0X?}", + "Kernel addr: {:?}, {:?}, HHDM Offset: {:#0X?}", boot::virt_addr(), boot::phys_addr(), boot::hhdm_offset() ); - mem::init(); + debug!( + "{:?}", + (0u32..32) + .map(|i| 2u32.pow(i)) + .collect::<alloc::vec::Vec<_>>() + ); // ofc. every kernel has to have this cringy ascii name splash info!("\n{}\n", include_str!("./splash")); diff --git a/src/mem/bump.rs b/src/mem/bump.rs index def5fef270dad68065445a78489af1f8d04f1d52..2d47afe1cebb3470749655d64e25c75889cb8e53 100644 --- a/src/mem/bump.rs +++ b/src/mem/bump.rs @@ -1,87 +1,60 @@ -use super::{map::Memmap, to_higher_half}; -use crate::{boot, error}; +use super::{ + pmm::{PageFrame, PageFrameAllocator}, + to_higher_half, +}; +use crate::error; use core::{ alloc::{GlobalAlloc, Layout}, ptr::null_mut, }; -use spin::{Mutex, Once}; - -// - -const MAX_BUMP_ALLOC: u64 = 2u64.pow(16); // 64KiB - -// - -pub fn init() { - let mut map = boot::memmap() - .min_by_key(|Memmap { len, .. }| *len) - .expect("No memory"); - - map.len = map.len.min(MAX_BUMP_ALLOC); - - ALLOC.inner.call_once(|| BumpAllocInner { - remaining: Mutex::new(map.len), - map, - }); -} - -pub fn map() -> Option<Memmap> { - ALLOC.inner.get().map(|i| i.map) -} +use spin::{Lazy, Mutex}; +use x86_64::{align_up, PhysAddr}; // #[global_allocator] -static ALLOC: BumpAllocator = BumpAllocator { inner: Once::new() }; +static ALLOC: BumpAllocator = BumpAllocator { + inner: Lazy::new(|| { + let pages = PageFrameAllocator::get().alloc(4); + BumpAllocInner { + marker: Mutex::new(pages.addr()), + pages, + } + }), +}; // struct BumpAllocator { - inner: Once<BumpAllocInner>, + inner: Lazy<BumpAllocInner>, } struct BumpAllocInner { - map: Memmap, - remaining: Mutex<u64>, + pages: PageFrame, + marker: Mutex<PhysAddr>, } // unsafe impl GlobalAlloc for BumpAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - let Some(inner) = self.inner.get() else { - error!("Allocator used before init"); - return null_mut(); - }; + let inner = &*self.inner; - let memory = inner.map.base; - let mut remaining = inner.remaining.lock(); + let pages = &inner.pages; + let mut marker = inner.marker.lock(); - let top = (memory + *remaining).as_u64(); - let Some(tmp) = top.checked_sub(layout.size() as u64) else { - error!("OUT OF MEMORY"); - error!( - "ALLOC: size: {} align: {} top: {top} memory: {memory:?} remaining: {remaining}", - layout.size(), - layout.align() - ); - return null_mut(); - }; - let new_top = tmp / layout.align() as u64 * layout.align() as u64; - let reservation = top - new_top; + let alloc_bottom = PhysAddr::new(align_up(marker.as_u64(), layout.align() as u64)); + let alloc_top = alloc_bottom + layout.size() as u64; - if let Some(left) = remaining.checked_sub(reservation) { - *remaining = left; - to_higher_half(memory + left).as_mut_ptr() - } else { - error!("OUT OF MEMORY"); - error!( - "ALLOC: size: {} align: {} top: {top} new: {new_top} memory: {memory:?} remaining: {remaining}", - layout.size(), - layout.align() - ); - null_mut() + if alloc_top > pages.addr() + pages.byte_len() as u64 { + error!("OOM"); + error!("layout: {layout:?} pages: {pages:?} marker: {marker:?}"); + return null_mut(); } + + *marker = alloc_top; + + to_higher_half(alloc_bottom).as_mut_ptr() } unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { diff --git a/src/mem/mod.rs b/src/mem/mod.rs index 55c7a3f3dc3a42710ecda7af5226cd3fc534c9fc..8892892183ad16d2753aa8fc5868345054fd213f 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -15,13 +15,6 @@ pub mod pmm; // -pub fn init() { - bump::init(); - pmm::init(); -} - -// - #[allow(unused)] fn is_higher_half(addr: u64) -> bool { addr >= boot::hhdm_offset() diff --git a/src/mem/pmm.rs b/src/mem/pmm.rs index cec1e49e095fa9e4d12f3a66f55d352cfcbc09ea..ef03e67b40aab9d6163bc72daa084e6d78fe27cc 100755 --- a/src/mem/pmm.rs +++ b/src/mem/pmm.rs @@ -1,15 +1,13 @@ use super::{map::Memmap, to_higher_half}; use crate::{ - boot, debug, - mem::bump, - trace, + boot, debug, trace, util::{bitmap::Bitmap, fmt::NumberPostfix}, }; use core::{ fmt, slice, sync::atomic::{AtomicU64, AtomicUsize, Ordering}, }; -use spin::{Mutex, Once}; +use spin::{Lazy, Mutex}; use x86_64::{align_up, PhysAddr}; // @@ -18,11 +16,11 @@ const PAGE_SIZE: u64 = 2u64.pow(12); // 4KiB pages // const PAGE_SIZE: u64 = 2u64.pow(21); // 2MiB pages -static PFA: Once<PageFrameAllocator> = Once::new(); +static PFA: Lazy<PageFrameAllocator> = Lazy::new(init); // -pub fn init() { +fn init() -> PageFrameAllocator { // usable system memory let usable: u64 = boot::memmap() .filter(Memmap::is_usable) @@ -61,11 +59,6 @@ pub fn init() { ty: _, } in boot::memmap().filter(Memmap::is_usable) { - if let Some(map) = bump::map() && map.base == base { - // skip the BumpAllocator spot - base += map.base.as_u64(); - len -= map.len; - } if base == bitmap_data { // skip the bitmap allocation spot base += bitmap_data.as_u64(); @@ -89,20 +82,18 @@ pub fn init() { } } - let used = bump::map().map(|Memmap { len, .. }| len).unwrap_or(0) + bitmap_size; - let pfa = PageFrameAllocator { bitmap: bitmap.into(), usable: usable.into(), - used: used.into(), + used: bitmap_size.into(), total: total.into(), last_alloc_index: 0.into(), }; - debug!("PFA:\n{pfa}"); + debug!("PFA initialized:\n{pfa}"); - PFA.call_once(|| pfa); + pfa } // @@ -126,6 +117,10 @@ pub struct PageFrame { // impl PageFrameAllocator { + pub fn get() -> &'static PageFrameAllocator { + &*PFA + } + /// System total memory in bytes pub fn total_mem(&self) -> u64 { self.total.load(Ordering::SeqCst) @@ -285,20 +280,46 @@ impl fmt::Display for PageFrameAllocator { } impl PageFrame { + // physical address of the first page pub fn addr(&self) -> PhysAddr { self.first } + + /// number of pages + pub fn len(&self) -> usize { + self.count + } + + /// number of bytes + pub fn byte_len(&self) -> usize { + self.count * PAGE_SIZE as usize + } + + pub fn as_bytes_mut(&mut self) -> &mut [u8] { + // SAFETY: &mut self makes sure that this is the only safe mut ref + unsafe { self.as_bytes_mut_unsafe() } + } + + pub fn as_bytes(&self) -> &[u8] { + // SAFETY: the mut ref is immediately downgraded to a const ref + unsafe { self.as_bytes_mut_unsafe() } + } + + /// SAFETY: only 1 mutable slice at one time + unsafe fn as_bytes_mut_unsafe(&self) -> &mut [u8] { + slice::from_raw_parts_mut(to_higher_half(self.first).as_mut_ptr(), self.byte_len()) + } } // #[cfg(test)] mod tests { - use crate::mem::pmm::PFA; + use super::PageFrameAllocator; #[test_case] fn pfa_simple() { - let pfa = PFA.get().unwrap(); + let pfa = PageFrameAllocator::get(); let a = pfa.alloc(1); assert_ne!(a.addr().as_u64(), 0); diff --git a/src/term/escape/decode.rs b/src/term/escape/decode.rs index d16c624fa2e45a139bb5943926195f577dc79cbb..4cd253b5b7118640a9e1fe318bd3a60d77c9a7ad 100644 --- a/src/term/escape/decode.rs +++ b/src/term/escape/decode.rs @@ -1,7 +1,7 @@ use crate::video::color::Color; -/// foreground color can be changed like this: "\x1B[38;2;<r>;<g>;<b>m" -/// background color can be changed like this: "\x1B[48;2;<r>;<g>;<b>m" +/// foreground color can be changed like this: `"\x1B[38;2;<r>;<g>;<b>m"` +/// background color can be changed like this: `"\x1B[48;2;<r>;<g>;<b>m"` /// /// THESE ARE NON STANDARD ESCAPE SEQUENCES pub struct EscapeDecoder { diff --git a/src/testfw.rs b/src/testfw.rs index a3179284f819ef5ec900a2875441e1fa3525411e..9685f7d756e3da3b6ee7badd3eae12809914e048 100644 --- a/src/testfw.rs +++ b/src/testfw.rs @@ -20,7 +20,7 @@ pub trait TestCase { impl<F: Fn()> TestCase for F { fn run(&self) { let name = type_name::<Self>(); - print!(" - {name:.<40}"); + print!(" - {name:.<60}"); self(); println!("[ok]"); } diff --git a/src/video/framebuffer.rs b/src/video/framebuffer.rs index ae4b93da18ea1265139b410e0cea890158d1e4b9..a781a279cccb786d1b00e77ef67c63653d440b06 100644 --- a/src/video/framebuffer.rs +++ b/src/video/framebuffer.rs @@ -1,15 +1,15 @@ use super::{color::Color, font::FONT}; -use core::ops::{Deref, DerefMut}; -use spin::{Mutex, MutexGuard, Once}; +use crate::boot; +use core::{ + fmt, + ops::{Deref, DerefMut}, +}; +use spin::{Lazy, Mutex, MutexGuard}; // -pub static FBO: Once<Mutex<Framebuffer>> = Once::new(); - -// - -pub fn get_fbo() -> Option<MutexGuard<'static, Framebuffer>> { - FBO.get().map(|mtx| mtx.lock()) +pub fn get() -> Option<MutexGuard<'static, Framebuffer>> { + FBO.as_ref().map(|mtx| mtx.lock()) } // @@ -29,6 +29,15 @@ pub struct FramebufferInfo { // +static FBO: Lazy<Option<Mutex<Framebuffer>>> = Lazy::new(|| { + let fbo = boot::framebuffer(); + let mut fbo = fbo?; + fbo.clear(); + Some(Mutex::new(fbo)) +}); + +// + impl Framebuffer { pub fn set(&mut self, x: usize, y: usize, color: Color) { let spot = x * 4 + y * self.pitch; @@ -91,18 +100,26 @@ impl DerefMut for Framebuffer { } } +impl fmt::Debug for Framebuffer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Framebuffer") + .field("info", &self.info) + .finish() + } +} + // #[cfg(test)] mod tests { - use super::get_fbo; + use super::get; use crate::video::color::Color; // #[test_case] fn fbo_draw() { - if let Some(mut fbo) = get_fbo() { + if let Some(mut fbo) = get() { fbo.fill(440, 340, 40, 40, Color::RED); fbo.fill(450, 350, 60, 40, Color::GREEN); fbo.fill(405, 315, 80, 20, Color::BLUE); diff --git a/src/video/logger.rs b/src/video/logger.rs index 75dcfc91416002b898e470fd3b7a74790b611f11..84ab28aa5c4a0080e1d7285d47425e955977e252 100644 --- a/src/video/logger.rs +++ b/src/video/logger.rs @@ -1,7 +1,7 @@ use super::{ color::Color, font::FONT, - framebuffer::{get_fbo, Framebuffer}, + framebuffer::{get, Framebuffer}, }; use crate::term::escape::decode::{DecodedPart, EscapeDecoder}; use core::fmt::{self, Arguments, Write}; @@ -39,7 +39,7 @@ impl Writer { pub fn write_byte(&mut self, byte: u8) { match self.escapes.next(byte) { DecodedPart::Byte(b'\n') => { - if let Some(mut fbo) = get_fbo() { + if let Some(mut fbo) = get() { #[cfg(debug_assertions)] let lines = if self.cursor[1] + 1 >= Self::size(&mut fbo)[1] { // scroll more if the cursor is near the bottom @@ -76,7 +76,7 @@ impl Writer { } pub fn write_byte_raw(&mut self, byte: u8) { - if let Some(mut fbo) = get_fbo() { + if let Some(mut fbo) = get() { let size = Self::size(&mut fbo); if size[0] == 0 || size[1] == 0 { return;