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 cglue::tuple::*;
use bumpalo::{collections::Vec as BumpVec, Bump};
use cglue::callback::FromExtend;
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 set_proc_arch(&mut self, new_arch: ArchitectureObj) -> ArchitectureObj {
core::mem::replace(&mut self.proc_arch, new_arch)
}
pub fn translator(&self) -> &D {
&self.translator
}
pub fn set_translator(&mut self, new_translator: D) -> D {
core::mem::replace(&mut self.translator, new_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(),
}
}
}
#[allow(clippy::needless_option_as_deref)]
impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> MemoryView
for VirtualDma<T, V, D>
{
fn read_raw_iter<'a>(
&mut self,
MemOps {
inp,
out,
mut out_fail,
}: ReadRawMemOps,
) -> Result<()> {
self.arena.reset();
let mut translation = BumpVec::with_capacity_in(inp.size_hint().0, &self.arena);
let phys_mem = &mut self.phys_mem;
self.vat.virt_to_phys_iter(
phys_mem,
&self.translator,
inp,
&mut translation.from_extend(),
&mut (&mut |(_, CTup3(_, meta, buf)): (_, _)| {
opt_call(out_fail.as_deref_mut(), CTup2(meta, buf))
})
.into(),
);
MemOps::with_raw(translation.into_iter(), out, out_fail, |data| {
phys_mem.phys_read_raw_iter(data)
})
}
fn write_raw_iter(
&mut self,
MemOps {
inp,
out,
mut out_fail,
}: WriteRawMemOps,
) -> Result<()> {
self.arena.reset();
let mut translation = BumpVec::with_capacity_in(inp.size_hint().0, &self.arena);
let phys_mem = &mut self.phys_mem;
self.vat.virt_to_phys_iter(
phys_mem,
&self.translator,
inp,
&mut translation.from_extend(),
&mut (&mut |(_, CTup3(_, meta, buf)): (_, _)| {
opt_call(out_fail.as_deref_mut(), CTup2(meta, buf))
})
.into(),
);
MemOps::with_raw(translation.into_iter(), out, out_fail, |data| {
phys_mem.phys_write_raw_iter(data)
})
}
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: &[VtopRange],
mut out: VirtualTranslationCallback,
mut out_fail: VirtualTranslationFailCallback,
) {
self.vat.virt_to_phys_iter(
&mut self.phys_mem,
&self.translator,
addrs
.iter()
.map(|&CTup2(address, size)| CTup3(address, address, size)),
&mut (&mut |CTup3(a, b, c): CTup3<PhysicalAddress, Address, umem>| {
out.call(VirtualTranslation {
in_virtual: b,
size: c,
out_physical: a,
})
})
.into(),
&mut (&mut |(_e, CTup3(from, _, size))| {
out_fail.call(VirtualTranslationFail { from, size })
})
.into(),
)
}
}