diff --git a/Cargo.toml b/Cargo.toml index 409a68a..7250624 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,16 +6,22 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["arch_riscv64", "board_virt", "log_color"] +default = ["arch_riscv64", "board_virt", "log_color", "frame_freelist"] + arch_riscv64 = [] arch_riscv32 = [] arch_arm = [] arch_x86 = [] + board_default = [] board_virt = [] board_thead = [] + log_color = [] +frame_bitmap = [] +frame_freelist = [] + [profile.dev] panic = "abort" diff --git a/src/mm/addr.rs b/src/mm/addr.rs index 6583f50..f757d0d 100644 --- a/src/mm/addr.rs +++ b/src/mm/addr.rs @@ -1,5 +1,6 @@ use core::fmt::{Debug, Display, Formatter, LowerHex, Result, UpperHex}; use core::hash::Hash; +use core::num::NonZeroUsize; use core::ops::{Add, AddAssign, Sub, SubAssign}; #[inline(always)] @@ -12,14 +13,17 @@ fn align_down(addr: usize, align: usize) -> usize { addr & !(align - 1) } +#[derive(Copy, Clone)] pub struct PhysAddr(pub usize); +#[derive(Copy, Clone)] pub struct VirtAddr(pub usize); pub trait AddressOps { fn as_u32(&self) -> u32; fn as_u64(&self) -> u64; fn as_usize(&self) -> usize; + fn as_non_zero_usize(&self) -> Option; fn align_up(&self, align: T) -> Self where T: Into; @@ -51,6 +55,10 @@ impl AddressOps for PhysAddr { self.0 } + fn as_non_zero_usize(&self) -> Option { + NonZeroUsize::new(self.0) + } + fn align_up(&self, align: T) -> Self where T: Into, @@ -79,6 +87,10 @@ impl AddressOps for VirtAddr { self.0 } + fn as_non_zero_usize(&self) -> Option { + NonZeroUsize::new(self.0) + } + fn align_up(&self, align: T) -> Self where T: Into, @@ -162,6 +174,18 @@ impl From for usize { } } +impl From for PhysAddr { + fn from(addr: NonZeroUsize) -> Self { + PhysAddr(addr.get()) + } +} + +impl From for NonZeroUsize { + fn from(addr: PhysAddr) -> Self { + NonZeroUsize::new(addr.0).unwrap() + } +} + impl From for VirtAddr { fn from(addr: usize) -> Self { VirtAddr(addr) @@ -174,6 +198,18 @@ impl From for usize { } } +impl From for VirtAddr { + fn from(addr: NonZeroUsize) -> Self { + VirtAddr(addr.get()) + } +} + +impl From for NonZeroUsize { + fn from(addr: VirtAddr) -> Self { + NonZeroUsize::new(addr.0).unwrap() + } +} + impl Debug for PhysAddr { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "PhysAddr({:#x})", self.0) diff --git a/src/mm/frame.rs b/src/mm/frame.rs index 8784708..bf53c3e 100644 --- a/src/mm/frame.rs +++ b/src/mm/frame.rs @@ -1,31 +1,78 @@ +#[allow(unused_imports)] +use lazy_static::lazy_static; +use log::trace; use spin::mutex::SpinMutex; use crate::arch::layout::*; use crate::mm::addr::{AddressOps, PhysAddr}; +#[allow(unused_imports)] use crate::mm::bitmap::{Bitmap1K, BitmapOps}; +#[allow(unused_imports)] +use crate::mm::freelist::FreeList; -// TODO: allow to switch allocator between `BitmapXX` and `FreeList` // 1k * 4k = 4MB, currently enough for kernel data +#[cfg(feature = "frame_bitmap")] static ALLOCATOR: SpinMutex = SpinMutex::new(Bitmap1K::DEFAULT); -pub trait FrameOps { - fn alloc(&self) -> Option; - fn dealloc(&self, addr: PhysAddr); +#[cfg(feature = "frame_freelist")] +lazy_static! { + static ref ALLOCATOR: SpinMutex = { + let mut list = FreeList::new(); + + for i in 0..1024 { + let addr = PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START); + list.push(addr.into()); + } + + SpinMutex::new(list) + }; } pub struct FrameAllocator; -impl FrameOps for FrameAllocator { - fn alloc(&self) -> Option { - ALLOCATOR - .lock() - .alloc() - .map(|i| PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START)) +impl FrameAllocator { + pub fn alloc(&self) -> Option { + #[cfg(feature = "frame_bitmap")] + let addr = crate::mm::frame::ALLOCATOR.lock().alloc().map(|i| { + crate::mm::addr::PhysAddr( + (i * crate::arch::arch::mm::page::PAGE_SIZE) + + crate::arch::arch::layout::KERNEL_MEM_START, + ) + }); + + #[cfg(feature = "frame_freelist")] + let addr = ALLOCATOR.lock().pop().map(|addr| addr.into()); + + trace!("[mm/frame] alloc frame: {:?}", addr); + fill_mem(addr, 0xaa); + + addr } - fn dealloc(&self, addr: PhysAddr) { - ALLOCATOR - .lock() - .dealloc((addr.as_usize() - KERNEL_MEM_START) / PAGE_SIZE); + pub fn dealloc(&self, addr: PhysAddr) { + debug_assert!(addr.is_aligned(PAGE_SIZE)); + debug_assert!(addr.as_usize() >= KERNEL_MEM_START); + + trace!("[mm/frame] dealloc frame: {:?}", addr); + fill_mem(Some(addr), 0x55); + + #[cfg(feature = "frame_bitmap")] + crate::mm::frame::ALLOCATOR.lock().dealloc( + (addr.as_usize() - crate::arch::arch::layout::KERNEL_MEM_START) + / crate::arch::arch::mm::page::PAGE_SIZE, + ); + + #[cfg(feature = "frame_freelist")] + ALLOCATOR.lock().push(addr.into()); + } +} + +fn fill_mem(addr: Option, val: u8) { + #[cfg(debug_assertions)] + unsafe { + // fill with junks + if let Some(addr) = addr { + core::ptr::write_bytes(addr.as_usize() as *mut u8, val, PAGE_SIZE); + } } } diff --git a/src/mm/freelist.rs b/src/mm/freelist.rs new file mode 100644 index 0000000..f92116f --- /dev/null +++ b/src/mm/freelist.rs @@ -0,0 +1,29 @@ +use core::num::NonZeroUsize; + +pub struct FreeList { + next: Option, +} + +impl FreeList { + pub const fn new() -> Self { + Self { next: None } + } + + pub fn push(&mut self, ptr: NonZeroUsize) { + unsafe { + let raw: *mut usize = ptr.get() as *mut usize; + *raw = self.next.map_or(0, |next| next.get()); + } + self.next = Some(ptr); + } + + pub fn pop(&mut self) -> Option { + let popped = self.next.take(); + if let Some(next) = popped { + let raw: *const usize = next.get() as *const usize; + self.next = NonZeroUsize::new(unsafe { *raw }); + } + + popped + } +} diff --git a/src/mm/mod.rs b/src/mm/mod.rs index dd55013..20dd779 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -1,4 +1,5 @@ pub mod addr; mod bitmap; pub mod frame; +mod freelist; pub mod page;