use crate::{mask, VmMeta};
use core::{
fmt,
marker::PhantomData,
ops::{Add, AddAssign, Range},
};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct PageNumber<Meta: VmMeta, S: Space>(usize, PhantomData<Meta>, PhantomData<S>);
pub trait Space: Clone + Copy + PartialEq + Eq + PartialOrd + Ord + fmt::Debug {}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Physical;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Virtual;
impl Space for Physical {}
impl Space for Virtual {}
impl<Meta: VmMeta, S: Space> PageNumber<Meta, S> {
pub const ZERO: Self = Self::new(0);
pub const MIN: Self = Self::ZERO;
#[inline]
pub const fn new(n: usize) -> Self {
Self(n, PhantomData, PhantomData)
}
#[inline]
pub const fn val(self) -> usize {
self.0
}
}
impl<Meta: VmMeta, S: Space> Add<usize> for PageNumber<Meta, S> {
type Output = Self;
#[inline]
fn add(self, rhs: usize) -> Self {
Self::new(self.0.wrapping_add(rhs))
}
}
impl<Meta: VmMeta, S: Space> AddAssign<usize> for PageNumber<Meta, S> {
#[inline]
fn add_assign(&mut self, rhs: usize) {
self.0 = self.0.wrapping_add(rhs);
}
}
pub type PPN<Meta> = PageNumber<Meta, Physical>;
pub type VPN<Meta> = PageNumber<Meta, Virtual>;
impl<Meta: VmMeta> PPN<Meta> {
pub const INVALID: Self = Self::new(1 << (Meta::P_ADDR_BITS - Meta::PAGE_BITS));
pub const MAX: Self = Self::new(Self::INVALID.val() - 1);
}
impl<Meta: VmMeta> fmt::Debug for PPN<Meta> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PPN({:#x})", self.0)
}
}
impl<Meta: VmMeta> VPN<Meta> {
pub const MAX: Self = Self::new(mask(Meta::V_ADDR_BITS - Meta::PAGE_BITS));
#[inline]
pub const fn base(self) -> VAddr<Meta> {
VAddr::new(self.0 << Meta::PAGE_BITS)
}
#[inline]
pub fn index_in(self, level: usize) -> usize {
(self.0 >> Self::bits_until(level)) & mask(Meta::LEVEL_BITS[level])
}
#[inline]
pub fn floor(self, level: usize) -> Self {
let bits = Self::bits_until(level);
Self::new(self.0 & !mask(bits))
}
#[inline]
pub fn ceil(self, level: usize) -> usize {
let bits = Self::bits_until(level);
(self.0 + mask(bits)) >> bits
}
#[inline]
pub fn vaddr_range(self, level: usize) -> Range<VAddr<Meta>> {
let base = self.base();
base..base + Meta::bytes_in_page(level)
}
#[inline]
pub fn align_level(self) -> usize {
let mut n = self.0;
for (i, bits) in Meta::LEVEL_BITS[..Meta::MAX_LEVEL].iter().rev().enumerate() {
if n & mask(*bits) != 0 {
return i;
}
n >>= bits;
}
Meta::MAX_LEVEL
}
#[inline]
fn bits_until(level: usize) -> usize {
Meta::LEVEL_BITS[..level].iter().sum::<usize>()
}
}
impl<Meta: VmMeta> fmt::Debug for VPN<Meta> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VPN({:#x})", self.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct MaybeInvalidPPN<Meta: VmMeta>(PPN<Meta>);
impl<Meta: VmMeta> MaybeInvalidPPN<Meta> {
#[inline]
pub const fn new(n: PPN<Meta>) -> Self {
Self(n)
}
#[inline]
pub const fn invalid() -> Self {
Self(PPN::INVALID)
}
#[inline]
pub const fn get(&self) -> Option<PPN<Meta>> {
if self.0.val() > PPN::<Meta>::MAX.val() {
None
} else {
Some(self.0)
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VAddr<Meta: VmMeta>(usize, PhantomData<Meta>);
impl<Meta: VmMeta> Add<usize> for VAddr<Meta> {
type Output = Self;
#[inline]
fn add(self, rhs: usize) -> Self {
Self::new(self.0.wrapping_add(rhs))
}
}
impl<Meta: VmMeta> AddAssign<usize> for VAddr<Meta> {
#[inline]
fn add_assign(&mut self, rhs: usize) {
self.0 = self.0.wrapping_add(rhs);
}
}
impl<Meta: VmMeta> VAddr<Meta> {
const IGNORED_MASK: usize = mask(Meta::V_ADDR_BITS - 1);
#[inline]
pub const fn new(value: usize) -> Self {
Self(value & mask(Meta::V_ADDR_BITS), PhantomData)
}
#[inline]
pub const fn val(self) -> usize {
if self.0 <= Self::IGNORED_MASK {
self.0
} else {
self.0 | !Self::IGNORED_MASK
}
}
#[inline]
pub const unsafe fn as_ptr<T>(self) -> *const T {
self.val() as _
}
#[inline]
pub unsafe fn as_mut_ptr<T>(self) -> *mut T {
self.val() as _
}
#[inline]
pub const fn floor(self) -> VPN<Meta> {
VPN::new(self.0 >> Meta::PAGE_BITS)
}
#[inline]
pub const fn ceil(self) -> VPN<Meta> {
VPN::new((self.0 + mask(Meta::PAGE_BITS)) >> Meta::PAGE_BITS)
}
#[inline]
pub const fn offset(self) -> usize {
self.0 & mask(Meta::PAGE_BITS)
}
}
impl<Meta: VmMeta> From<usize> for VAddr<Meta> {
#[inline]
fn from(value: usize) -> Self {
Self::new(value)
}
}
impl<Meta: VmMeta, T> From<&T> for VAddr<Meta> {
#[inline]
fn from(value: &T) -> Self {
Self::new(value as *const _ as _)
}
}
impl<Meta: VmMeta> fmt::Debug for VAddr<Meta> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VAddr({:#x})", self.0)
}
}
#[test]
fn test_index_in() {
use crate::test_meta::Sv39;
for i in 0..=Sv39::MAX_LEVEL {
let vpn = VPN::<Sv39>::new(1 << (i * 9));
for j in 0..=Sv39::MAX_LEVEL {
assert_eq!(vpn.index_in(j), if i == j { 1 } else { 0 });
}
}
}
#[test]
fn test_align_level() {
use crate::test_meta::Sv39;
assert_eq!(VPN::<Sv39>::new(1).align_level(), 0);
assert_eq!(VPN::<Sv39>::new(1 << 9).align_level(), 1);
assert_eq!(VPN::<Sv39>::new(1 << 18).align_level(), 2);
assert_eq!(VPN::<Sv39>::new(0).align_level(), 2);
}