use std::prelude::v1::*;
use crate::architecture::{ArchitectureObj, Endianess};
use crate::error::{Error, Result, *};
use crate::mem::memory_view::*;
use crate::mem::{
mem_data::*,
virt_translate::{
DirectTranslate, VirtualTranslate, VirtualTranslate2, VirtualTranslate3,
VirtualTranslation, VirtualTranslationCallback, VirtualTranslationFail,
VirtualTranslationFailCallback,
},
MemoryView, PhysicalMemory, PhysicalMemoryMetadata,
};
use crate::types::{umem, Address, PhysicalAddress};
use bumpalo::{collections::Vec as BumpVec, Bump};
use cglue::{callback::FromExtend, iter::CIterator};
pub struct VirtualDma<T, V, D> {
phys_mem: T,
vat: V,
proc_arch: ArchitectureObj,
translator: D,
arena: Bump,
}
impl<T: PhysicalMemory, D: VirtualTranslate3> VirtualDma<T, DirectTranslate, D> {
pub fn new(phys_mem: T, arch: impl Into<ArchitectureObj>, translator: D) -> Self {
Self {
phys_mem,
vat: DirectTranslate::new(),
proc_arch: arch.into(),
translator,
arena: Bump::new(),
}
}
}
impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> VirtualDma<T, V, D> {
pub fn with_vat(phys_mem: T, arch: impl Into<ArchitectureObj>, translator: D, vat: V) -> Self {
Self {
phys_mem,
vat,
proc_arch: arch.into(),
translator,
arena: Bump::new(),
}
}
pub fn sys_arch(&self) -> ArchitectureObj {
self.translator.arch()
}
pub fn proc_arch(&self) -> ArchitectureObj {
self.proc_arch
}
pub fn translator(&self) -> &impl VirtualTranslate3 {
&self.translator
}
pub fn read_addr(&mut self, addr: Address) -> PartialResult<Address> {
match self.proc_arch.bits() {
64 => self.read_addr64(addr),
32 => self.read_addr32(addr),
_ => Err(PartialError::Error(Error(
ErrorOrigin::VirtualMemory,
ErrorKind::InvalidArchitecture,
))),
}
}
pub fn into_inner(self) -> (T, V) {
(self.phys_mem, self.vat)
}
pub fn mem_vat_pair(&mut self) -> (&mut T, &mut V) {
(&mut self.phys_mem, &mut self.vat)
}
pub fn phys_mem(&mut self) -> &mut T {
&mut self.phys_mem
}
pub fn phys_mem_ref(&self) -> &T {
&self.phys_mem
}
pub fn vat(&mut self) -> &mut V {
&mut self.vat
}
}
impl<T, V, D> Clone for VirtualDma<T, V, D>
where
T: Clone,
V: Clone,
D: Clone,
{
fn clone(&self) -> Self {
Self {
phys_mem: self.phys_mem.clone(),
vat: self.vat.clone(),
proc_arch: self.proc_arch,
translator: self.translator.clone(),
arena: Bump::new(),
}
}
}
impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> MemoryView
for VirtualDma<T, V, D>
{
fn read_raw_iter<'a>(
&mut self,
data: CIterator<ReadData<'a>>,
out_fail: &mut ReadFailCallback<'_, 'a>,
) -> Result<()> {
self.arena.reset();
let mut translation = BumpVec::with_capacity_in(data.size_hint().0, &self.arena);
self.vat.virt_to_phys_iter(
&mut self.phys_mem,
&self.translator,
data,
&mut translation.from_extend(),
&mut (&mut |(_, rdata): (_, ReadData<'a>)| out_fail.call(rdata)).into(),
);
let mut iter = translation.into_iter();
self.phys_mem
.phys_read_raw_iter((&mut iter).into(), &mut (&mut |_| true).into())
}
fn write_raw_iter<'a>(
&mut self,
data: CIterator<WriteData<'a>>,
out_fail: &mut WriteFailCallback<'_, 'a>,
) -> Result<()> {
self.arena.reset();
let mut translation = BumpVec::with_capacity_in(data.size_hint().0, &self.arena);
self.vat.virt_to_phys_iter(
&mut self.phys_mem,
&self.translator,
data,
&mut translation.from_extend(),
&mut (&mut |(_, wdata): (_, WriteData<'a>)| out_fail.call(wdata)).into(),
);
let mut iter = translation.into_iter();
self.phys_mem
.phys_write_raw_iter((&mut iter).into(), &mut (&mut |_| true).into())
}
fn metadata(&self) -> MemoryViewMetadata {
let PhysicalMemoryMetadata {
max_address,
real_size,
readonly,
..
} = self.phys_mem.metadata();
MemoryViewMetadata {
max_address,
real_size,
readonly,
little_endian: self.proc_arch.endianess() == Endianess::LittleEndian,
arch_bits: self.proc_arch.bits(),
}
}
}
impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> VirtualTranslate
for VirtualDma<T, V, D>
{
fn virt_to_phys_list(
&mut self,
addrs: &[MemoryRange],
mut out: VirtualTranslationCallback,
mut out_fail: VirtualTranslationFailCallback,
) {
self.vat.virt_to_phys_iter(
&mut self.phys_mem,
&self.translator,
addrs
.iter()
.map(|&MemData(address, size)| MemData(address, (address, size))),
&mut (&mut |MemData(a, b): MemData<PhysicalAddress, (Address, umem)>| {
out.call(VirtualTranslation {
in_virtual: b.0,
size: b.1,
out_physical: a,
})
})
.into(),
&mut (&mut |(_e, MemData(from, (_, size)))| {
out_fail.call(VirtualTranslationFail { from, size })
})
.into(),
)
}
}