use core::fmt;
#[cfg(feature = "step_trait")]
use core::iter::Step;
use core::ops::{Index, IndexMut};
#[cfg(feature = "memory_encryption")]
use core::sync::atomic::{AtomicU64, Ordering};
use super::{PageSize, PhysFrame, Size4KiB};
use crate::addr::PhysAddr;
use bitflags::bitflags;
use dep_const_fn::const_fn;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FrameError {
FrameNotPresent,
HugeFrame,
}
#[cfg(feature = "memory_encryption")]
pub(crate) static PHYSICAL_ADDRESS_MASK: AtomicU64 = AtomicU64::new(0x000f_ffff_ffff_f000u64);
#[derive(Clone)]
#[repr(transparent)]
pub struct PageTableEntry {
entry: u64,
}
impl PageTableEntry {
#[inline]
pub const fn new() -> Self {
PageTableEntry { entry: 0 }
}
#[inline]
pub const fn is_unused(&self) -> bool {
self.entry == 0
}
#[inline]
pub fn set_unused(&mut self) {
self.entry = 0;
}
#[inline]
#[const_fn(cfg(not(feature = "memory_encryption")))]
pub const fn flags(&self) -> PageTableFlags {
PageTableFlags::from_bits_retain(self.entry & !Self::physical_address_mask())
}
#[inline]
pub fn addr(&self) -> PhysAddr {
PhysAddr::new(self.entry & Self::physical_address_mask())
}
#[inline]
pub fn frame(&self) -> Result<PhysFrame, FrameError> {
if !self.flags().contains(PageTableFlags::PRESENT) {
Err(FrameError::FrameNotPresent)
} else if self.flags().contains(PageTableFlags::HUGE_PAGE) {
Err(FrameError::HugeFrame)
} else {
Ok(PhysFrame::containing_address(self.addr()))
}
}
#[inline]
pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
assert!(addr.is_aligned(Size4KiB::SIZE));
self.entry = (addr.as_u64()) | flags.bits();
}
#[inline]
pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) {
assert!(!flags.contains(PageTableFlags::HUGE_PAGE));
self.set_addr(frame.start_address(), flags)
}
#[inline]
pub fn set_flags(&mut self, flags: PageTableFlags) {
self.entry = self.addr().as_u64() | flags.bits();
}
#[inline(always)]
#[cfg(not(feature = "memory_encryption"))]
const fn physical_address_mask() -> u64 {
0x000f_ffff_ffff_f000u64
}
#[inline(always)]
#[cfg(feature = "memory_encryption")]
fn physical_address_mask() -> u64 {
PHYSICAL_ADDRESS_MASK.load(Ordering::Relaxed)
}
}
impl Default for PageTableEntry {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for PageTableEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut f = f.debug_struct("PageTableEntry");
f.field("addr", &self.addr());
f.field("flags", &self.flags());
f.finish()
}
}
bitflags! {
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct PageTableFlags: u64 {
const PRESENT = 1;
const WRITABLE = 1 << 1;
const USER_ACCESSIBLE = 1 << 2;
const WRITE_THROUGH = 1 << 3;
const NO_CACHE = 1 << 4;
const ACCESSED = 1 << 5;
const DIRTY = 1 << 6;
const HUGE_PAGE = 1 << 7;
const GLOBAL = 1 << 8;
const BIT_9 = 1 << 9;
const BIT_10 = 1 << 10;
const BIT_11 = 1 << 11;
const BIT_52 = 1 << 52;
const BIT_53 = 1 << 53;
const BIT_54 = 1 << 54;
const BIT_55 = 1 << 55;
const BIT_56 = 1 << 56;
const BIT_57 = 1 << 57;
const BIT_58 = 1 << 58;
const BIT_59 = 1 << 59;
const BIT_60 = 1 << 60;
const BIT_61 = 1 << 61;
const BIT_62 = 1 << 62;
const NO_EXECUTE = 1 << 63;
}
}
const ENTRY_COUNT: usize = 512;
#[repr(align(4096))]
#[repr(C)]
#[derive(Clone)]
pub struct PageTable {
entries: [PageTableEntry; ENTRY_COUNT],
}
impl PageTable {
#[inline]
pub const fn new() -> Self {
const EMPTY: PageTableEntry = PageTableEntry::new();
PageTable {
entries: [EMPTY; ENTRY_COUNT],
}
}
#[inline]
pub fn zero(&mut self) {
for entry in self.iter_mut() {
entry.set_unused();
}
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &PageTableEntry> {
(0..512).map(move |i| &self.entries[i])
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PageTableEntry> {
let ptr = self.entries.as_mut_ptr();
(0..512).map(move |i| unsafe { &mut *ptr.add(i) })
}
#[inline]
pub fn is_empty(&self) -> bool {
self.iter().all(|entry| entry.is_unused())
}
}
impl Index<usize> for PageTable {
type Output = PageTableEntry;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.entries[index]
}
}
impl IndexMut<usize> for PageTable {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.entries[index]
}
}
impl Index<PageTableIndex> for PageTable {
type Output = PageTableEntry;
#[inline]
fn index(&self, index: PageTableIndex) -> &Self::Output {
&self.entries[usize::from(index)]
}
}
impl IndexMut<PageTableIndex> for PageTable {
#[inline]
fn index_mut(&mut self, index: PageTableIndex) -> &mut Self::Output {
&mut self.entries[usize::from(index)]
}
}
impl Default for PageTable {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for PageTable {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.entries[..].fmt(f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PageTableIndex(u16);
impl PageTableIndex {
#[inline]
pub const fn new(index: u16) -> Self {
assert!((index as usize) < ENTRY_COUNT);
Self(index)
}
#[inline]
pub const fn new_truncate(index: u16) -> Self {
Self(index % ENTRY_COUNT as u16)
}
#[inline]
pub(crate) const fn into_u64(self) -> u64 {
self.0 as u64
}
}
impl From<PageTableIndex> for u16 {
#[inline]
fn from(index: PageTableIndex) -> Self {
index.0
}
}
impl From<PageTableIndex> for u32 {
#[inline]
fn from(index: PageTableIndex) -> Self {
u32::from(index.0)
}
}
impl From<PageTableIndex> for u64 {
#[inline]
fn from(index: PageTableIndex) -> Self {
index.into_u64()
}
}
impl From<PageTableIndex> for usize {
#[inline]
fn from(index: PageTableIndex) -> Self {
usize::from(index.0)
}
}
#[cfg(feature = "step_trait")]
impl Step for PageTableIndex {
#[inline]
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
Step::steps_between(&start.0, &end.0)
}
#[inline]
fn forward_checked(start: Self, count: usize) -> Option<Self> {
let idx = usize::from(start).checked_add(count)?;
(idx < ENTRY_COUNT).then(|| Self::new(idx as u16))
}
#[inline]
fn backward_checked(start: Self, count: usize) -> Option<Self> {
let idx = usize::from(start).checked_sub(count)?;
Some(Self::new(idx as u16))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PageOffset(u16);
impl PageOffset {
#[inline]
pub fn new(offset: u16) -> Self {
assert!(offset < (1 << 12));
Self(offset)
}
#[inline]
pub const fn new_truncate(offset: u16) -> Self {
Self(offset % (1 << 12))
}
}
impl From<PageOffset> for u16 {
#[inline]
fn from(offset: PageOffset) -> Self {
offset.0
}
}
impl From<PageOffset> for u32 {
#[inline]
fn from(offset: PageOffset) -> Self {
u32::from(offset.0)
}
}
impl From<PageOffset> for u64 {
#[inline]
fn from(offset: PageOffset) -> Self {
u64::from(offset.0)
}
}
impl From<PageOffset> for usize {
#[inline]
fn from(offset: PageOffset) -> Self {
usize::from(offset.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PageTableLevel {
One = 1,
Two,
Three,
Four,
Five,
}
impl PageTableLevel {
pub const fn next_lower_level(self) -> Option<Self> {
match self {
PageTableLevel::Five => Some(PageTableLevel::Four),
PageTableLevel::Four => Some(PageTableLevel::Three),
PageTableLevel::Three => Some(PageTableLevel::Two),
PageTableLevel::Two => Some(PageTableLevel::One),
PageTableLevel::One => None,
}
}
pub const fn next_higher_level(self) -> Option<Self> {
match self {
PageTableLevel::Five => None,
PageTableLevel::Four => Some(PageTableLevel::Five),
PageTableLevel::Three => Some(PageTableLevel::Four),
PageTableLevel::Two => Some(PageTableLevel::Three),
PageTableLevel::One => Some(PageTableLevel::Two),
}
}
pub const fn table_address_space_alignment(self) -> u64 {
1u64 << (self as u8 * 9 + 12)
}
pub const fn entry_address_space_alignment(self) -> u64 {
1u64 << (((self as u8 - 1) * 9) + 12)
}
}