use super::{Pos, Visitor};
use crate::{PageTable, Pte, VmMeta, PPN};
use core::{fmt, marker::PhantomData, ptr::NonNull};
pub struct PageTableFormatter<Meta: VmMeta, F: Fn(PPN<Meta>) -> NonNull<Pte<Meta>>> {
pub pt: PageTable<Meta>,
pub f: F,
}
impl<Meta: VmMeta, F: Fn(PPN<Meta>) -> NonNull<Pte<Meta>>> fmt::Debug
for PageTableFormatter<Meta, F>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.pt.walk(
Pos {
vpn: self.pt.base,
level: 0,
},
&mut FmtVisitor {
f,
t: &self.f,
max_level: self.pt.level,
level: self.pt.level + 1,
_phantom: PhantomData,
},
);
Ok(())
}
}
struct FmtVisitor<'f1, 'f2, Meta: VmMeta, T: Fn(PPN<Meta>) -> NonNull<Pte<Meta>>> {
f: &'f1 mut fmt::Formatter<'f2>,
t: T,
max_level: usize,
level: usize,
_phantom: PhantomData<Meta>,
}
impl<'f1, 'f2, Meta: VmMeta, T: Fn(PPN<Meta>) -> NonNull<Pte<Meta>>> FmtVisitor<'f1, 'f2, Meta, T> {
fn ppn(&mut self, ppn: PPN<Meta>, level: usize) {
if level >= self.level {
writeln!(self.f).unwrap();
for _ in level..self.max_level {
for _ in 0..18 {
write!(self.f, " ").unwrap();
}
write!(self.f, " - ").unwrap();
}
}
write!(self.f, "{:#018x}", ppn.val()).unwrap();
}
fn pte(&mut self, pte: Pte<Meta>, pos: Pos<Meta>) {
let range = pos.vpn.vaddr_range(pos.level);
write!(
self.f,
" {:#018x}..{:#018x} (",
range.start.val(),
range.end.val()
)
.unwrap();
Meta::fmt_flags(self.f, pte.flags().val()).unwrap();
write!(self.f, ")").unwrap();
self.level = pos.level;
}
}
impl<'f1, 'f2, Meta: VmMeta, T: Fn(PPN<Meta>) -> NonNull<Pte<Meta>>> Visitor<Meta>
for FmtVisitor<'f1, 'f2, Meta, T>
{
#[inline]
fn meet(
&mut self,
level: usize,
pte: Pte<Meta>,
_target: Pos<Meta>,
) -> Option<core::ptr::NonNull<Pte<Meta>>> {
self.ppn(pte.ppn(), level);
write!(self.f, " - ").unwrap();
self.level = level;
Some((self.t)(pte.ppn()))
}
#[inline]
fn block(&mut self, level: usize, pte: Pte<Meta>, target: Pos<Meta>) -> Pos<Meta> {
if pte.is_valid() {
self.ppn(pte.ppn(), level);
for _ in 0..level {
write!(self.f, " - ").unwrap();
for _ in 0..18 {
write!(self.f, "-").unwrap();
}
}
self.pte(pte, Pos { level, ..target });
}
Pos {
level: 0,
..Pos::new(target.vpn, level).next()
}
}
fn arrive(&mut self, pte: Pte<Meta>, target: Pos<Meta>) -> Pos<Meta> {
if pte.is_valid() {
self.ppn(pte.ppn(), 0);
self.pte(pte, target);
}
target.next()
}
}