use core::fmt;
use memory_addr::PhysAddr;
pub use x86_64::structures::paging::page_table::PageTableFlags as PTF;
use crate::{GenericPTE, MappingFlags};
impl From<PTF> for MappingFlags {
fn from(f: PTF) -> Self {
if f.is_empty() {
return Self::empty();
}
let mut ret = Self::READ;
if f.contains(PTF::WRITABLE) {
ret |= Self::WRITE;
}
if !f.contains(PTF::NO_EXECUTE) {
ret |= Self::EXECUTE;
}
if f.contains(PTF::USER_ACCESSIBLE) {
ret |= Self::USER;
}
if f.contains(PTF::NO_CACHE) {
ret |= Self::UNCACHED;
}
ret
}
}
impl From<MappingFlags> for PTF {
fn from(f: MappingFlags) -> Self {
if f.is_empty() {
return Self::empty();
}
let mut ret = Self::PRESENT;
if f.contains(MappingFlags::WRITE) {
ret |= Self::WRITABLE;
}
if !f.contains(MappingFlags::EXECUTE) {
ret |= Self::NO_EXECUTE;
}
if f.contains(MappingFlags::USER) {
ret |= Self::USER_ACCESSIBLE;
}
if f.contains(MappingFlags::DEVICE) || f.contains(MappingFlags::UNCACHED) {
ret |= Self::NO_CACHE | Self::WRITE_THROUGH;
}
ret
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct X64PTE(u64);
impl X64PTE {
const PHYS_ADDR_MASK: u64 = 0x000f_ffff_ffff_f000; }
impl GenericPTE for X64PTE {
fn new_page(paddr: PhysAddr, flags: MappingFlags, is_huge: bool) -> Self {
let mut flags = PTF::from(flags);
if is_huge {
flags |= PTF::HUGE_PAGE;
}
Self(flags.bits() | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK))
}
fn new_fault_page(_flags: MappingFlags, _is_huge: bool) -> Self {
let flags = PTF::ACCESSED | PTF::DIRTY | PTF::NO_EXECUTE;
Self(flags.bits())
}
fn new_table(paddr: PhysAddr) -> Self {
let flags = PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE;
Self(flags.bits() | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK))
}
fn paddr(&self) -> PhysAddr {
PhysAddr::from((self.0 & Self::PHYS_ADDR_MASK) as usize)
}
fn flags(&self) -> MappingFlags {
PTF::from_bits_truncate(self.0).into()
}
fn set_paddr(&mut self, paddr: PhysAddr) {
self.0 = (self.0 & !Self::PHYS_ADDR_MASK) | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK)
}
fn set_flags(&mut self, flags: MappingFlags, is_huge: bool) {
let mut flags = PTF::from(flags);
if is_huge {
flags |= PTF::HUGE_PAGE;
}
self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits()
}
fn is_unused(&self) -> bool {
self.0 == 0
}
fn is_present(&self) -> bool {
PTF::from_bits_truncate(self.0).contains(PTF::PRESENT)
}
fn is_huge(&self) -> bool {
PTF::from_bits_truncate(self.0).contains(PTF::HUGE_PAGE)
}
fn clear(&mut self) {
self.0 = 0
}
}
impl fmt::Debug for X64PTE {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut f = f.debug_struct("X64PTE");
f.field("raw", &self.0)
.field("paddr", &self.paddr())
.field("flags", &self.flags())
.finish()
}
}