use owo_colors::OwoColorize;
use std::{
fmt,
ops::{Add, BitAnd, BitOr, Shr, Sub},
};
use zerocopy::{FromBytes, Immutable, IntoBytes};
#[derive(Clone, Copy, Debug, PartialEq, FromBytes, IntoBytes, Immutable)]
pub struct VirtAddr(pub u64);
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PhysAddr(pub u64);
#[derive(Clone, Copy, Debug)]
pub struct Dtb(pub PhysAddr);
#[derive(Clone, Copy, Debug, FromBytes, IntoBytes, Immutable)]
pub struct PageTableEntry(pub u64);
impl Add<u64> for VirtAddr {
type Output = Self;
fn add(self, rhs: u64) -> Self {
VirtAddr(self.0 + rhs)
}
}
impl Sub<u64> for VirtAddr {
type Output = Self;
fn sub(self, rhs: u64) -> Self {
VirtAddr(self.0 - rhs)
}
}
impl BitAnd<u64> for VirtAddr {
type Output = Self;
fn bitand(self, rhs: u64) -> Self {
VirtAddr(self.0 & rhs)
}
}
impl BitOr<u64> for VirtAddr {
type Output = Self;
fn bitor(self, rhs: u64) -> Self {
VirtAddr(self.0 | rhs)
}
}
impl Shr<u64> for VirtAddr {
type Output = Self;
fn shr(self, rhs: u64) -> Self {
VirtAddr(self.0 >> rhs)
}
}
impl VirtAddr {
pub fn pdp_index(self) -> u64 {
(self.0 >> 39) & 0x1ff
}
pub fn pd_index(self) -> u64 {
(self.0 >> 30) & 0x1ff
}
pub fn pt_index(self) -> u64 {
(self.0 >> 21) & 0x1ff
}
pub fn pte_index(self) -> u64 {
(self.0 >> 12) & 0x1ff
}
pub fn page_offset(self) -> u64 {
const PAGE_OFFSET_SIZE: u32 = 12;
self.0 & !(!0 << PAGE_OFFSET_SIZE)
}
}
impl PageTableEntry {
pub fn is_present(self) -> bool {
self.0 & 1 != 0
}
pub fn is_large_page(self) -> bool {
self.0 & 0x80 != 0
}
pub fn pte_frame_addr(self) -> u64 {
self.0 & 0x0000_ffff_ffff_f000u64
}
pub fn is_zero(self) -> bool {
self.0 == 0
}
pub fn is_kernel_table(self) -> bool {
(self.0 & 0x8000000000000087) == 0x03
}
pub fn is_self_ref(self, pa: u64) -> bool {
(self.0 & 0x0000fffffffff083) == (pa | 0x03)
}
pub fn pfn(self) -> u64 {
self.pte_frame_addr() >> 12
}
pub fn flags(self) -> String {
format!(
"{}{}{}{}{}{}{}{}{}{}{}",
if self.0 & (1 << 9) != 0 { 'C' } else { '-' }, if self.0 & (1 << 8) != 0 { 'G' } else { '-' }, if self.0 & (1 << 7) != 0 { 'L' } else { '-' }, if self.0 & (1 << 6) != 0 { 'D' } else { '-' }, if self.0 & (1 << 5) != 0 { 'A' } else { '-' }, if self.0 & (1 << 4) != 0 { 'N' } else { '-' }, '-', if self.0 & (1 << 2) != 0 { 'U' } else { 'K' }, if self.0 & (1 << 11) != 0 { 'W' } else { 'R' }, if self.0 & (1 << 63) != 0 { '-' } else { 'E' }, if self.0 & 1 != 0 { 'V' } else { '-' }, )
}
}
pub struct Value<T>(pub T);
macro_rules! impl_colored_fmt {
(impl<$g:ident> $t:ty, $color:ident, $($trait:path),+) => {
$(
impl<$g> $trait for $t
where $g: $trait
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<_ as $trait>::fmt(&self.0.$color(), f)
}
}
)*
};
($t:ty, $color:ident, $($trait:path),+) => {
$(
impl $trait for $t {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<_ as $trait>::fmt(&self.0.$color(), f)
}
}
)*
};
}
impl_colored_fmt!(
VirtAddr,
yellow,
fmt::Display,
fmt::LowerHex,
fmt::UpperHex,
fmt::Binary
);
impl_colored_fmt!(
impl<T> Value<T>,
cyan,
fmt::Display, fmt::LowerHex, fmt::UpperHex, fmt::Binary
);