-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replaces the freelist-based page allocator and can be used for lifetime of kernel. Signed-off-by: Graham MacDonald <[email protected]>
- Loading branch information
Showing
8 changed files
with
376 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,73 @@ | ||
/// This module acts as an interface between the portable allocator and the | ||
/// arch-specific use of it. | ||
/// | ||
/// The page allocator is constructed and finalised in a number of phases: | ||
/// 1. `init_page_allocator` to create a fixed size allocator assuming everything | ||
/// is in use except a small number of statically defined pages available for | ||
/// setting up the initial page tables. | ||
/// 2. `free_unused_ranges` to mark available ranges as the inverse of the | ||
/// physical memory map within the bounds of the available memory. | ||
use crate::kmem; | ||
use crate::kmem::physaddr_as_ptr_mut; | ||
use crate::vm::Page4K; | ||
use core::ptr; | ||
use port::bitmapalloc::BitmapPageAlloc; | ||
use port::bitmapalloc::BitmapPageAllocError; | ||
use port::mem::PhysRange; | ||
use port::{ | ||
mcslock::{Lock, LockNode}, | ||
mem::PAGE_SIZE_4K, | ||
}; | ||
|
||
static FREE_LIST: Lock<FreeList> = Lock::new("kmem", FreeList { next: None }); | ||
/// Set up bitmap page allocator assuming everything is allocated. | ||
static PAGE_ALLOC: Lock<BitmapPageAlloc<16, PAGE_SIZE_4K>> = Lock::new( | ||
"page_alloc", | ||
const { BitmapPageAlloc::<16, PAGE_SIZE_4K>::new_all_allocated(PAGE_SIZE_4K) }, | ||
); | ||
|
||
#[repr(align(4096))] | ||
struct FreeList { | ||
next: Option<ptr::NonNull<FreeList>>, | ||
} | ||
unsafe impl Send for FreeList {} | ||
/// The bitmap allocator has all pages marked as allocated initially. We'll | ||
/// add some pages (mark free) to allow us to set up the page tables and build | ||
/// a memory map. Once the memory map has been build, we can mark all the unused | ||
/// space as available. This allows us to use only one page allocator throughout. | ||
pub fn init_page_allocator() { | ||
static mut NODE: LockNode = LockNode::new(); | ||
let mut lock = PAGE_ALLOC.lock(unsafe { &*ptr::addr_of!(NODE) }); | ||
let page_alloc = &mut *lock; | ||
|
||
#[derive(Debug)] | ||
pub enum Error { | ||
NoFreeBlocks, | ||
let early_pages_range = kmem::early_pages_range(); | ||
if let Err(err) = page_alloc.mark_free(&early_pages_range) { | ||
panic!("Couldn't mark early pages free: range: {} err: {:?}", early_pages_range, err); | ||
} | ||
} | ||
|
||
impl FreeList { | ||
pub fn put(&mut self, page: &mut Page4K) { | ||
let ptr = (page as *mut Page4K).addr(); | ||
assert_eq!(ptr % PAGE_SIZE_4K, 0, "freeing unaligned page"); | ||
page.scribble(); | ||
let f = page as *mut Page4K as *mut FreeList; | ||
unsafe { | ||
ptr::write(f, FreeList { next: self.next }); | ||
} | ||
self.next = ptr::NonNull::new(f); | ||
} | ||
/// Free unused pages in mem that aren't covered by the memory map. Assumes | ||
/// that custom_map is sorted. | ||
pub fn free_unused_ranges<'a>( | ||
available_mem: &PhysRange, | ||
used_ranges: impl Iterator<Item = &'a PhysRange>, | ||
) -> Result<(), BitmapPageAllocError> { | ||
static mut NODE: LockNode = LockNode::new(); | ||
let mut lock = PAGE_ALLOC.lock(unsafe { &*ptr::addr_of!(NODE) }); | ||
let page_alloc = &mut *lock; | ||
|
||
pub fn get(&mut self) -> Result<&'static mut Page4K, Error> { | ||
let mut next = self.next.ok_or(Error::NoFreeBlocks)?; | ||
let next = unsafe { next.as_mut() }; | ||
self.next = next.next; | ||
let pg = unsafe { &mut *(next as *mut FreeList as *mut Page4K) }; | ||
pg.clear(); | ||
Ok(pg) | ||
} | ||
page_alloc.free_unused_ranges(available_mem, used_ranges) | ||
} | ||
|
||
pub unsafe fn free_pages(pages: &mut [Page4K]) { | ||
/// Try to allocate a page | ||
pub fn allocate() -> Result<&'static mut Page4K, BitmapPageAllocError> { | ||
static mut NODE: LockNode = LockNode::new(); | ||
let mut lock = FREE_LIST.lock(unsafe { &*ptr::addr_of!(NODE) }); | ||
let fl = &mut *lock; | ||
for page in pages.iter_mut() { | ||
fl.put(page); | ||
let mut lock = PAGE_ALLOC.lock(unsafe { &NODE }); | ||
let page_alloc = &mut *lock; | ||
|
||
match page_alloc.allocate() { | ||
Ok(page_pa) => Ok(unsafe { &mut *physaddr_as_ptr_mut::<Page4K>(page_pa) }), | ||
Err(err) => Err(err), | ||
} | ||
} | ||
|
||
pub fn alloc() -> Result<&'static mut Page4K, Error> { | ||
pub fn usage_bytes() -> (usize, usize) { | ||
static mut NODE: LockNode = LockNode::new(); | ||
let mut lock = FREE_LIST.lock(unsafe { &*ptr::addr_of!(NODE) }); | ||
let fl = &mut *lock; | ||
fl.get() | ||
let mut lock = PAGE_ALLOC.lock(unsafe { &NODE }); | ||
let page_alloc = &mut *lock; | ||
page_alloc.usage_bytes() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.