Add remaining interfaces to user RMM for user mem.
This commit is contained in:
+8
-2
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user