mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-25 18:33:24 +00:00
Use the HUGE/PAT bit to track the validity of x86 PTEs
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
b269118c9a
commit
dc7e0d7a63
@ -161,7 +161,9 @@ impl PageTableCreator {
|
|||||||
}
|
}
|
||||||
let pt = unsafe { &mut *(pde.paddr() as *mut Ia32eTable) };
|
let pt = unsafe { &mut *(pde.paddr() as *mut Ia32eTable) };
|
||||||
let pte = pt.index(1, from.addr());
|
let pte = pt.index(1, from.addr());
|
||||||
pte.update(to.addr(), flags);
|
// In level-1 PTE, the HUGE bit is the PAT bit (page attribute table).
|
||||||
|
// We use it as the "valid" bit for the page table entry.
|
||||||
|
pte.update(to.addr(), flags | Ia32eFlags::HUGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nr_frames_used(&self) -> usize {
|
pub fn nr_frames_used(&self) -> usize {
|
||||||
|
@ -53,7 +53,10 @@ bitflags::bitflags! {
|
|||||||
const ACCESSED = 1 << 5;
|
const ACCESSED = 1 << 5;
|
||||||
/// Whether the memory area represented by this entry is modified.
|
/// Whether the memory area represented by this entry is modified.
|
||||||
const DIRTY = 1 << 6;
|
const DIRTY = 1 << 6;
|
||||||
/// Only in the non-starting and non-ending levels, indication of huge page.
|
/// In level 2 or 3 it indicates that it map to a huge page.
|
||||||
|
/// In level 1, it is the PAT (page attribute table) bit.
|
||||||
|
/// We use this bit in level 1, 2 and 3 to indicate that this entry is
|
||||||
|
/// "valid". For levels above 3, `PRESENT` is used for "valid".
|
||||||
const HUGE = 1 << 7;
|
const HUGE = 1 << 7;
|
||||||
/// Indicates that the mapping is present in all address spaces, so it isn't flushed from
|
/// Indicates that the mapping is present in all address spaces, so it isn't flushed from
|
||||||
/// the TLB on an address space switch.
|
/// the TLB on an address space switch.
|
||||||
@ -156,14 +159,15 @@ macro_rules! parse_flags {
|
|||||||
|
|
||||||
impl PageTableEntryTrait for PageTableEntry {
|
impl PageTableEntryTrait for PageTableEntry {
|
||||||
fn is_present(&self) -> bool {
|
fn is_present(&self) -> bool {
|
||||||
self.0 & PageTableFlags::PRESENT.bits() != 0
|
// For PT child, `PRESENT` should be set; for huge page, `HUGE` should
|
||||||
|
// be set; for the leaf child page, `PAT`, which is the same bit as
|
||||||
|
// the `HUGE` bit in upper levels, should be set.
|
||||||
|
self.0 & PageTableFlags::PRESENT.bits() != 0 || self.0 & PageTableFlags::HUGE.bits() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self {
|
fn new_page(paddr: Paddr, _level: PagingLevel, prop: PageProperty) -> Self {
|
||||||
let mut pte = Self(
|
let flags = PageTableFlags::HUGE.bits();
|
||||||
paddr & Self::PHYS_ADDR_MASK
|
let mut pte = Self(paddr & Self::PHYS_ADDR_MASK | flags);
|
||||||
| ((level != 1) as usize) << PageTableFlags::HUGE.bits().ilog2(),
|
|
||||||
);
|
|
||||||
pte.set_prop(prop);
|
pte.set_prop(prop);
|
||||||
pte
|
pte
|
||||||
}
|
}
|
||||||
@ -209,8 +213,12 @@ impl PageTableEntryTrait for PageTableEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_prop(&mut self, prop: PageProperty) {
|
fn set_prop(&mut self, prop: PageProperty) {
|
||||||
let mut flags = PageTableFlags::PRESENT.bits();
|
if !self.is_present() {
|
||||||
flags |= parse_flags!(prop.flags.bits(), PageFlags::W, PageTableFlags::WRITABLE)
|
return;
|
||||||
|
}
|
||||||
|
let mut flags = PageTableFlags::empty().bits();
|
||||||
|
flags |= parse_flags!(prop.flags.bits(), PageFlags::R, PageTableFlags::PRESENT)
|
||||||
|
| parse_flags!(prop.flags.bits(), PageFlags::W, PageTableFlags::WRITABLE)
|
||||||
| parse_flags!(!prop.flags.bits(), PageFlags::X, PageTableFlags::NO_EXECUTE)
|
| parse_flags!(!prop.flags.bits(), PageFlags::X, PageTableFlags::NO_EXECUTE)
|
||||||
| parse_flags!(
|
| parse_flags!(
|
||||||
prop.flags.bits(),
|
prop.flags.bits(),
|
||||||
@ -249,8 +257,8 @@ impl PageTableEntryTrait for PageTableEntry {
|
|||||||
self.0 = self.0 & !Self::PROP_MASK | flags;
|
self.0 = self.0 & !Self::PROP_MASK | flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_last(&self, level: PagingLevel) -> bool {
|
fn is_last(&self, _level: PagingLevel) -> bool {
|
||||||
level == 1 || (self.0 & PageTableFlags::HUGE.bits() != 0)
|
self.0 & PageTableFlags::HUGE.bits() != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,6 +327,10 @@ pub trait PageTableEntryTrait: Clone + Copy + Debug + Default + Pod + Sized + Sy
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// If the flags are present with valid mappings.
|
/// If the flags are present with valid mappings.
|
||||||
|
///
|
||||||
|
/// For PTEs created by [`Self::new_absent`], this method should return
|
||||||
|
/// false. And for PTEs created by [`Self::new_page`] or [`Self::new_pt`]
|
||||||
|
/// and modified with [`Self::set_prop`] this method should return true.
|
||||||
fn is_present(&self) -> bool;
|
fn is_present(&self) -> bool;
|
||||||
|
|
||||||
/// Create a new PTE with the given physical address and flags that map to a page.
|
/// Create a new PTE with the given physical address and flags that map to a page.
|
||||||
@ -343,6 +347,10 @@ pub trait PageTableEntryTrait: Clone + Copy + Debug + Default + Pod + Sized + Sy
|
|||||||
|
|
||||||
fn prop(&self) -> PageProperty;
|
fn prop(&self) -> PageProperty;
|
||||||
|
|
||||||
|
/// Set the page property of the PTE.
|
||||||
|
///
|
||||||
|
/// This will be only done if the PTE is present. If not, this method will
|
||||||
|
/// do nothing.
|
||||||
fn set_prop(&mut self, prop: PageProperty);
|
fn set_prop(&mut self, prop: PageProperty);
|
||||||
|
|
||||||
/// If the PTE maps a page rather than a child page table.
|
/// If the PTE maps a page rather than a child page table.
|
||||||
|
@ -57,9 +57,6 @@ where
|
|||||||
/// Operates on the mapping properties of the entry.
|
/// Operates on the mapping properties of the entry.
|
||||||
///
|
///
|
||||||
/// It only modifies the properties if the entry is present.
|
/// It only modifies the properties if the entry is present.
|
||||||
// FIXME: in x86_64, you can protect a page with neither of the RWX
|
|
||||||
// permissions. This would make the page not accessible and leaked. Such a
|
|
||||||
// behavior is memory-safe but wrong. In RISC-V there's no problem.
|
|
||||||
pub(in crate::mm) fn protect(&mut self, op: &mut impl FnMut(&mut PageProperty)) {
|
pub(in crate::mm) fn protect(&mut self, op: &mut impl FnMut(&mut PageProperty)) {
|
||||||
if !self.pte.is_present() {
|
if !self.pte.is_present() {
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user