maint: sync up other architectures with mmap(file)
This commit is contained in:
@@ -6,7 +6,7 @@ use core::{
|
||||
use libk_mm_interface::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
pointer::PhysicalRefMut,
|
||||
process::ProcessAddressSpaceManager,
|
||||
process::{PageAttributeUpdate, ProcessAddressSpaceManager},
|
||||
table::{
|
||||
EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator,
|
||||
},
|
||||
@@ -70,7 +70,15 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error> {
|
||||
unsafe fn update_page_attributes(
|
||||
&mut self,
|
||||
address: usize,
|
||||
update: &PageAttributeUpdate,
|
||||
) -> Result<(), Error> {
|
||||
self.update_l3_entry(address, |entry| entry.update(update))
|
||||
}
|
||||
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error> {
|
||||
self.pop_l3_entry(address)
|
||||
}
|
||||
|
||||
@@ -118,7 +126,11 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_l3_entry(&mut self, virt: usize) -> Result<PhysicalAddress, Error> {
|
||||
fn update_l3_entry<F: FnOnce(&mut PageEntry<L3>) -> Result<(), Error>>(
|
||||
&mut self,
|
||||
virt: usize,
|
||||
mapper: F,
|
||||
) -> Result<(), Error> {
|
||||
let l1i = virt.page_index::<L1>();
|
||||
let l2i = virt.page_index::<L2>();
|
||||
let l3i = virt.page_index::<L3>();
|
||||
@@ -127,12 +139,33 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
|
||||
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
|
||||
|
||||
let page = l3[l3i].as_page().ok_or(Error::DoesNotExist)?;
|
||||
let entry = &mut l3[l3i];
|
||||
if !entry.is_present() {
|
||||
return Err(Error::DoesNotExist);
|
||||
}
|
||||
mapper(entry)?;
|
||||
super::tlb_flush_va_asid(virt, self.asid as usize);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop_l3_entry(&mut self, virt: usize) -> Result<(PhysicalAddress, bool), Error> {
|
||||
let l1i = virt.page_index::<L1>();
|
||||
let l2i = virt.page_index::<L2>();
|
||||
let l3i = virt.page_index::<L3>();
|
||||
|
||||
// TODO somehow drop tables if they're known to be empty?
|
||||
let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
|
||||
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
|
||||
|
||||
let entry = l3[l3i];
|
||||
let page = entry.as_page().ok_or(Error::DoesNotExist)?;
|
||||
let dirty = entry.is_dirty();
|
||||
|
||||
l3[l3i] = PageEntry::INVALID;
|
||||
super::tlb_flush_va_asid(virt, self.asid as usize);
|
||||
|
||||
Ok(page)
|
||||
Ok((page, dirty))
|
||||
}
|
||||
|
||||
fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> {
|
||||
@@ -178,6 +211,9 @@ fn to_page_attributes(src: MapAttributes) -> PageAttributes {
|
||||
if src.intersects(MapAttributes::USER_READ | MapAttributes::USER_WRITE) {
|
||||
result |= PageAttributes::U;
|
||||
}
|
||||
if src.contains(MapAttributes::DIRTY) {
|
||||
result |= PageAttributes::SW_DIRTY;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -192,5 +228,9 @@ fn to_map_attributes(src: PageAttributes) -> MapAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
if src.contains(PageAttributes::SW_DIRTY) {
|
||||
result |= MapAttributes::DIRTY;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use core::{
|
||||
use libk_mm_interface::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
process::PageAttributeUpdate,
|
||||
table::{
|
||||
page_index, EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel,
|
||||
TableAllocator,
|
||||
@@ -88,6 +89,8 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
}
|
||||
|
||||
impl<L: EntryLevel> PageEntry<L> {
|
||||
// Upper + lower 10 bits
|
||||
const ATTR_MASK: u64 = 0xFFC00000000003FF;
|
||||
pub const INVALID: Self = Self(0, PhantomData);
|
||||
|
||||
/// Constructs a [PageEntry] from its raw representation.
|
||||
@@ -103,6 +106,23 @@ impl<L: EntryLevel> PageEntry<L> {
|
||||
self.0 & PageAttributes::V.bits() != 0
|
||||
}
|
||||
|
||||
pub fn update(&mut self, update: &PageAttributeUpdate) -> Result<(), Error> {
|
||||
let mut attrs = self.attributes();
|
||||
if let Some(write) = update.user_write {
|
||||
attrs.set(PageAttributes::W, write);
|
||||
}
|
||||
if let Some(dirty) = update.dirty {
|
||||
attrs.set(PageAttributes::SW_DIRTY, dirty);
|
||||
}
|
||||
self.0 &= !Self::ATTR_MASK;
|
||||
self.0 |= attrs.bits() & Self::ATTR_MASK;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub const fn is_dirty(&self) -> bool {
|
||||
self.0 & PageAttributes::SW_DIRTY.bits() != 0
|
||||
}
|
||||
|
||||
pub fn attributes(self) -> PageAttributes {
|
||||
PageAttributes::from_bits_retain(self.0)
|
||||
}
|
||||
@@ -211,7 +231,7 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
|
||||
& (PageAttributes::R | PageAttributes::W | PageAttributes::X | PageAttributes::V)
|
||||
.bits()
|
||||
== PageAttributes::V.bits())
|
||||
.then_some((self.0 << 2) & !0xFFF)
|
||||
.then_some((self.0 & !Self::ATTR_MASK) << 2)
|
||||
.map(PhysicalAddress::from_u64)
|
||||
}
|
||||
}
|
||||
@@ -232,7 +252,7 @@ impl PageEntry<L3> {
|
||||
|
||||
pub fn as_page(&self) -> Option<PhysicalAddress> {
|
||||
(self.0 & PageAttributes::V.bits() != 0)
|
||||
.then_some((self.0 << 2) & !0xFFF)
|
||||
.then_some((self.0 & !Self::ATTR_MASK) << 2)
|
||||
.map(PhysicalAddress::from_u64)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user