diff --git a/src/memory/bump.rs b/src/memory/bump.rs index 16c837783595c343eb389be8c843c85ec6b4ec4f..6453b108a511122ce9206ba791cce00d98b2c2bb 100644 --- a/src/memory/bump.rs +++ b/src/memory/bump.rs @@ -1,4 +1,4 @@ -//! # Area frame allocator +//! # Bump frame allocator //! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/allocating-frames.html) use paging::PhysicalAddress; @@ -15,8 +15,8 @@ pub struct BumpAllocator { } impl BumpAllocator { - pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> BumpAllocator { - let mut allocator = BumpAllocator { + pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> Self { + let mut allocator = Self { next_free_frame: Frame::containing_address(PhysicalAddress::new(0)), current_area: None, areas: memory_areas, @@ -43,6 +43,8 @@ impl BumpAllocator { } impl FrameAllocator for BumpAllocator { + fn set_noncore(&mut self, noncore: bool) {} + fn free_frames(&self) -> usize { let mut count = 0; diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 01216b18906e639064da236b74ea7d48917b297e..fb4275bdb45401622dd3d85c48a62e0aac0c272a 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -4,10 +4,12 @@ pub use paging::{PAGE_SIZE, PhysicalAddress}; use self::bump::BumpAllocator; +use self::recycle::RecycleAllocator; use spin::Mutex; pub mod bump; +pub mod recycle; /// The current memory map. It's size is maxed out to 512 entries, due to it being /// from 0x500 to 0x5000 (800 is the absolute total) @@ -64,7 +66,7 @@ impl Iterator for MemoryAreaIter { } } -static ALLOCATOR: Mutex<Option<BumpAllocator>> = Mutex::new(None); +static ALLOCATOR: Mutex<Option<RecycleAllocator<BumpAllocator>>> = Mutex::new(None); /// Init memory module /// Must be called once, and only once, @@ -77,7 +79,17 @@ pub unsafe fn init(kernel_start: usize, kernel_end: usize) { } } - *ALLOCATOR.lock() = Some(BumpAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE))); + *ALLOCATOR.lock() = Some(RecycleAllocator::new(BumpAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE)))); +} + +/// Init memory module after core +/// Must be called once, and only once, +pub unsafe fn init_noncore() { + if let Some(ref mut allocator) = *ALLOCATOR.lock() { + allocator.set_noncore(true) + } else { + panic!("frame allocator not initialized"); + } } /// Get the number of frames available @@ -172,6 +184,7 @@ impl Iterator for FrameIter { } pub trait FrameAllocator { + fn set_noncore(&mut self, noncore: bool); fn free_frames(&self) -> usize; fn used_frames(&self) -> usize; fn allocate_frames(&mut self, size: usize) -> Option<Frame>; diff --git a/src/memory/recycle.rs b/src/memory/recycle.rs new file mode 100644 index 0000000000000000000000000000000000000000..34af97e208ef5008cbab50d22aa08ea5dffbb8a4 --- /dev/null +++ b/src/memory/recycle.rs @@ -0,0 +1,126 @@ +//! Recycle allocator +//! Uses freed frames if possible, then uses inner allocator + +use collections::Vec; + +use paging::PhysicalAddress; + +use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter}; + +pub struct RecycleAllocator<T: FrameAllocator> { + inner: T, + noncore: bool, + free: Vec<(usize, usize)>, +} + +impl<T: FrameAllocator> RecycleAllocator<T> { + pub fn new(inner: T) -> Self { + Self { + inner: inner, + noncore: false, + free: Vec::new(), + } + } + + fn free_count(&self) -> usize { + let mut count = 0; + for free in self.free.iter() { + count += free.1; + } + println!("Free count: {} in {} entries", count, self.free.len()); + count + } + + fn merge(&mut self, address: usize, count: usize) -> bool { + for i in 0 .. self.free.len() { + let changed = { + let mut free = &mut self.free[i]; + if address + count * 4096 == free.0 { + free.0 = address; + free.1 += count; + true + } else if free.0 + free.1 * 4096 == address { + free.1 += count; + true + } else { + false + } + }; + + if changed { + //TODO: Use do not use recursion + let (address, count) = self.free[i]; + if self.merge(address, count) { + self.free.remove(i); + } + return true; + } + } + + false + } +} + +impl<T: FrameAllocator> FrameAllocator for RecycleAllocator<T> { + fn set_noncore(&mut self, noncore: bool) { + self.noncore = noncore; + } + + fn free_frames(&self) -> usize { + self.inner.free_frames() + self.free_count() + } + + fn used_frames(&self) -> usize { + self.inner.used_frames() - self.free_count() + } + + fn allocate_frames(&mut self, count: usize) -> Option<Frame> { + if count == 1 { + if ! self.free.is_empty() { + let mut i = 0; + { + let mut small = self.free[i]; + for j in 1..self.free.len() { + let free = self.free[j]; + // Later entries can be removed faster + if free.1 <= small.1 { + i = j; + small = free; + } + } + } + + let (address, remove) = { + let free = &mut self.free[i]; + free.1 -= 1; + (free.0 + free.1 * 4096, free.1 == 0) + }; + + if remove { + self.free.remove(i); + } + + //println!("Restoring frame {:?}, {}", frame, count); + Some(Frame::containing_address(PhysicalAddress::new(address))) + } else { + //println!("No saved frames {}", count); + self.inner.allocate_frames(count) + } + } else { + println!("Could not restore frame {}", count); + self.inner.allocate_frames(count) + } + } + + fn deallocate_frames(&mut self, frame: Frame, count: usize) { + if self.noncore { + let address = frame.start_address().get(); + if ! self.merge(address, count) { + self.free.push((address, count)); + } + } else { + println!("Could not save frame {:?}, {}", frame, count); + self.inner.deallocate_frames(frame, count); + } + } +} diff --git a/src/start.rs b/src/start.rs index 4a42dfa8e2b254561e991f2d735bde634cab9590..2bf9f59102cc1f149c66168cf25a479db12b6565 100644 --- a/src/start.rs +++ b/src/start.rs @@ -123,6 +123,9 @@ pub unsafe extern fn kstart() -> ! { // Initialize all of the non-core devices not otherwise needed to complete initialization device::init_noncore(); + // Initialize memory functions after core has loaded + memory::init_noncore(); + BSP_READY.store(true, Ordering::SeqCst); }