use core::marker::PhantomData;
use core::ops::Range;
use crate::address_space::PageTableMapper;
use crate::{PageFormat, PteType};
use num_traits::{FromPrimitive, PrimInt, Unsigned};
pub struct CopyFromWalker<'a, PTE, Mapper, Error>
where
PTE: FromPrimitive + PrimInt + Unsigned,
Mapper: PageTableMapper<PTE, Error>,
{
pub mapper: &'a Mapper,
pub offset: usize,
pub data: &'a mut [u8],
pub format: &'a PageFormat<'a, PTE>,
pub error: PhantomData<Error>,
}
impl<'a, PTE, Mapper, Error> crate::PageWalker<PTE, Error> for CopyFromWalker<'a, PTE, Mapper, Error>
where
PTE: FromPrimitive + PrimInt + Unsigned,
Mapper: PageTableMapper<PTE, Error>,
{
fn read_pte(&self, phys_addr: PTE) -> Result<PTE, Error> {
self.mapper.read_pte(phys_addr)
}
fn handle_pte(&mut self, pte_type: PteType, range: Range<usize>, pte: &PTE) -> Result<(), Error> {
let level = match pte_type {
PteType::Page(level) => level,
_ => return Ok(()),
};
let level = &self.format.levels[level];
if !level.is_present(*pte) {
return Err(Mapper::PAGE_NOT_PRESENT);
}
let phys_addr = *pte & self.format.physical_mask;
let offset = PTE::from_usize(range.start & (level.page_size() - 1)).unwrap();
let size = (self.data.len() - self.offset).min(level.page_size());
self.mapper.read_bytes(&mut self.data[self.offset..self.offset + size], phys_addr + offset)?;
self.offset += size;
Ok(())
}
}
pub struct CopyToWalker<'a, PTE, Mapper, Error>
where
PTE: FromPrimitive + PrimInt + Unsigned,
Mapper: PageTableMapper<PTE, Error>,
{
pub mapper: &'a mut Mapper,
pub offset: usize,
pub data: &'a [u8],
pub format: &'a PageFormat<'a, PTE>,
pub error: PhantomData<Error>,
}
impl<'a, PTE, Mapper, Error> crate::PageWalker<PTE, Error> for CopyToWalker<'a, PTE, Mapper, Error>
where
PTE: FromPrimitive + PrimInt + Unsigned,
Mapper: PageTableMapper<PTE, Error>,
{
fn read_pte(&self, phys_addr: PTE) -> Result<PTE, Error> {
self.mapper.read_pte(phys_addr)
}
fn handle_pte(&mut self, pte_type: PteType, range: Range<usize>, pte: &PTE) -> Result<(), Error> {
let level = match pte_type {
PteType::Page(level) => level,
_ => return Ok(()),
};
let level = &self.format.levels[level];
if !level.is_present(*pte) {
return Err(Mapper::PAGE_NOT_PRESENT);
}
let phys_addr = *pte & self.format.physical_mask;
let offset = PTE::from_usize(range.start & (level.page_size() - 1)).unwrap();
let size = (self.data.len() - self.offset).min(level.page_size());
self.mapper.write_bytes(phys_addr + offset, &self.data[self.offset..self.offset + size])?;
self.offset += size;
Ok(())
}
}