vminer_core/arch/
aarch64.rs

1use bytemuck::{Pod, Zeroable};
2
3use super::runtime;
4use crate::{endian::LittleEndian, PhysicalAddress, VcpuResult, VirtualAddress};
5
6#[derive(Debug, Clone, Copy)]
7pub struct Aarch64;
8
9#[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
10#[repr(C)]
11pub struct Vcpu {
12    pub registers: Registers,
13    pub special_registers: SpecialRegisters,
14    pub other_registers: OtherRegisters,
15}
16
17struct MmuDesc;
18
19impl super::MmuDesc for MmuDesc {
20    #[inline]
21    fn is_valid(mmu_entry: crate::addr::MmuEntry) -> bool {
22        mmu_entry.0 & 1 != 0
23    }
24
25    #[inline]
26    fn is_large(mmu_entry: crate::addr::MmuEntry) -> bool {
27        mmu_entry.0 & 0b10 == 0
28    }
29}
30
31impl super::Architecture for Aarch64 {
32    type Endian = LittleEndian;
33
34    type Registers = Registers;
35    type SpecialRegisters = SpecialRegisters;
36    type OtherRegisters = OtherRegisters;
37
38    #[inline]
39    fn into_runtime(self) -> runtime::Architecture {
40        runtime::Architecture::Aarch64(self)
41    }
42
43    #[inline]
44    fn endianness(&self) -> LittleEndian {
45        LittleEndian
46    }
47
48    fn virtual_to_physical<M: crate::Memory + ?Sized>(
49        &self,
50        memory: &M,
51        mmu_addr: PhysicalAddress,
52        addr: VirtualAddress,
53    ) -> crate::TranslationResult<PhysicalAddress> {
54        super::virtual_to_physical::<MmuDesc, M>(memory, mmu_addr, addr)
55    }
56
57    fn find_kernel_pgd<M: crate::Memory + ?Sized>(
58        &self,
59        memory: &M,
60        vcpus: &(impl super::HasVcpus<Arch = Self> + ?Sized),
61        use_per_cpu: bool,
62        additional: &[VirtualAddress],
63    ) -> crate::VmResult<Option<PhysicalAddress>> {
64        for vcpu in vcpus.iter_vcpus() {
65            if vcpus.instruction_pointer(vcpu)?.is_kernel() {
66                return Ok(Some(vcpus.pgd(vcpu)?));
67            }
68        }
69
70        // To check if a TTBR is valid, try to translate valid kernel addresses with it
71        let addresses = &[additional];
72        let test = super::make_address_test(vcpus, memory, use_per_cpu, addresses);
73
74        // // Try pages near a "wrong" TTBR1
75        // if let Some(vcpu) = vcpus
76        //     .iter_vcpus()
77        //     .find(|vcpu| vcpus.instruction_pointer( vcpu).is_kernel())
78        // {
79        //     for i in -5..6 {
80        //         let ttbr1 = vcpu.cleaned_ttbr1() + i * 4096i64;
81        //         if test(ttbr1) {
82        //             return Some(ttbr1);
83        //         }
84        //     }
85        // }
86
87        Ok(super::try_all_addresses(test))
88    }
89
90    fn find_in_kernel_memory_raw<M: crate::Memory + ?Sized>(
91        &self,
92        memory: &M,
93        mmu_addr: PhysicalAddress,
94        base_search_addr: VirtualAddress,
95        finder: &memchr::memmem::Finder,
96        buf: &mut [u8],
97    ) -> crate::MemoryAccessResult<Option<VirtualAddress>> {
98        super::find_in_kernel_memory_raw::<MmuDesc, M>(
99            memory,
100            mmu_addr,
101            base_search_addr,
102            finder,
103            buf,
104        )
105    }
106
107    fn find_in_kernel_memory<M: crate::Memory + ?Sized>(
108        &self,
109        memory: &M,
110        mmu_addr: PhysicalAddress,
111        needle: &[u8],
112    ) -> crate::MemoryAccessResult<Option<VirtualAddress>> {
113        super::find_in_kernel_memory::<MmuDesc, M>(memory, mmu_addr, needle, self.kernel_base())
114    }
115
116    #[inline]
117    fn kernel_base(&self) -> VirtualAddress {
118        VirtualAddress(0xffff_a000_0000_0000)
119    }
120
121    fn instruction_pointer<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
122        &self,
123        vcpus: &Vcpus,
124        vcpu: crate::VcpuId,
125    ) -> VcpuResult<VirtualAddress> {
126        let registers = vcpus.registers(vcpu)?;
127        Ok(VirtualAddress(registers.pc))
128    }
129
130    fn stack_pointer<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
131        &self,
132        vcpus: &Vcpus,
133        vcpu: crate::VcpuId,
134    ) -> VcpuResult<VirtualAddress> {
135        let sp = if self.instruction_pointer(vcpus, vcpu)?.is_kernel() {
136            vcpus.special_registers(vcpu)?.sp_el1
137        } else {
138            vcpus.registers(vcpu)?.sp
139        };
140        Ok(VirtualAddress(sp))
141    }
142
143    fn base_pointer<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
144        &self,
145        vcpus: &Vcpus,
146        vcpu: crate::VcpuId,
147    ) -> VcpuResult<Option<VirtualAddress>> {
148        let registers = vcpus.registers(vcpu)?;
149        Ok(Some(VirtualAddress(registers.regs[29])))
150    }
151
152    fn pgd<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
153        &self,
154        vcpus: &Vcpus,
155        vcpu: crate::VcpuId,
156    ) -> VcpuResult<PhysicalAddress> {
157        use super::MmuDesc as _;
158
159        let s_registers = vcpus.special_registers(vcpu)?;
160
161        let ttbr = if self.instruction_pointer(vcpus, vcpu)?.is_kernel() {
162            s_registers.ttbr1_el1
163        } else {
164            s_registers.ttbr0_el1
165        };
166        Ok(PhysicalAddress(ttbr & crate::mask(MmuDesc::ADDR_BITS)))
167    }
168
169    fn kernel_per_cpu<Vcpus: super::HasVcpus<Arch = Self> + ?Sized>(
170        &self,
171        _vcpus: &Vcpus,
172        _vcpu: crate::VcpuId,
173    ) -> VcpuResult<Option<VirtualAddress>> {
174        Ok(None)
175    }
176}
177
178#[repr(C)]
179#[derive(Debug, Clone, Copy, Pod, Zeroable)]
180pub struct Registers {
181    pub regs: [u64; 31],
182    pub sp: u64,
183    pub pc: u64,
184    pub pstate: u64,
185}
186
187/// A curated list of additional useful registers
188#[repr(C)]
189#[derive(Debug, Clone, Copy, Pod, Zeroable)]
190pub struct SpecialRegisters {
191    pub sp_el1: u64,
192    pub ttbr0_el1: u64,
193    pub ttbr1_el1: u64,
194    pub vbar_el1: u64,
195}
196
197#[repr(C)]
198#[derive(Debug, Clone, Copy, Pod, Zeroable)]
199pub struct OtherRegisters;
200
201impl From<Registers> for super::runtime::Registers {
202    #[inline]
203    fn from(regs: Registers) -> Self {
204        Self::Aarch64(regs)
205    }
206}
207
208impl From<SpecialRegisters> for super::runtime::SpecialRegisters {
209    #[inline]
210    fn from(regs: SpecialRegisters) -> Self {
211        Self::Aarch64(regs)
212    }
213}
214
215impl From<OtherRegisters> for super::runtime::OtherRegisters {
216    #[inline]
217    fn from(regs: OtherRegisters) -> Self {
218        Self::Aarch64(regs)
219    }
220}