memflow/architecture/x86/
mod.rs

1pub mod x32;
2pub mod x32_pae;
3pub mod x64;
4
5use super::{Architecture, ArchitectureIdent, ArchitectureObj, Endianess};
6
7use crate::mem::virt_translate::{
8    mmu::ArchMmuSpec, VirtualTranslate3, VtopFailureCallback, VtopOutputCallback,
9};
10
11use crate::error::{Error, ErrorKind, ErrorOrigin, Result};
12use crate::iter::SplitAtIndex;
13use crate::mem::PhysicalMemory;
14use crate::types::{umem, Address};
15use cglue::tuple::*;
16
17use std::ptr;
18
19pub struct X86Architecture {
20    /// Defines how many bits does the native word size have
21    bits: u8,
22    /// Defines the underlying MMU used for address translation
23    mmu: ArchMmuSpec,
24}
25
26impl Architecture for X86Architecture {
27    fn bits(&self) -> u8 {
28        self.bits
29    }
30
31    fn endianess(&self) -> Endianess {
32        self.mmu.def.endianess
33    }
34
35    fn page_size(&self) -> usize {
36        self.mmu.page_size_level(1) as usize
37    }
38
39    fn size_addr(&self) -> usize {
40        self.mmu.def.addr_size.into()
41    }
42
43    fn address_space_bits(&self) -> u8 {
44        self.mmu.def.address_space_bits
45    }
46
47    fn ident(&self) -> ArchitectureIdent {
48        ArchitectureIdent::X86(
49            self.bits,
50            ptr::eq(self as *const _, &x32_pae::ARCH_SPEC as *const _),
51        )
52    }
53}
54
55#[derive(Clone, Copy)]
56pub struct X86VirtualTranslate {
57    arch: &'static X86Architecture,
58    dtb: Address,
59}
60
61impl X86VirtualTranslate {
62    pub fn new(arch: &'static X86Architecture, dtb: Address) -> Self {
63        Self { arch, dtb }
64    }
65}
66
67impl VirtualTranslate3 for X86VirtualTranslate {
68    fn virt_to_phys_iter<
69        T: PhysicalMemory + ?Sized,
70        B: SplitAtIndex,
71        VI: Iterator<Item = CTup3<Address, Address, B>>,
72    >(
73        &self,
74        mem: &mut T,
75        addrs: VI,
76        out: &mut VtopOutputCallback<B>,
77        out_fail: &mut VtopFailureCallback<B>,
78        tmp_buf: &mut [std::mem::MaybeUninit<u8>],
79    ) {
80        self.arch
81            .mmu
82            .virt_to_phys_iter(mem, self.dtb, addrs, out, out_fail, tmp_buf)
83    }
84
85    fn translation_table_id(&self, _address: Address) -> umem {
86        self.dtb.to_umem().overflowing_shr(12).0
87    }
88
89    fn arch(&self) -> ArchitectureObj {
90        self.arch
91    }
92}
93
94// This lint doesn't make any sense in our usecase, since we nevel leak ARCH_SPECs, and ARCH is
95// a static trait object with a consistent address.
96fn underlying_arch(arch: ArchitectureObj) -> Option<&'static X86Architecture> {
97    if arch == x64::ARCH {
98        Some(&x64::ARCH_SPEC)
99    } else if arch == x32::ARCH {
100        Some(&x32::ARCH_SPEC)
101    } else if arch == x32_pae::ARCH {
102        Some(&x32_pae::ARCH_SPEC)
103    } else {
104        None
105    }
106}
107
108pub fn new_translator(dtb: Address, arch: ArchitectureObj) -> Result<X86VirtualTranslate> {
109    let arch =
110        underlying_arch(arch).ok_or(Error(ErrorOrigin::Mmu, ErrorKind::InvalidArchitecture))?;
111    Ok(X86VirtualTranslate::new(arch, dtb))
112}
113
114pub fn is_x86_arch(arch: ArchitectureObj) -> bool {
115    underlying_arch(arch).is_some()
116}