Add remaining interfaces to user RMM for user mem.

This commit is contained in:
4lDO2
2022-07-17 14:05:33 +02:00
parent efc67a2012
commit 229ae5da40
4 changed files with 89 additions and 34 deletions
+8 -2
View File
@@ -24,8 +24,14 @@ impl<A: Arch> PageEntry<A> {
}
#[inline(always)]
pub fn address(&self) -> PhysicalAddress {
PhysicalAddress(self.data & A::ENTRY_ADDRESS_MASK)
pub fn address(&self) -> Result<PhysicalAddress, PhysicalAddress> {
let addr = PhysicalAddress(self.data & A::ENTRY_ADDRESS_MASK);
if self.present() {
Ok(addr)
} else {
Err(addr)
}
}
#[inline(always)]
+6 -2
View File
@@ -111,7 +111,11 @@ impl<A: Arch> PageFlags<A> {
impl<A: Arch> fmt::Debug for PageFlags<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PageFlags")
.field("data", &self.data)
.field("present", &self.has_present())
.field("write", &self.has_write())
.field("executable", &self.has_execute())
.field("user", &self.has_user())
.field("bits", &format_args!("{:#0x}", self.data))
.finish()
}
}
}
+67 -20
View File
@@ -8,44 +8,61 @@ use crate::{
PageFlush,
PageTable,
PhysicalAddress,
TableKind,
VirtualAddress,
};
pub struct PageMapper<'f, A, F> {
pub struct PageMapper<A, F> {
table_addr: PhysicalAddress,
allocator: &'f mut F,
phantom: PhantomData<A>,
allocator: F,
_phantom: PhantomData<fn() -> A>,
}
impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
pub unsafe fn new(table_addr: PhysicalAddress, allocator: &'f mut F) -> Self {
impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
pub unsafe fn new(table_addr: PhysicalAddress, allocator: F) -> Self {
Self {
table_addr,
allocator,
phantom: PhantomData,
_phantom: PhantomData,
}
}
pub unsafe fn create(allocator: &'f mut F) -> Option<Self> {
pub unsafe fn create(mut allocator: F) -> Option<Self> {
let table_addr = allocator.allocate_one()?;
Some(Self::new(table_addr, allocator))
}
pub unsafe fn current(allocator: &'f mut F) -> Self {
pub unsafe fn current(allocator: F) -> Self {
let table_addr = A::table();
Self::new(table_addr, allocator)
}
pub fn is_current(&self) -> bool {
unsafe { self.table().phys() == A::table() }
}
pub unsafe fn make_current(&mut self) {
pub unsafe fn make_current(&self) {
A::set_table(self.table_addr);
}
pub unsafe fn table(&self) -> PageTable<A> {
PageTable::new(
VirtualAddress::new(0),
self.table_addr,
A::PAGE_LEVELS - 1
)
pub fn table(&self) -> PageTable<A> {
// SAFETY: The only way to initialize a PageMapper is via new(), and we assume it upholds
// all necessary invariants for this to be safe.
unsafe {
PageTable::new(
VirtualAddress::new(0),
self.table_addr,
A::PAGE_LEVELS - 1
)
}
}
pub unsafe fn remap(&mut self, virt: VirtualAddress, flags: PageFlags<A>) -> Option<PageFlush<A>> {
self.visit(virt, |p1, i| {
let mut entry = p1.entry(i)?;
entry.set_flags(flags);
p1.set_entry(i, entry);
Some(PageFlush::new(virt))
}).flatten()
}
pub unsafe fn map(&mut self, virt: VirtualAddress, flags: PageFlags<A>) -> Option<PageFlush<A>> {
@@ -71,7 +88,8 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
None => {
let next_phys = self.allocator.allocate_one()?;
//TODO: correct flags?
table.set_entry(i, PageEntry::new(next_phys.data() | A::ENTRY_FLAG_READWRITE | A::ENTRY_FLAG_DEFAULT_TABLE));
let flags = A::ENTRY_FLAG_READWRITE | A::ENTRY_FLAG_DEFAULT_TABLE | if virt.kind() == TableKind::User { A::ENTRY_FLAG_USER } else { 0 };
table.set_entry(i, PageEntry::new(next_phys.data() | flags));
table.next(i)?
}
};
@@ -79,14 +97,35 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
}
}
}
pub unsafe fn map_linearly(&mut self, phys: PhysicalAddress, flags: PageFlags<A>) -> Option<(VirtualAddress, PageFlush<A>)> {
let virt = A::phys_to_virt(phys);
self.map_phys(virt, phys, flags).map(|flush| (virt, flush))
}
fn visit<T>(&self, virt: VirtualAddress, f: impl FnOnce(&mut PageTable<A>, usize) -> T) -> Option<T> {
let mut table = self.table();
unsafe {
loop {
let i = table.index_of(virt)?;
if table.level() == 0 {
return Some(f(&mut table, i));
} else {
table = table.next(i)?;
}
}
}
}
pub fn translate(&self, virt: VirtualAddress) -> Option<(PhysicalAddress, PageFlags<A>)> {
let entry = self.visit(virt, |p1, i| unsafe { p1.entry(i) })??;
Some((entry.address().ok()?, entry.flags()))
}
pub unsafe fn unmap(&mut self, virt: VirtualAddress) -> Option<PageFlush<A>> {
let (old, flush) = self.unmap_phys(virt)?;
self.allocator.free_one(old.address());
let (old, _, flush) = self.unmap_phys(virt)?;
self.allocator.free_one(old);
Some(flush)
}
pub unsafe fn unmap_phys(&mut self, virt: VirtualAddress) -> Option<(PageEntry<A>, PageFlush<A>)> {
pub unsafe fn unmap_phys(&mut self, virt: VirtualAddress) -> Option<(PhysicalAddress, PageFlags<A>, PageFlush<A>)> {
//TODO: verify virt is aligned
let mut table = self.table();
//TODO: unmap parents
@@ -96,10 +135,18 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
let entry_opt = table.entry(i);
table.set_entry(i, PageEntry::new(0));
let entry = entry_opt?;
return Some((entry, PageFlush::new(virt)));
return Some((entry.address().ok()?, entry.flags(), PageFlush::new(virt)));
} else {
table = table.next(i)?;
}
}
}
}
impl<A, F: core::fmt::Debug> core::fmt::Debug for PageMapper<A, F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PageMapper")
.field("frame", &self.table_addr)
.field("allocator", &self.allocator)
.finish()
}
}
+8 -10
View File
@@ -93,16 +93,14 @@ impl<A: Arch> PageTable<A> {
}
pub unsafe fn next(&self, i: usize) -> Option<Self> {
if self.level > 0 {
let entry = self.entry(i)?;
if entry.present() {
return Some(PageTable::new(
self.entry_base(i)?,
entry.address(),
self.level - 1
));
}
if self.level == 0 {
return None;
}
None
Some(PageTable::new(
self.entry_base(i)?,
self.entry(i)?.address().ok()?,
self.level - 1,
))
}
}