Skip to content
Snippets Groups Projects
Commit efb06c42 authored by Eemeli Lehtonen's avatar Eemeli Lehtonen
Browse files

refactoring + lazier

parent c455a80b
No related branches found
No related tags found
No related merge requests found
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);
}
}
use crate::env::Arguments;
use limine::LimineKernelFileRequest; use limine::LimineKernelFileRequest;
// //
pub fn init() { pub fn cmdline() -> Option<&'static str> {
static REQ: LimineKernelFileRequest = LimineKernelFileRequest::new(0); static REQ: LimineKernelFileRequest = LimineKernelFileRequest::new(0);
REQ.get_response()
if let Some(cmdline) = REQ
.get_response()
.get() .get()
.and_then(|resp| resp.kernel_file.get()) .and_then(|resp| resp.kernel_file.get())
.and_then(|file| file.cmdline.to_str()) .and_then(|file| file.cmdline.to_str())
.and_then(|cmdline| cmdline.to_str().ok()) .and_then(|cmdline| cmdline.to_str().ok())
{
Arguments::parse(cmdline);
}
} }
use crate::{ use crate::{
debug, debug,
video::framebuffer::{get_fbo, Framebuffer, FramebufferInfo, FBO}, video::framebuffer::{Framebuffer, FramebufferInfo},
}; };
use core::slice; use core::slice;
use limine::LimineFramebufferRequest; use limine::LimineFramebufferRequest;
use spin::Mutex;
// //
pub fn init() { pub fn framebuffer() -> Option<Framebuffer> {
static FB_REQ: LimineFramebufferRequest = LimineFramebufferRequest::new(0); static FB_REQ: LimineFramebufferRequest = LimineFramebufferRequest::new(0);
let fbo = FB_REQ FB_REQ
.get_response() .get_response()
.get() .get()
.into_iter() .into_iter()
...@@ -22,6 +21,7 @@ pub fn init() { ...@@ -22,6 +21,7 @@ pub fn init() {
} }
let buf = unsafe { slice::from_raw_parts_mut(fb.address.as_ptr()?, fb.size()) }; let buf = unsafe { slice::from_raw_parts_mut(fb.address.as_ptr()?, fb.size()) };
Some(Framebuffer { Some(Framebuffer {
buf, buf,
info: FramebufferInfo { info: FramebufferInfo {
...@@ -30,11 +30,5 @@ pub fn init() { ...@@ -30,11 +30,5 @@ pub fn init() {
pitch: fb.pitch as _, 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))
} }
use super::args;
use super::BOOT_NAME; use super::BOOT_NAME;
use crate::{arch, kernel_main}; use crate::{arch, kernel_main};
...@@ -6,6 +7,8 @@ use crate::{arch, kernel_main}; ...@@ -6,6 +7,8 @@ use crate::{arch, kernel_main};
pub use addr::hhdm_offset; pub use addr::hhdm_offset;
pub use addr::phys_addr; pub use addr::phys_addr;
pub use addr::virt_addr; pub use addr::virt_addr;
pub use cmdline::cmdline;
pub use framebuffer::framebuffer;
pub use mem::memmap; pub use mem::memmap;
pub use term::_print; pub use term::_print;
...@@ -24,8 +27,7 @@ mod term; ...@@ -24,8 +27,7 @@ mod term;
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
BOOT_NAME.call_once(|| "Limine"); BOOT_NAME.call_once(|| "Limine");
framebuffer::init(); args::get().apply();
cmdline::init();
arch::early_boot_cpu(); arch::early_boot_cpu();
arch::early_per_cpu(); arch::early_per_cpu();
......
...@@ -2,6 +2,10 @@ use spin::Once; ...@@ -2,6 +2,10 @@ use spin::Once;
// //
pub use boot::*;
//
#[cfg(feature = "multiboot1")] #[cfg(feature = "multiboot1")]
#[path = "multiboot1/mod.rs"] #[path = "multiboot1/mod.rs"]
#[allow(clippy::module_inception)] #[allow(clippy::module_inception)]
...@@ -19,9 +23,7 @@ mod boot; ...@@ -19,9 +23,7 @@ mod boot;
#[allow(clippy::module_inception)] #[allow(clippy::module_inception)]
mod boot; mod boot;
// pub mod args;
pub use boot::*;
// //
......
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();
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#![feature(let_chains)] #![feature(let_chains)]
#![test_runner(crate::testfw::test_runner)] #![test_runner(crate::testfw::test_runner)]
#![reexport_test_harness_main = "test_main"] #![reexport_test_harness_main = "test_main"]
#![doc = include_str!("../README.md")]
// //
...@@ -47,17 +48,25 @@ pub static KERNEL_VERS: &str = env!("CARGO_PKG_VERSION"); ...@@ -47,17 +48,25 @@ pub static KERNEL_VERS: &str = env!("CARGO_PKG_VERSION");
// the actual entry exists in [´crate::boot::boot´] // the actual entry exists in [´crate::boot::boot´]
fn kernel_main() -> ! { fn kernel_main() -> ! {
let args = boot::args::get();
args.apply();
debug!("Entering kernel_main"); debug!("Entering kernel_main");
debug!("Cmdline: {:?}", env::Arguments::get()); debug!("Cmdline: {args:?}");
debug!( debug!(
"Kernel addr: {:?}, {:?}, HDDM Offset: {:#0X?}", "Kernel addr: {:?}, {:?}, HHDM Offset: {:#0X?}",
boot::virt_addr(), boot::virt_addr(),
boot::phys_addr(), boot::phys_addr(),
boot::hhdm_offset() 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 // ofc. every kernel has to have this cringy ascii name splash
info!("\n{}\n", include_str!("./splash")); info!("\n{}\n", include_str!("./splash"));
......
use super::{map::Memmap, to_higher_half}; use super::{
use crate::{boot, error}; pmm::{PageFrame, PageFrameAllocator},
to_higher_half,
};
use crate::error;
use core::{ use core::{
alloc::{GlobalAlloc, Layout}, alloc::{GlobalAlloc, Layout},
ptr::null_mut, ptr::null_mut,
}; };
use spin::{Mutex, Once}; use spin::{Lazy, Mutex};
use x86_64::{align_up, PhysAddr};
//
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)
}
// //
#[global_allocator] #[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 { struct BumpAllocator {
inner: Once<BumpAllocInner>, inner: Lazy<BumpAllocInner>,
} }
struct BumpAllocInner { struct BumpAllocInner {
map: Memmap, pages: PageFrame,
remaining: Mutex<u64>, marker: Mutex<PhysAddr>,
} }
// //
unsafe impl GlobalAlloc for BumpAllocator { unsafe impl GlobalAlloc for BumpAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let Some(inner) = self.inner.get() else { let inner = &*self.inner;
error!("Allocator used before init");
return null_mut();
};
let memory = inner.map.base; let pages = &inner.pages;
let mut remaining = inner.remaining.lock(); let mut marker = inner.marker.lock();
let top = (memory + *remaining).as_u64(); let alloc_bottom = PhysAddr::new(align_up(marker.as_u64(), layout.align() as u64));
let Some(tmp) = top.checked_sub(layout.size() as u64) else { let alloc_top = alloc_bottom + layout.size() as u64;
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;
if let Some(left) = remaining.checked_sub(reservation) { if alloc_top > pages.addr() + pages.byte_len() as u64 {
*remaining = left; error!("OOM");
to_higher_half(memory + left).as_mut_ptr() error!("layout: {layout:?} pages: {pages:?} marker: {marker:?}");
} else { return null_mut();
error!("OUT OF MEMORY");
error!(
"ALLOC: size: {} align: {} top: {top} new: {new_top} memory: {memory:?} remaining: {remaining}",
layout.size(),
layout.align()
);
null_mut()
} }
*marker = alloc_top;
to_higher_half(alloc_bottom).as_mut_ptr()
} }
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
......
...@@ -15,13 +15,6 @@ pub mod pmm; ...@@ -15,13 +15,6 @@ pub mod pmm;
// //
pub fn init() {
bump::init();
pmm::init();
}
//
#[allow(unused)] #[allow(unused)]
fn is_higher_half(addr: u64) -> bool { fn is_higher_half(addr: u64) -> bool {
addr >= boot::hhdm_offset() addr >= boot::hhdm_offset()
......
use super::{map::Memmap, to_higher_half}; use super::{map::Memmap, to_higher_half};
use crate::{ use crate::{
boot, debug, boot, debug, trace,
mem::bump,
trace,
util::{bitmap::Bitmap, fmt::NumberPostfix}, util::{bitmap::Bitmap, fmt::NumberPostfix},
}; };
use core::{ use core::{
fmt, slice, fmt, slice,
sync::atomic::{AtomicU64, AtomicUsize, Ordering}, sync::atomic::{AtomicU64, AtomicUsize, Ordering},
}; };
use spin::{Mutex, Once}; use spin::{Lazy, Mutex};
use x86_64::{align_up, PhysAddr}; use x86_64::{align_up, PhysAddr};
// //
...@@ -18,11 +16,11 @@ const PAGE_SIZE: u64 = 2u64.pow(12); // 4KiB pages ...@@ -18,11 +16,11 @@ const PAGE_SIZE: u64 = 2u64.pow(12); // 4KiB pages
// const PAGE_SIZE: u64 = 2u64.pow(21); // 2MiB 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 // usable system memory
let usable: u64 = boot::memmap() let usable: u64 = boot::memmap()
.filter(Memmap::is_usable) .filter(Memmap::is_usable)
...@@ -61,11 +59,6 @@ pub fn init() { ...@@ -61,11 +59,6 @@ pub fn init() {
ty: _, ty: _,
} in boot::memmap().filter(Memmap::is_usable) } 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 { if base == bitmap_data {
// skip the bitmap allocation spot // skip the bitmap allocation spot
base += bitmap_data.as_u64(); base += bitmap_data.as_u64();
...@@ -89,20 +82,18 @@ pub fn init() { ...@@ -89,20 +82,18 @@ pub fn init() {
} }
} }
let used = bump::map().map(|Memmap { len, .. }| len).unwrap_or(0) + bitmap_size;
let pfa = PageFrameAllocator { let pfa = PageFrameAllocator {
bitmap: bitmap.into(), bitmap: bitmap.into(),
usable: usable.into(), usable: usable.into(),
used: used.into(), used: bitmap_size.into(),
total: total.into(), total: total.into(),
last_alloc_index: 0.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 { ...@@ -126,6 +117,10 @@ pub struct PageFrame {
// //
impl PageFrameAllocator { impl PageFrameAllocator {
pub fn get() -> &'static PageFrameAllocator {
&*PFA
}
/// System total memory in bytes /// System total memory in bytes
pub fn total_mem(&self) -> u64 { pub fn total_mem(&self) -> u64 {
self.total.load(Ordering::SeqCst) self.total.load(Ordering::SeqCst)
...@@ -285,20 +280,46 @@ impl fmt::Display for PageFrameAllocator { ...@@ -285,20 +280,46 @@ impl fmt::Display for PageFrameAllocator {
} }
impl PageFrame { impl PageFrame {
// physical address of the first page
pub fn addr(&self) -> PhysAddr { pub fn addr(&self) -> PhysAddr {
self.first 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)] #[cfg(test)]
mod tests { mod tests {
use crate::mem::pmm::PFA; use super::PageFrameAllocator;
#[test_case] #[test_case]
fn pfa_simple() { fn pfa_simple() {
let pfa = PFA.get().unwrap(); let pfa = PageFrameAllocator::get();
let a = pfa.alloc(1); let a = pfa.alloc(1);
assert_ne!(a.addr().as_u64(), 0); assert_ne!(a.addr().as_u64(), 0);
......
use crate::video::color::Color; use crate::video::color::Color;
/// foreground color can be changed like this: "\x1B[38;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" /// background color can be changed like this: `"\x1B[48;2;<r>;<g>;<b>m"`
/// ///
/// THESE ARE NON STANDARD ESCAPE SEQUENCES /// THESE ARE NON STANDARD ESCAPE SEQUENCES
pub struct EscapeDecoder { pub struct EscapeDecoder {
......
...@@ -20,7 +20,7 @@ pub trait TestCase { ...@@ -20,7 +20,7 @@ pub trait TestCase {
impl<F: Fn()> TestCase for F { impl<F: Fn()> TestCase for F {
fn run(&self) { fn run(&self) {
let name = type_name::<Self>(); let name = type_name::<Self>();
print!(" - {name:.<40}"); print!(" - {name:.<60}");
self(); self();
println!("[ok]"); println!("[ok]");
} }
......
use super::{color::Color, font::FONT}; use super::{color::Color, font::FONT};
use core::ops::{Deref, DerefMut}; use crate::boot;
use spin::{Mutex, MutexGuard, Once}; use core::{
fmt,
ops::{Deref, DerefMut},
};
use spin::{Lazy, Mutex, MutexGuard};
// //
pub static FBO: Once<Mutex<Framebuffer>> = Once::new(); pub fn get() -> Option<MutexGuard<'static, Framebuffer>> {
FBO.as_ref().map(|mtx| mtx.lock())
//
pub fn get_fbo() -> Option<MutexGuard<'static, Framebuffer>> {
FBO.get().map(|mtx| mtx.lock())
} }
// //
...@@ -29,6 +29,15 @@ pub struct FramebufferInfo { ...@@ -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 { impl Framebuffer {
pub fn set(&mut self, x: usize, y: usize, color: Color) { pub fn set(&mut self, x: usize, y: usize, color: Color) {
let spot = x * 4 + y * self.pitch; let spot = x * 4 + y * self.pitch;
...@@ -91,18 +100,26 @@ impl DerefMut for Framebuffer { ...@@ -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)] #[cfg(test)]
mod tests { mod tests {
use super::get_fbo; use super::get;
use crate::video::color::Color; use crate::video::color::Color;
// //
#[test_case] #[test_case]
fn fbo_draw() { 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(440, 340, 40, 40, Color::RED);
fbo.fill(450, 350, 60, 40, Color::GREEN); fbo.fill(450, 350, 60, 40, Color::GREEN);
fbo.fill(405, 315, 80, 20, Color::BLUE); fbo.fill(405, 315, 80, 20, Color::BLUE);
......
use super::{ use super::{
color::Color, color::Color,
font::FONT, font::FONT,
framebuffer::{get_fbo, Framebuffer}, framebuffer::{get, Framebuffer},
}; };
use crate::term::escape::decode::{DecodedPart, EscapeDecoder}; use crate::term::escape::decode::{DecodedPart, EscapeDecoder};
use core::fmt::{self, Arguments, Write}; use core::fmt::{self, Arguments, Write};
...@@ -39,7 +39,7 @@ impl Writer { ...@@ -39,7 +39,7 @@ impl Writer {
pub fn write_byte(&mut self, byte: u8) { pub fn write_byte(&mut self, byte: u8) {
match self.escapes.next(byte) { match self.escapes.next(byte) {
DecodedPart::Byte(b'\n') => { DecodedPart::Byte(b'\n') => {
if let Some(mut fbo) = get_fbo() { if let Some(mut fbo) = get() {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let lines = if self.cursor[1] + 1 >= Self::size(&mut fbo)[1] { let lines = if self.cursor[1] + 1 >= Self::size(&mut fbo)[1] {
// scroll more if the cursor is near the bottom // scroll more if the cursor is near the bottom
...@@ -76,7 +76,7 @@ impl Writer { ...@@ -76,7 +76,7 @@ impl Writer {
} }
pub fn write_byte_raw(&mut self, byte: u8) { 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); let size = Self::size(&mut fbo);
if size[0] == 0 || size[1] == 0 { if size[0] == 0 || size[1] == 0 {
return; return;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment