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 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 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 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}