a96ea6f5f3
Before this commit, RMM assumed base physical address was presented in PTE as is, i.e. physical page address was shifted exactly to PAGE_SHIFT, so physical address can be extracted from PTE by simply masking off some bits and can be placed in PTE by simple addition/OR. This is not the case for RISC-V which has 4Kb base page so 12 bits PAGE_SHIFT, yet physical page address is only shifted 10 bits in PTE. This commit removes this assumption. NOTE: This commit changes meaning of constants: * ENTRY_ADDRESS_SIZE from "total physical size in bytes" to "total physical size in PAGES" * ENTRY_ADDRESS_MASK from "mask of physical bits in PTE" to "mask of physical bits starting at bit 0"
60 lines
1.4 KiB
Rust
60 lines
1.4 KiB
Rust
use core::marker::PhantomData;
|
|
|
|
use crate::{Arch, PageFlags, PhysicalAddress};
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct PageEntry<A> {
|
|
data: usize,
|
|
phantom: PhantomData<A>,
|
|
}
|
|
|
|
impl<A: Arch> PageEntry<A> {
|
|
#[inline(always)]
|
|
pub fn new(address: usize, flags: usize) -> Self {
|
|
let data = (((address >> A::PAGE_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::ENTRY_ADDRESS_SHIFT)
|
|
| flags;
|
|
Self::from_data(data)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn from_data(data: usize) -> Self {
|
|
Self {
|
|
data,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn data(&self) -> usize {
|
|
self.data
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn address(&self) -> Result<PhysicalAddress, PhysicalAddress> {
|
|
let addr = PhysicalAddress(
|
|
((self.data >> A::ENTRY_ADDRESS_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::PAGE_SHIFT,
|
|
);
|
|
|
|
if self.present() {
|
|
Ok(addr)
|
|
} else {
|
|
Err(addr)
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn flags(&self) -> PageFlags<A> {
|
|
unsafe { PageFlags::from_data(self.data & A::ENTRY_FLAGS_MASK) }
|
|
}
|
|
#[inline(always)]
|
|
pub fn set_flags(&mut self, flags: PageFlags<A>) {
|
|
self.data &= !A::ENTRY_FLAGS_MASK;
|
|
self.data |= flags.data();
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn present(&self) -> bool {
|
|
self.data & A::ENTRY_FLAG_PRESENT != 0
|
|
}
|
|
}
|