|
|
@ -0,0 +1,75 @@ |
|
|
|
use arch::x86_64::memory::{Frame, FrameAllocator};
|
|
|
|
use super::{Page, Table, ActivePageTable};
|
|
|
|
use super::table::{Level1, Level4};
|
|
|
|
use super::{VirtualAddress};
|
|
|
|
|
|
|
|
pub struct TemporaryPage {
|
|
|
|
page: Page,
|
|
|
|
allocator: TinyAllocator,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TemporaryPage {
|
|
|
|
pub fn new<A>(page: Page, allocator: &mut A) -> TemporaryPage
|
|
|
|
where A: FrameAllocator {
|
|
|
|
TemporaryPage {
|
|
|
|
page: page,
|
|
|
|
allocator: TinyAllocator::new(allocator),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Maps the temporary page to the given frame, using the active table.
|
|
|
|
/// Returns the start address of the temporary page in VRAM.
|
|
|
|
pub fn map(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> VirtualAddress {
|
|
|
|
use super::entry::WRITABLE;
|
|
|
|
|
|
|
|
assert!(active_table.page_to_frame(self.page).is_none(),
|
|
|
|
"Temporary page is already mapped!");
|
|
|
|
active_table.map_to(self.page, frame, WRITABLE, &mut self.allocator);
|
|
|
|
|
|
|
|
self.page.start_address()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Maps the temporary page to the given page table frame, using the active table.
|
|
|
|
/// Returns a &mut reference to the now-mapped table.
|
|
|
|
pub fn map_table_frame(&mut self, frame: Frame, active_table: &mut ActivePageTable)
|
|
|
|
-> &mut Table<Level1> {
|
|
|
|
unsafe { &mut *(self.map(frame, active_table) as *mut Table<Level1>) }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unmap(&mut self, active_table: &mut ActivePageTable) {
|
|
|
|
active_table.unmap(self.page, &mut self.allocator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A tiny frame allocator which can only hold three frames,
|
|
|
|
/// used to temporarily create a P3, P2, and P1 table.
|
|
|
|
struct TinyAllocator([Option<Frame>; 3]);
|
|
|
|
impl TinyAllocator {
|
|
|
|
fn new<A>(allocator: &mut A) -> TinyAllocator
|
|
|
|
where A: FrameAllocator{
|
|
|
|
let mut f = || allocator.alloc_frame();
|
|
|
|
let frames = [f(), f(), f()];
|
|
|
|
TinyAllocator(frames)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl FrameAllocator for TinyAllocator {
|
|
|
|
fn alloc_frame(&mut self) -> Option<Frame> {
|
|
|
|
for frame in &mut self.0 {
|
|
|
|
if frame.is_some() {
|
|
|
|
return frame.take();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dealloc_frame(&mut self, frame: Frame) {
|
|
|
|
for stored_frame in &mut self.0 {
|
|
|
|
if stored_frame.is_none() {
|
|
|
|
*stored_frame = Some(frame);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic!("TinyAllocator can only hold 3 frames!");
|
|
|
|
}
|
|
|
|
}
|