-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b5448e6
commit 4ebc20f
Showing
5 changed files
with
90 additions
and
21 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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,53 @@ | ||
use self::stage1::Stage1; | ||
use self::stage2::Stage2; | ||
use core::alloc::{GlobalAlloc, Layout}; | ||
use core::ptr::{null_mut, NonNull}; | ||
use talc::{ClaimOnOom, Span, Talc}; | ||
use core::ptr::null_mut; | ||
use core::sync::atomic::{AtomicPtr, Ordering}; | ||
|
||
mod stage1; | ||
mod stage2; | ||
|
||
/// Implementation of [`GlobalAlloc`] for objects belong to kernel space. | ||
/// | ||
/// This allocator has 2 stages. The first stage will allocate a memory from a static buffer (AKA | ||
/// arena). This stage will be primary used for bootstrapping the kernel. The second stage will be | ||
/// activated once the required subsystems has been initialized. | ||
pub struct KernelHeap { | ||
stage1: spin::Mutex<Talc<ClaimOnOom>>, | ||
stage1: Stage1, | ||
stage2: AtomicPtr<Stage2>, | ||
} | ||
|
||
impl KernelHeap { | ||
/// # Safety | ||
/// The specified memory must be valid for reads and writes and it must be exclusively available | ||
/// to [`KernelHeap`]. | ||
pub const unsafe fn new(stage1: *mut u8, len: usize) -> Self { | ||
let stage1 = Talc::new(unsafe { ClaimOnOom::new(Span::from_base_size(stage1, len)) }); | ||
|
||
Self { | ||
stage1: spin::Mutex::new(stage1), | ||
stage1: Stage1::new(stage1, len), | ||
stage2: AtomicPtr::new(null_mut()), | ||
} | ||
} | ||
} | ||
|
||
unsafe impl GlobalAlloc for KernelHeap { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
// SAFETY: GlobalAlloc::alloc required layout to be non-zero. | ||
self.stage1 | ||
.lock() | ||
.malloc(layout) | ||
.map(|v| v.as_ptr()) | ||
.unwrap_or(null_mut()) | ||
let stage2 = self.stage2.load(Ordering::Relaxed); | ||
|
||
if stage2.is_null() { | ||
// SAFETY: GlobalAlloc::alloc required layout to be non-zero. | ||
self.stage1.alloc(layout) | ||
} else { | ||
todo!() | ||
} | ||
} | ||
|
||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | ||
// SAFETY: GlobalAlloc::dealloc required ptr to be the same one that returned from our | ||
// GlobalAlloc::alloc and layout to be the same one that passed to it. | ||
self.stage1.lock().free(NonNull::new_unchecked(ptr), layout); | ||
if self.stage1.is_owner(ptr) { | ||
// SAFETY: GlobalAlloc::dealloc required ptr to be the same one that returned from our | ||
// GlobalAlloc::alloc and layout to be the same one that passed to it. | ||
self.stage1.dealloc(ptr, layout); | ||
} else { | ||
todo!() | ||
} | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use core::alloc::Layout; | ||
use core::ptr::{null_mut, NonNull}; | ||
use talc::{ClaimOnOom, Span, Talc}; | ||
|
||
/// Stage 1 kernel heap. | ||
/// | ||
/// This stage allocate a memory from a static buffer (AKA arena). | ||
pub struct Stage1 { | ||
engine: spin::Mutex<Talc<ClaimOnOom>>, | ||
buf_ptr: *const u8, | ||
buf_end: *const u8, | ||
} | ||
|
||
impl Stage1 { | ||
/// # Safety | ||
/// The specified memory must be valid for reads and writes and it must be exclusively available | ||
/// to [`Stage1`]. | ||
pub const unsafe fn new(buf: *mut u8, len: usize) -> Self { | ||
let engine = Talc::new(ClaimOnOom::new(Span::from_base_size(buf, len))); | ||
|
||
Self { | ||
engine: spin::Mutex::new(engine), | ||
buf_ptr: buf, | ||
buf_end: buf.add(len), | ||
} | ||
} | ||
|
||
pub fn is_owner(&self, ptr: *const u8) -> bool { | ||
ptr >= self.buf_ptr && ptr < self.buf_end | ||
} | ||
|
||
/// The returned pointer will always within the buffer that was specified in the | ||
/// [`Self::new()`]. | ||
/// | ||
/// # Safety | ||
/// `layout` must be nonzero. | ||
pub unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
self.engine | ||
.lock() | ||
.malloc(layout) | ||
.map(|v| v.as_ptr()) | ||
.unwrap_or(null_mut()) | ||
} | ||
|
||
/// # Safety | ||
/// `ptr` must be obtained with [`Self::alloc()`] and `layout` must be the same one that was | ||
/// passed to that method. | ||
pub unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { | ||
self.engine.lock().free(NonNull::new_unchecked(ptr), layout); | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/// Stage 2 kernel heap. | ||
/// | ||
/// This stage allocate a memory from a virtual memory management system. | ||
pub struct Stage2 {} |