use super::ArchMmuSpec;
use crate::architecture::Endianess;
use crate::types::{clamp_to_usize, umem, Address};
#[derive(Debug)]
pub struct ArchMmuDef {
pub virtual_address_splits: &'static [u8],
pub valid_final_page_steps: &'static [usize],
pub address_space_bits: u8,
pub endianess: Endianess,
pub addr_size: u8,
pub pte_size: usize,
pub present_bit: fn(Address) -> bool,
pub writeable_bit: fn(Address, bool) -> bool,
pub nx_bit: fn(Address, bool) -> bool,
pub large_page_bit: fn(Address) -> bool,
}
impl ArchMmuDef {
pub const fn into_spec(self) -> ArchMmuSpec {
ArchMmuSpec::from_def(self)
}
#[allow(unused)]
pub fn pte_addr_mask(&self, pte_addr: Address, step: usize) -> umem {
let max = self.address_space_bits - 1;
let min = self.virtual_address_splits[step]
+ if step == self.virtual_address_splits.len() - 1 {
0
} else {
self.pte_size.to_le().trailing_zeros() as u8
};
let mask = Address::bit_mask(min..=max);
pte_addr.to_umem() & umem::from_le(mask.to_umem())
}
pub(crate) const fn virt_addr_bit_range(&self, step: usize) -> (u8, u8) {
let max_index_bits = {
let subsl = &self.virtual_address_splits;
let mut accum = 0;
let mut i = step;
while i < subsl.len() {
accum += subsl[i];
i += 1;
}
accum
};
let min_index_bits = max_index_bits - self.virtual_address_splits[step];
(min_index_bits, max_index_bits)
}
#[allow(unused)]
pub fn split_count(&self) -> usize {
self.virtual_address_splits.len()
}
pub const fn spare_allocs(&self) -> usize {
let mut i = 1;
let mut fold = 0;
while i < self.virtual_address_splits.len() {
fold += 1 << self.virtual_address_splits[i - 1];
i += 1;
}
fold
}
pub const fn pt_leaf_size(&self, step: usize) -> usize {
let (min, max) = self.virt_addr_bit_range(step);
clamp_to_usize((1 << (max - min)) * self.pte_size as umem)
}
#[allow(unused)]
pub const fn page_size_step_unchecked(&self, step: usize) -> umem {
let max_index_bits = {
let subsl = &self.virtual_address_splits;
let mut i = step;
let mut accum = 0;
while i < subsl.len() {
accum += subsl[i];
i += 1;
}
accum
};
1 << max_index_bits
}
#[allow(unused)]
pub fn page_size_step(&self, step: usize) -> umem {
debug_assert!(self.valid_final_page_steps.binary_search(&step).is_ok());
self.page_size_step_unchecked(step)
}
}