Add page flushing, add support for mapping anonymous pages
This commit is contained in:
+18
-15
@@ -13,6 +13,7 @@ use rmm::{
|
||||
PageMapper,
|
||||
PageTable,
|
||||
PhysicalAddress,
|
||||
VirtualAddress,
|
||||
};
|
||||
|
||||
use core::{
|
||||
@@ -178,17 +179,19 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
|
||||
|
||||
{
|
||||
// Map all physical areas at PHYS_OFFSET
|
||||
let mut mapper = PageMapper::<A, _>::new(
|
||||
let mut mapper = PageMapper::<A, _>::create(
|
||||
&mut bump_allocator
|
||||
).expect("failed to create Mapper");
|
||||
for area in areas.iter() {
|
||||
for i in 0..area.size / A::PAGE_SIZE {
|
||||
let phys = area.base.add(i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
mapper.map(
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
PageEntry::new(phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT)
|
||||
).expect("failed to map frame");
|
||||
phys,
|
||||
A::ENTRY_FLAG_WRITABLE
|
||||
).expect("failed to map page to frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,17 +214,17 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// for i in 0..16 {
|
||||
// let phys_opt = allocator.allocate(2 * MEGABYTE);
|
||||
// println!("2 MB page {}: {:X?}", i, phys_opt);
|
||||
// if i % 2 == 0 {
|
||||
// if let Some(phys) = phys_opt {
|
||||
// allocator.free(phys, 2 * MEGABYTE);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// println!("Remaining: {}", format_size(allocator.remaining()));
|
||||
|
||||
let mut mapper = PageMapper::<A, _>::current(
|
||||
&mut allocator
|
||||
);
|
||||
for i in 0..16 {
|
||||
let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE);
|
||||
let flush = mapper.map(
|
||||
virt,
|
||||
A::ENTRY_FLAG_USER | A::ENTRY_FLAG_WRITABLE
|
||||
).expect("failed to map page");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn inner<A: Arch>() {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Arch,
|
||||
VirtualAddress,
|
||||
};
|
||||
|
||||
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
|
||||
pub struct PageFlush<A> {
|
||||
virt: VirtualAddress,
|
||||
phantom: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<A: Arch> PageFlush<A> {
|
||||
pub fn new(virt: VirtualAddress) -> Self {
|
||||
Self {
|
||||
virt,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(self) {
|
||||
unsafe { A::invalidate(self.virt); }
|
||||
}
|
||||
|
||||
pub unsafe fn ignore(self) {
|
||||
mem::forget(self);
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
|
||||
pub struct PageFlushAll<A> {
|
||||
phantom: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl <A: Arch> PageFlushAll<A> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(&self, flush: PageFlush<A>) {
|
||||
unsafe { flush.ignore(); }
|
||||
}
|
||||
|
||||
pub fn flush(self) {
|
||||
unsafe { A::invalidate_all(); }
|
||||
}
|
||||
|
||||
pub unsafe fn ignore(self) {
|
||||
mem::forget(self);
|
||||
}
|
||||
}
|
||||
+26
-8
@@ -4,6 +4,7 @@ use crate::{
|
||||
Arch,
|
||||
FrameAllocator,
|
||||
PageEntry,
|
||||
PageFlush,
|
||||
PageTable,
|
||||
PhysicalAddress,
|
||||
VirtualAddress,
|
||||
@@ -16,13 +17,22 @@ pub struct PageMapper<'f, A, F> {
|
||||
}
|
||||
|
||||
impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
|
||||
pub unsafe fn new(allocator: &'f mut F) -> Option<Self> {
|
||||
let table_addr = allocator.allocate_one()?;
|
||||
Some(Self {
|
||||
pub unsafe fn new(table_addr: PhysicalAddress, allocator: &'f mut F) -> Self {
|
||||
Self {
|
||||
table_addr,
|
||||
allocator,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn create(allocator: &'f mut F) -> Option<Self> {
|
||||
let table_addr = allocator.allocate_one()?;
|
||||
Some(Self::new(table_addr, allocator))
|
||||
}
|
||||
|
||||
pub unsafe fn current(allocator: &'f mut F) -> Self {
|
||||
let table_addr = A::table();
|
||||
Self::new(table_addr, allocator)
|
||||
}
|
||||
|
||||
pub unsafe fn activate(&mut self) {
|
||||
@@ -37,22 +47,30 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn map(&mut self, virt: VirtualAddress, entry: PageEntry<A>) -> Option<()> {
|
||||
pub unsafe fn map(&mut self, virt: VirtualAddress, flags: usize) -> Option<PageFlush<A>> {
|
||||
let phys = self.allocator.allocate_one()?;
|
||||
self.map_phys(virt, phys, flags)
|
||||
}
|
||||
|
||||
pub unsafe fn map_phys(&mut self, virt: VirtualAddress, phys: PhysicalAddress, flags: usize) -> Option<PageFlush<A>> {
|
||||
//TODO: verify virt and phys are aligned
|
||||
//TODO: verify flags have correct bits
|
||||
let entry = PageEntry::new(phys.data() | flags | A::ENTRY_FLAG_PRESENT);
|
||||
let mut table = self.table();
|
||||
loop {
|
||||
let i = table.index_of(virt)?;
|
||||
if table.level() == 0 {
|
||||
//TODO: check for overwriting entry
|
||||
table.set_entry(i, entry);
|
||||
return Some(());
|
||||
return Some(PageFlush::new(virt));
|
||||
} else {
|
||||
let next_opt = table.next(i);
|
||||
let next = match next_opt {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
let phys = self.allocator.allocate_one()?;
|
||||
let next_phys = self.allocator.allocate_one()?;
|
||||
//TODO: correct flags?
|
||||
table.set_entry(i, PageEntry::new(phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT));
|
||||
table.set_entry(i, PageEntry::new(next_phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT));
|
||||
table.next(i)?
|
||||
}
|
||||
};
|
||||
|
||||
+5
-3
@@ -1,9 +1,11 @@
|
||||
pub use self::{
|
||||
entry::PageEntry,
|
||||
mapper::PageMapper,
|
||||
table::PageTable,
|
||||
entry::*,
|
||||
flush::*,
|
||||
mapper::*,
|
||||
table::*,
|
||||
};
|
||||
|
||||
mod entry;
|
||||
mod flush;
|
||||
mod mapper;
|
||||
mod table;
|
||||
|
||||
Reference in New Issue
Block a user