memflow/mem/virt_mem/virtual_dma.rs
1use std::prelude::v1::*;
2
3use crate::architecture::{ArchitectureObj, Endianess};
4use crate::error::{Error, Result, *};
5use crate::mem::memory_view::*;
6use crate::mem::{
7 mem_data::*,
8 virt_translate::{
9 DirectTranslate, VirtualTranslate, VirtualTranslate2, VirtualTranslate3,
10 VirtualTranslation, VirtualTranslationCallback, VirtualTranslationFail,
11 VirtualTranslationFailCallback,
12 },
13 MemoryView, PhysicalMemory, PhysicalMemoryMetadata,
14};
15use crate::types::{umem, Address, PhysicalAddress};
16use cglue::tuple::*;
17
18use bumpalo::{collections::Vec as BumpVec, Bump};
19use cglue::callback::FromExtend;
20
21/// The VirtualDma struct provides a default implementation to access virtual memory
22/// from user provided [`PhysicalMemory`] and [`VirtualTranslate2`] objects.
23///
24/// This struct implements [`MemoryView`] and allows the user to access the virtual memory of a process.
25pub struct VirtualDma<T, V, D> {
26 phys_mem: T,
27 vat: V,
28 proc_arch: ArchitectureObj,
29 translator: D,
30 arena: Bump,
31}
32
33impl<T: PhysicalMemory, D: VirtualTranslate3> VirtualDma<T, DirectTranslate, D> {
34 /// Constructs a `VirtualDma` object from user supplied architectures and DTB.
35 /// It creates a default `VirtualTranslate2` object using the `DirectTranslate` struct.
36 ///
37 /// If you want to use a cache for translating virtual to physical memory
38 /// consider using the `VirtualDma::with_vat()` function and supply your own `VirtualTranslate2` object.
39 ///
40 /// # Examples
41 ///
42 /// Constructing a `VirtualDma` object with a given dtb and using it to read:
43 /// ```
44 /// use memflow::types::Address;
45 /// use memflow::architecture::x86::x64;
46 /// use memflow::mem::{PhysicalMemory, VirtualTranslate2, MemoryView, VirtualDma};
47 /// use memflow::cglue::Fwd;
48 ///
49 /// fn read(phys_mem: Fwd<&mut impl PhysicalMemory>, vat: &mut impl VirtualTranslate2, dtb: Address, read_addr: Address) {
50 /// let arch = x64::ARCH;
51 /// let translator = x64::new_translator(dtb);
52 ///
53 /// let mut virt_mem = VirtualDma::new(phys_mem, arch, translator);
54 ///
55 /// let mut addr = 0u64;
56 /// virt_mem.read_into(read_addr, &mut addr).unwrap();
57 /// println!("addr: {:x}", addr);
58 /// # assert_eq!(addr, 0x00ff_00ff_00ff_00ff);
59 /// }
60 /// # use memflow::dummy::{DummyMemory, DummyOs};
61 /// # use memflow::types::size;
62 /// # use memflow::mem::DirectTranslate;
63 /// # use memflow::cglue::ForwardMut;
64 /// # let mem = DummyMemory::new(size::mb(4));
65 /// # let (mut os, dtb, virt_base) = DummyOs::new_and_dtb(mem, size::mb(2), &[255, 0, 255, 0, 255, 0, 255, 0]);
66 /// # let mut vat = DirectTranslate::new();
67 /// # read(os.forward_mut(), &mut vat, dtb, virt_base);
68 /// ```
69 pub fn new(phys_mem: T, arch: impl Into<ArchitectureObj>, translator: D) -> Self {
70 Self {
71 phys_mem,
72 vat: DirectTranslate::new(),
73 proc_arch: arch.into(),
74 translator,
75 arena: Bump::new(),
76 }
77 }
78}
79
80impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> VirtualDma<T, V, D> {
81 /// This function constructs a `VirtualDma` instance with a user supplied `VirtualTranslate2` object.
82 /// It can be used when working with cached virtual to physical translations such as a Tlb.
83 ///
84 /// # Examples
85 ///
86 /// Constructing a `VirtualDma` object with VAT and using it to read:
87 /// ```
88 /// use memflow::types::Address;
89 /// use memflow::architecture::x86::x64;
90 /// use memflow::mem::{PhysicalMemory, VirtualTranslate2, MemoryView, VirtualDma};
91 /// use memflow::cglue::Fwd;
92 ///
93 /// fn read(phys_mem: Fwd<&mut impl PhysicalMemory>, vat: impl VirtualTranslate2, dtb: Address, read_addr: Address) {
94 /// let arch = x64::ARCH;
95 /// let translator = x64::new_translator(dtb);
96 ///
97 /// let mut virt_mem = VirtualDma::with_vat(phys_mem, arch, translator, vat);
98 ///
99 /// let mut addr = 0u64;
100 /// virt_mem.read_into(read_addr, &mut addr).unwrap();
101 /// println!("addr: {:x}", addr);
102 /// # assert_eq!(addr, 0x00ff_00ff_00ff_00ff);
103 /// }
104 /// # use memflow::dummy::{DummyMemory, DummyOs};
105 /// # use memflow::types::size;
106 /// # use memflow::mem::DirectTranslate;
107 /// # use memflow::cglue::ForwardMut;
108 /// # let mem = DummyMemory::new(size::mb(4));
109 /// # let (mut os, dtb, virt_base) = DummyOs::new_and_dtb(mem, size::mb(2), &[255, 0, 255, 0, 255, 0, 255, 0]);
110 /// # let mut vat = DirectTranslate::new();
111 /// # read(os.forward_mut(), &mut vat, dtb, virt_base);
112 /// ```
113 pub fn with_vat(phys_mem: T, arch: impl Into<ArchitectureObj>, translator: D, vat: V) -> Self {
114 Self {
115 phys_mem,
116 vat,
117 proc_arch: arch.into(),
118 translator,
119 arena: Bump::new(),
120 }
121 }
122
123 /// Returns the architecture of the system. The system architecture is used for virtual to physical translations.
124 pub fn sys_arch(&self) -> ArchitectureObj {
125 self.translator.arch()
126 }
127
128 /// Returns the architecture of the process for this context. The process architecture is mainly used to determine pointer sizes.
129 pub fn proc_arch(&self) -> ArchitectureObj {
130 self.proc_arch
131 }
132
133 /// Replaces current process architecture with a new one.
134 pub fn set_proc_arch(&mut self, new_arch: ArchitectureObj) -> ArchitectureObj {
135 core::mem::replace(&mut self.proc_arch, new_arch)
136 }
137
138 /// Returns the Directory Table Base of this process..
139 pub fn translator(&self) -> &D {
140 &self.translator
141 }
142
143 /// Replace current translator with a new one.
144 pub fn set_translator(&mut self, new_translator: D) -> D {
145 core::mem::replace(&mut self.translator, new_translator)
146 }
147
148 /// A wrapper around `read_addr64` and `read_addr32` that will use the pointer size of this context's process.
149 /// TODO: do this in virt mem
150 pub fn read_addr(&mut self, addr: Address) -> PartialResult<Address> {
151 match self.proc_arch.bits() {
152 64 => self.read_addr64(addr),
153 32 => self.read_addr32(addr),
154 _ => Err(PartialError::Error(Error(
155 ErrorOrigin::VirtualMemory,
156 ErrorKind::InvalidArchitecture,
157 ))),
158 }
159 }
160
161 /// Consumes this VirtualDma object, returning the underlying memory and vat objects
162 pub fn into_inner(self) -> (T, V) {
163 (self.phys_mem, self.vat)
164 }
165
166 pub fn mem_vat_pair(&mut self) -> (&mut T, &mut V) {
167 (&mut self.phys_mem, &mut self.vat)
168 }
169
170 pub fn phys_mem(&mut self) -> &mut T {
171 &mut self.phys_mem
172 }
173
174 pub fn phys_mem_ref(&self) -> &T {
175 &self.phys_mem
176 }
177
178 pub fn vat(&mut self) -> &mut V {
179 &mut self.vat
180 }
181}
182
183impl<T, V, D> Clone for VirtualDma<T, V, D>
184where
185 T: Clone,
186 V: Clone,
187 D: Clone,
188{
189 fn clone(&self) -> Self {
190 Self {
191 phys_mem: self.phys_mem.clone(),
192 vat: self.vat.clone(),
193 proc_arch: self.proc_arch,
194 translator: self.translator.clone(),
195 arena: Bump::new(),
196 }
197 }
198}
199
200#[allow(clippy::needless_option_as_deref)]
201impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> MemoryView
202 for VirtualDma<T, V, D>
203{
204 fn read_raw_iter<'a>(
205 &mut self,
206 MemOps {
207 inp,
208 out,
209 mut out_fail,
210 }: ReadRawMemOps,
211 ) -> Result<()> {
212 self.arena.reset();
213
214 let mut translation = BumpVec::with_capacity_in(inp.size_hint().0, &self.arena);
215 let phys_mem = &mut self.phys_mem;
216
217 self.vat.virt_to_phys_iter(
218 phys_mem,
219 &self.translator,
220 inp,
221 &mut translation.from_extend(),
222 &mut (&mut |(_, CTup3(_, meta, buf)): (_, _)| {
223 opt_call(out_fail.as_deref_mut(), CTup2(meta, buf))
224 })
225 .into(),
226 );
227
228 MemOps::with_raw(translation.into_iter(), out, out_fail, |data| {
229 phys_mem.phys_read_raw_iter(data)
230 })
231 }
232
233 fn write_raw_iter(
234 &mut self,
235 MemOps {
236 inp,
237 out,
238 mut out_fail,
239 }: WriteRawMemOps,
240 ) -> Result<()> {
241 self.arena.reset();
242
243 let mut translation = BumpVec::with_capacity_in(inp.size_hint().0, &self.arena);
244 let phys_mem = &mut self.phys_mem;
245
246 self.vat.virt_to_phys_iter(
247 phys_mem,
248 &self.translator,
249 inp,
250 &mut translation.from_extend(),
251 &mut (&mut |(_, CTup3(_, meta, buf)): (_, _)| {
252 opt_call(out_fail.as_deref_mut(), CTup2(meta, buf))
253 })
254 .into(),
255 );
256
257 MemOps::with_raw(translation.into_iter(), out, out_fail, |data| {
258 phys_mem.phys_write_raw_iter(data)
259 })
260 }
261
262 fn metadata(&self) -> MemoryViewMetadata {
263 let PhysicalMemoryMetadata {
264 max_address,
265 real_size,
266 readonly,
267 ..
268 } = self.phys_mem.metadata();
269
270 MemoryViewMetadata {
271 max_address,
272 real_size,
273 readonly,
274 little_endian: self.proc_arch.endianess() == Endianess::LittleEndian,
275 arch_bits: self.proc_arch.bits(),
276 }
277 }
278}
279
280impl<T: PhysicalMemory, V: VirtualTranslate2, D: VirtualTranslate3> VirtualTranslate
281 for VirtualDma<T, V, D>
282{
283 fn virt_to_phys_list(
284 &mut self,
285 addrs: &[VtopRange],
286 mut out: VirtualTranslationCallback,
287 mut out_fail: VirtualTranslationFailCallback,
288 ) {
289 self.vat.virt_to_phys_iter(
290 &mut self.phys_mem,
291 &self.translator,
292 addrs
293 .iter()
294 .map(|&CTup2(address, size)| CTup3(address, address, size)),
295 &mut (&mut |CTup3(a, b, c): CTup3<PhysicalAddress, Address, umem>| {
296 out.call(VirtualTranslation {
297 in_virtual: b,
298 size: c,
299 out_physical: a,
300 })
301 })
302 .into(),
303 &mut (&mut |(_e, CTup3(from, _, size))| {
304 out_fail.call(VirtualTranslationFail { from, size })
305 })
306 .into(),
307 )
308 }
309}