use core::fmt;
use memory_addr::PhysAddr;
use crate::{GenericPTE, MappingFlags};
bitflags::bitflags! {
#[derive(Debug)]
pub struct PTEFlags: usize {
const V = 1 << 0;
const R = 1 << 1;
const W = 1 << 2;
const X = 1 << 3;
const U = 1 << 4;
const G = 1 << 5;
const A = 1 << 6;
const D = 1 << 7;
}
}
impl From<PTEFlags> for MappingFlags {
fn from(f: PTEFlags) -> Self {
let mut ret = Self::empty();
if f.contains(PTEFlags::R) {
ret |= Self::READ;
}
if f.contains(PTEFlags::W) {
ret |= Self::WRITE;
}
if f.contains(PTEFlags::X) {
ret |= Self::EXECUTE;
}
if f.contains(PTEFlags::U) {
ret |= Self::USER;
}
ret
}
}
impl From<MappingFlags> for PTEFlags {
fn from(f: MappingFlags) -> Self {
if f.is_empty() {
return Self::empty();
}
let mut ret = Self::V;
if f.contains(MappingFlags::READ) {
ret |= Self::R;
}
if f.contains(MappingFlags::WRITE) {
ret |= Self::W;
}
if f.contains(MappingFlags::EXECUTE) {
ret |= Self::X;
}
if f.contains(MappingFlags::USER) {
ret |= Self::U;
}
ret
}
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Rv64PTE(u64);
impl Rv64PTE {
const PHYS_ADDR_MASK: u64 = (1 << 54) - (1 << 10); }
impl GenericPTE for Rv64PTE {
fn new_page(paddr: PhysAddr, flags: MappingFlags, _is_huge: bool) -> Self {
let flags = PTEFlags::from(flags) | PTEFlags::A | PTEFlags::D;
debug_assert!(flags.intersects(PTEFlags::R | PTEFlags::X));
Self(flags.bits() as u64 | ((paddr.as_usize() >> 2) as u64 & Self::PHYS_ADDR_MASK))
}
fn new_fault_page(_flags: MappingFlags, _is_huge: bool) -> Self {
let flags = PTEFlags::A | PTEFlags::D;
Self(flags.bits() as u64)
}
fn new_table(paddr: PhysAddr) -> Self {
Self(PTEFlags::V.bits() as u64 | ((paddr.as_usize() >> 2) as u64 & Self::PHYS_ADDR_MASK))
}
fn paddr(&self) -> PhysAddr {
PhysAddr::from(((self.0 & Self::PHYS_ADDR_MASK) << 2) as usize)
}
fn flags(&self) -> MappingFlags {
PTEFlags::from_bits_truncate(self.0 as usize).into()
}
fn set_paddr(&mut self, paddr: PhysAddr) {
self.0 = (self.0 & !Self::PHYS_ADDR_MASK)
| ((paddr.as_usize() as u64 >> 2) & Self::PHYS_ADDR_MASK);
}
fn set_flags(&mut self, flags: MappingFlags, _is_huge: bool) {
let flags = PTEFlags::from(flags) | PTEFlags::A | PTEFlags::D;
debug_assert!(flags.intersects(PTEFlags::R | PTEFlags::X));
self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits() as u64;
}
fn is_unused(&self) -> bool {
self.0 == 0
}
fn is_present(&self) -> bool {
PTEFlags::from_bits_truncate(self.0 as usize).contains(PTEFlags::V)
}
fn is_huge(&self) -> bool {
PTEFlags::from_bits_truncate(self.0 as usize).intersects(PTEFlags::R | PTEFlags::X)
}
fn clear(&mut self) {
self.0 = 0
}
}
impl fmt::Debug for Rv64PTE {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut f = f.debug_struct("Rv64PTE");
f.field("raw", &self.0)
.field("paddr", &self.paddr())
.field("flags", &self.flags())
.finish()
}
}