vminer_core/arch/
x86_64.rs

1use super::runtime;
2use crate::{endian::LittleEndian, PhysicalAddress, VirtualAddress};
3use bytemuck::{Pod, Zeroable};
4
5#[derive(Debug, Clone, Copy)]
6pub struct X86_64;
7
8#[derive(Debug, Clone, Copy, Pod, Zeroable)]
9#[repr(C)]
10pub struct Vcpu {
11    pub registers: Registers,
12    pub special_registers: SpecialRegisters,
13    pub other_registers: OtherRegisters,
14}
15
16struct MmuDesc;
17
18impl super::MmuDesc for MmuDesc {
19    #[inline]
20    fn is_valid(mmu_entry: crate::addr::MmuEntry) -> bool {
21        mmu_entry.0 & 1 != 0
22    }
23
24    #[inline]
25    fn is_large(mmu_entry: crate::addr::MmuEntry) -> bool {
26        mmu_entry.0 & (1 << 7) != 0
27    }
28}
29
30impl super::Architecture for X86_64 {
31    type Endian = LittleEndian;
32
33    type Registers = Registers;
34    type SpecialRegisters = SpecialRegisters;
35    type OtherRegisters = OtherRegisters;
36
37    #[inline]
38    fn into_runtime(self) -> runtime::Architecture {
39        runtime::Architecture::X86_64(self)
40    }
41
42    #[inline]
43    fn endianness(&self) -> LittleEndian {
44        LittleEndian
45    }
46
47    fn virtual_to_physical<M: crate::Memory + ?Sized>(
48        &self,
49        memory: &M,
50        mmu_addr: PhysicalAddress,
51        addr: VirtualAddress,
52    ) -> crate::TranslationResult<PhysicalAddress> {
53        super::virtual_to_physical::<MmuDesc, M>(memory, mmu_addr, addr)
54    }
55
56    fn find_kernel_pgd<M: crate::Memory + ?Sized>(
57        &self,
58        memory: &M,
59        vcpus: &(impl super::HasVcpus<Arch = Self> + ?Sized),
60        use_per_cpu: bool,
61        additional: &[VirtualAddress],
62    ) -> crate::VmResult<Option<PhysicalAddress>> {
63        // To check if a CR3 is valid, try to translate addresses with it
64        let lstar = VirtualAddress(vcpus.other_registers(crate::VcpuId(0))?.lstar);
65        let addresses = &[additional, &[lstar]];
66        let test = super::make_address_test(vcpus, memory, use_per_cpu, addresses);
67
68        // First, try cr3 registers
69        for vcpu in vcpus.iter_vcpus() {
70            let addr = vcpus.pgd(vcpu)?;
71            if test(addr) {
72                return Ok(Some(addr));
73            }
74        }
75
76        // If it didn't work, try all addresses !
77        Ok(super::try_all_addresses(test))
78    }
79
80    fn find_in_kernel_memory_raw<M: crate::Memory + ?Sized>(
81        &self,
82        memory: &M,
83        mmu_addr: PhysicalAddress,
84        base_search_addr: VirtualAddress,
85        finder: &memchr::memmem::Finder,
86        buf: &mut [u8],
87    ) -> crate::MemoryAccessResult<Option<VirtualAddress>> {
88        super::find_in_kernel_memory_raw::<MmuDesc, M>(
89            memory,
90            mmu_addr,
91            base_search_addr,
92            finder,
93            buf,
94        )
95    }
96
97    fn find_in_kernel_memory<M: crate::Memory + ?Sized>(
98        &self,
99        memory: &M,
100        mmu_addr: PhysicalAddress,
101        needle: &[u8],
102    ) -> crate::MemoryAccessResult<Option<VirtualAddress>> {
103        super::find_in_kernel_memory::<MmuDesc, M>(memory, mmu_addr, needle, self.kernel_base())
104    }
105
106    #[inline]
107    fn kernel_base(&self) -> VirtualAddress {
108        VirtualAddress(0xffff_f800_0000_0000)
109    }
110
111    fn instruction_pointer<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
112        &self,
113        vcpus: &Vcpus,
114        vcpu: crate::VcpuId,
115    ) -> crate::VcpuResult<VirtualAddress> {
116        let regs = vcpus.registers(vcpu)?;
117        Ok(VirtualAddress(regs.rip))
118    }
119
120    fn stack_pointer<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
121        &self,
122        vcpus: &Vcpus,
123        vcpu: crate::VcpuId,
124    ) -> crate::VcpuResult<VirtualAddress> {
125        let regs = vcpus.registers(vcpu)?;
126        Ok(VirtualAddress(regs.rsp))
127    }
128
129    fn base_pointer<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
130        &self,
131        vcpus: &Vcpus,
132        vcpu: crate::VcpuId,
133    ) -> crate::VcpuResult<Option<VirtualAddress>> {
134        let regs = vcpus.registers(vcpu)?;
135        Ok(Some(VirtualAddress(regs.rbp)))
136    }
137
138    fn pgd<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
139        &self,
140        vcpus: &Vcpus,
141        vcpu: crate::VcpuId,
142    ) -> crate::VcpuResult<PhysicalAddress> {
143        let regs = vcpus.special_registers(vcpu)?;
144        Ok(PhysicalAddress(regs.cr3))
145    }
146
147    fn kernel_per_cpu<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
148        &self,
149        vcpus: &Vcpus,
150        vcpu: crate::VcpuId,
151    ) -> crate::VcpuResult<Option<VirtualAddress>> {
152        let per_cpu = VirtualAddress(vcpus.special_registers(vcpu)?.gs.base);
153        if per_cpu.is_kernel() {
154            return Ok(Some(per_cpu));
155        }
156
157        let per_cpu = VirtualAddress(vcpus.other_registers(vcpu)?.gs_kernel_base);
158        if per_cpu.is_kernel() {
159            return Ok(Some(per_cpu));
160        }
161
162        Ok(None)
163    }
164}
165
166#[repr(C)]
167#[derive(Debug, Clone, Copy, Pod, Zeroable)]
168pub struct Registers {
169    pub rax: u64,
170    pub rbx: u64,
171    pub rcx: u64,
172    pub rdx: u64,
173    pub rsi: u64,
174    pub rdi: u64,
175    pub rsp: u64,
176    pub rbp: u64,
177    pub r8: u64,
178    pub r9: u64,
179    pub r10: u64,
180    pub r11: u64,
181    pub r12: u64,
182    pub r13: u64,
183    pub r14: u64,
184    pub r15: u64,
185    pub rip: u64,
186    pub rflags: u64,
187}
188
189#[repr(C)]
190#[derive(Debug, Clone, Copy, Pod, Zeroable)]
191pub struct Segment {
192    pub base: u64,
193    pub limit: u32,
194    pub selector: u16,
195    pub type_: u8,
196    pub present: u8,
197    pub dpl: u8,
198    pub db: u8,
199    pub s: u8,
200    pub l: u8,
201    pub g: u8,
202    pub avl: u8,
203    pub unusable: u8,
204    pub padding: u8,
205}
206
207#[repr(C)]
208#[derive(Debug, Clone, Copy, Pod, Zeroable)]
209pub struct Dtable {
210    pub base: u64,
211    pub limit: u16,
212    pub padding: [u16; 3],
213}
214
215#[repr(C)]
216#[derive(Debug, Clone, Copy, Pod, Zeroable)]
217pub struct SpecialRegisters {
218    pub cs: Segment,
219    pub ds: Segment,
220    pub es: Segment,
221    pub fs: Segment,
222    pub gs: Segment,
223    pub ss: Segment,
224    pub tr: Segment,
225    pub ldt: Segment,
226    pub gdt: Dtable,
227    pub idt: Dtable,
228    pub cr0: u64,
229    pub cr2: u64,
230    pub cr3: u64,
231    pub cr4: u64,
232    pub cr8: u64,
233    pub efer: u64,
234    pub apic_base: u64,
235    pub interrupt_bitmap: [u64; 4],
236}
237
238#[repr(C)]
239#[derive(Debug, Clone, Copy, Pod, Zeroable)]
240pub struct OtherRegisters {
241    pub lstar: u64,
242    pub gs_kernel_base: u64,
243}
244
245impl From<Registers> for super::runtime::Registers {
246    #[inline]
247    fn from(regs: Registers) -> Self {
248        Self::X86_64(regs)
249    }
250}
251
252impl From<SpecialRegisters> for super::runtime::SpecialRegisters {
253    #[inline]
254    fn from(regs: SpecialRegisters) -> Self {
255        Self::X86_64(regs)
256    }
257}
258
259impl From<OtherRegisters> for super::runtime::OtherRegisters {
260    #[inline]
261    fn from(regs: OtherRegisters) -> Self {
262        Self::X86_64(regs)
263    }
264}