1mod address;
4mod cr;
5mod descriptor;
6mod dr;
7mod event;
8mod interrupt;
9mod msr;
10mod paging;
11mod registers;
12mod rflags;
13mod segment;
14mod translation;
15
16use vmi_core::{
17 AccessContext, AddressContext, Architecture, Gfn, MemoryAccess, Pa, Va, VmiCore, VmiError,
18 arch::GpRegisters as _, driver::VmiRead,
19};
20use zerocopy::FromBytes;
21
22pub use self::{
23 cr::{ControlRegister, Cr0, Cr2, Cr3, Cr4},
24 descriptor::{Gdtr, Idtr},
25 dr::{Dr0, Dr1, Dr2, Dr3, Dr6, Dr7},
26 event::{
27 EventCpuId, EventHypercall, EventInterrupt, EventIo, EventIoDirection, EventMemoryAccess,
28 EventMonitor, EventReason, EventSinglestep, EventWriteCr, EventWriteMsr, MemoryAccessFlags,
29 },
30 interrupt::{ExceptionVector, Idt, IdtAccess, IdtEntry, Interrupt, InterruptType},
31 msr::{Msr, MsrEfer},
32 paging::{PageTableEntry, PageTableLevel, PagingMode},
33 registers::{GpRegisters, Registers},
34 rflags::Rflags,
35 segment::{
36 DescriptorTable, DescriptorType, Granularity, OperationSize, SegmentAccess,
37 SegmentDescriptor, Selector,
38 },
39 translation::{TranslationEntries, TranslationEntry, VaTranslation},
40};
41
42#[derive(Debug)]
44pub struct Amd64;
45
46impl Architecture for Amd64 {
47 const PAGE_SIZE: u64 = 0x1000;
48 const PAGE_SHIFT: u64 = 12;
49 const PAGE_MASK: u64 = 0xFFFFFFFFFFFFF000;
50
51 const BREAKPOINT: &'static [u8] = &[0xcc];
52
53 type Registers = Registers;
54 type PageTableLevel = PageTableLevel;
55 type Interrupt = Interrupt;
56 type SpecialRegister = ControlRegister;
57
58 type EventMonitor = EventMonitor;
59 type EventReason = EventReason;
60
61 fn gfn_from_pa(pa: Pa) -> Gfn {
62 Gfn(pa.0 >> Self::PAGE_SHIFT)
63 }
64
65 fn pa_from_gfn(gfn: Gfn) -> Pa {
66 Pa(gfn.0 << Self::PAGE_SHIFT)
67 }
68
69 fn pa_in_gfn(gfn: Gfn, va: Va) -> Pa {
70 Self::pa_in_gfn_for(gfn, va, PageTableLevel::Pt)
71 }
72
73 fn pa_in_gfn_for(gfn: Gfn, va: Va, level: Self::PageTableLevel) -> Pa {
74 Self::pa_from_gfn(gfn) + Self::va_offset_for(va, level)
75 }
76
77 fn pa_offset(pa: Pa) -> u64 {
78 pa.0 & !Self::PAGE_MASK
79 }
80
81 fn va_align_down(va: Va) -> Va {
82 Self::va_align_down_for(va, PageTableLevel::Pt)
83 }
84
85 fn va_align_down_for(va: Va, level: Self::PageTableLevel) -> Va {
86 let mask = match level {
87 PageTableLevel::Pt => !0xfff,
88 PageTableLevel::Pd => !0x1fffff,
89 PageTableLevel::Pdpt => !0x3fffffff,
90 PageTableLevel::Pml4 => !0x7fffffffff,
91 };
92
93 va & mask
94 }
95
96 fn va_align_up(va: Va) -> Va {
97 Self::va_align_up_for(va, PageTableLevel::Pt)
98 }
99
100 fn va_align_up_for(va: Va, level: Self::PageTableLevel) -> Va {
101 let mask = match level {
102 PageTableLevel::Pt => 0xfff,
103 PageTableLevel::Pd => 0x1fffff,
104 PageTableLevel::Pdpt => 0x3fffffff,
105 PageTableLevel::Pml4 => 0x7fffffffff,
106 };
107
108 (va + mask) & !mask
109 }
110
111 fn va_offset(va: Va) -> u64 {
112 Self::va_offset_for(va, PageTableLevel::Pt)
113 }
114
115 fn va_offset_for(va: Va, level: Self::PageTableLevel) -> u64 {
116 match level {
117 PageTableLevel::Pt => va.0 & 0xfff,
119
120 PageTableLevel::Pd => va.0 & 0x1fffff,
122
123 PageTableLevel::Pdpt => va.0 & 0x3fffffff,
125
126 PageTableLevel::Pml4 => va.0 & 0x7fffffffff,
128 }
129 }
130
131 fn va_index(va: Va) -> u64 {
132 Self::va_index_for(va, PageTableLevel::Pt)
133 }
134
135 fn va_index_for(va: Va, level: Self::PageTableLevel) -> u64 {
136 match level {
137 PageTableLevel::Pt => (va.0 >> 12) & 0x1ff,
138 PageTableLevel::Pd => (va.0 >> 21) & 0x1ff,
139 PageTableLevel::Pdpt => (va.0 >> 30) & 0x1ff,
140 PageTableLevel::Pml4 => (va.0 >> 39) & 0x1ff,
141 }
142 }
143
144 fn translate_address<Driver>(vmi: &VmiCore<Driver>, va: Va, root: Pa) -> Result<Pa, VmiError>
145 where
146 Driver: VmiRead<Architecture = Self>,
147 {
148 let buffer = vmi.read_page(Self::gfn_from_pa(root))?;
150 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
151
152 let pml4i = Self::va_index_for(va, PageTableLevel::Pml4) as usize;
153 let pml4e = page_table[pml4i];
154
155 if !pml4e.present() {
156 return Err(VmiError::translation((va, root)));
157 }
158
159 if pml4e.large() {
160 return Ok(Self::pa_in_gfn_for(pml4e.pfn(), va, PageTableLevel::Pml4));
161 }
162
163 let buffer = vmi.read_page(pml4e.pfn())?;
165 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
166
167 let pdpti = Self::va_index_for(va, PageTableLevel::Pdpt) as usize;
168 let pdpte = page_table[pdpti];
169
170 if !pdpte.present() {
171 return Err(VmiError::translation((va, root)));
172 }
173
174 if pdpte.large() {
175 return Ok(Self::pa_in_gfn_for(pdpte.pfn(), va, PageTableLevel::Pdpt));
176 }
177
178 let buffer = vmi.read_page(pdpte.pfn())?;
180 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
181
182 let pdi = Self::va_index_for(va, PageTableLevel::Pd) as usize;
183 let pde = page_table[pdi];
184
185 if !pde.present() {
186 return Err(VmiError::translation((va, root)));
187 }
188
189 if pde.large() {
190 return Ok(Self::pa_in_gfn_for(pde.pfn(), va, PageTableLevel::Pd));
191 }
192
193 let buffer = vmi.read_page(pde.pfn())?;
195 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
196
197 let pti = Self::va_index_for(va, PageTableLevel::Pt) as usize;
198 let pte = page_table[pti];
199
200 if !pte.present() {
201 return Err(VmiError::translation((va, root)));
202 }
203
204 Ok(Self::pa_in_gfn_for(pte.pfn(), va, PageTableLevel::Pt))
205 }
206}
207
208impl Amd64 {
209 pub fn va_canonical(va: Va) -> Va {
211 const BITS: u64 = 48;
212 const MASK: u64 = (1 << BITS) - 1;
213
214 Va(va.0 & MASK)
215 }
216
217 pub fn paging_mode(registers: &Registers) -> Option<PagingMode> {
230 if !registers.cr0.paging() {
231 return None;
232 }
233
234 if !registers.cr4.physical_address_extension() {
235 return Some(PagingMode::Legacy);
236 }
237
238 if !registers.msr_efer.long_mode_enable() {
239 return Some(PagingMode::PAE);
240 }
241
242 if !registers.cr4.linear_address_57_bit() {
243 return Some(PagingMode::Ia32e);
244 }
245
246 Some(PagingMode::Ia32eLA57)
247 }
248
249 pub fn interrupt_descriptor_table<Driver>(
252 vmi: &VmiCore<Driver>,
253 registers: &Registers,
254 ) -> Result<Idt, VmiError>
255 where
256 Driver: VmiRead<Architecture = Self>,
257 {
258 let idtr_base = registers.idtr.base.into();
259 vmi.read_struct::<Idt>((idtr_base, registers.cr3.into()))
260 }
261
262 pub fn translation<Driver>(vmi: &VmiCore<Driver>, va: Va, root: Pa) -> VaTranslation
302 where
303 Driver: VmiRead<Architecture = Self>,
304 {
305 let mut entries = TranslationEntries::new();
306 let va = Self::va_canonical(va);
307
308 let buffer = match vmi.read_page(Self::gfn_from_pa(root)) {
310 Ok(buffer) => buffer,
311 Err(_) => return VaTranslation { entries, pa: None },
312 };
313 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
314 let pml4i = Self::va_index_for(va, PageTableLevel::Pml4) as usize;
315 let pml4e = page_table[pml4i];
316
317 entries.push(TranslationEntry {
318 level: PageTableLevel::Pml4,
319 entry: pml4e,
320 entry_address: root + (pml4i * size_of::<PageTableEntry>()) as u64,
321 });
322
323 if !pml4e.present() {
324 return VaTranslation { entries, pa: None };
325 }
326
327 if pml4e.large() {
328 return VaTranslation {
329 entries,
330 pa: Some(Self::pa_in_gfn_for(pml4e.pfn(), va, PageTableLevel::Pml4)),
331 };
332 }
333
334 let buffer = match vmi.read_page(pml4e.pfn()) {
336 Ok(buffer) => buffer,
337 Err(_) => return VaTranslation { entries, pa: None },
338 };
339 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
340 let pdpti = Self::va_index_for(va, PageTableLevel::Pdpt) as usize;
341 let pdpte = page_table[pdpti];
342
343 entries.push(TranslationEntry {
344 level: PageTableLevel::Pdpt,
345 entry: pdpte,
346 entry_address: Self::pa_from_gfn(pml4e.pfn())
347 + (pdpti * size_of::<PageTableEntry>()) as u64,
348 });
349
350 if !pdpte.present() {
351 return VaTranslation { entries, pa: None };
352 }
353
354 if pdpte.large() {
355 return VaTranslation {
356 entries,
357 pa: Some(Self::pa_in_gfn_for(pdpte.pfn(), va, PageTableLevel::Pdpt)),
358 };
359 }
360
361 let buffer = match vmi.read_page(pdpte.pfn()) {
363 Ok(buffer) => buffer,
364 Err(_) => return VaTranslation { entries, pa: None },
365 };
366 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
367 let pdi = Self::va_index_for(va, PageTableLevel::Pd) as usize;
368 let pde = page_table[pdi];
369
370 entries.push(TranslationEntry {
371 level: PageTableLevel::Pd,
372 entry: pde,
373 entry_address: Self::pa_from_gfn(pdpte.pfn())
374 + (pdi * size_of::<PageTableEntry>()) as u64,
375 });
376
377 if !pde.present() {
378 return VaTranslation { entries, pa: None };
379 }
380
381 if pde.large() {
382 return VaTranslation {
383 entries,
384 pa: Some(Self::pa_in_gfn_for(pde.pfn(), va, PageTableLevel::Pd)),
385 };
386 }
387
388 let buffer = match vmi.read_page(pde.pfn()) {
390 Ok(buffer) => buffer,
391 Err(_) => return VaTranslation { entries, pa: None },
392 };
393 let page_table = <[PageTableEntry]>::ref_from_bytes(&buffer).unwrap();
394 let pti = Self::va_index_for(va, PageTableLevel::Pt) as usize;
395 let pte = page_table[pti];
396
397 entries.push(TranslationEntry {
398 level: PageTableLevel::Pt,
399 entry: pte,
400 entry_address: Self::pa_from_gfn(pde.pfn())
401 + (pti * size_of::<PageTableEntry>()) as u64,
402 });
403
404 VaTranslation {
405 entries,
406 pa: Some(Self::pa_in_gfn_for(pte.pfn(), va, PageTableLevel::Pt)),
407 }
408 }
409}
410
411impl vmi_core::arch::GpRegisters for GpRegisters {
412 type Architecture = Amd64;
413
414 fn instruction_pointer(&self) -> u64 {
415 self.rip
416 }
417
418 fn set_instruction_pointer(&mut self, ip: u64) {
419 self.rip = ip;
420 }
421
422 fn stack_pointer(&self) -> u64 {
423 self.rsp
424 }
425
426 fn set_stack_pointer(&mut self, sp: u64) {
427 self.rsp = sp;
428 }
429
430 fn result(&self) -> u64 {
431 self.rax
432 }
433
434 fn set_result(&mut self, result: u64) {
435 self.rax = result;
436 }
437}
438
439impl vmi_core::arch::Registers for Registers {
440 type Architecture = Amd64;
441
442 type GpRegisters = GpRegisters;
443
444 fn instruction_pointer(&self) -> u64 {
445 self.rip
446 }
447
448 fn set_instruction_pointer(&mut self, ip: u64) {
449 self.rip = ip;
450 }
451
452 fn stack_pointer(&self) -> u64 {
453 self.rsp
454 }
455
456 fn set_stack_pointer(&mut self, sp: u64) {
457 self.rsp = sp;
458 }
459
460 fn result(&self) -> u64 {
461 self.rax
462 }
463
464 fn set_result(&mut self, result: u64) {
465 self.rax = result;
466 }
467
468 fn gp_registers(&self) -> GpRegisters {
469 GpRegisters {
470 rax: self.rax,
471 rbx: self.rbx,
472 rcx: self.rcx,
473 rdx: self.rdx,
474 rbp: self.rbp,
475 rsi: self.rsi,
476 rdi: self.rdi,
477 rsp: self.rsp,
478 r8: self.r8,
479 r9: self.r9,
480 r10: self.r10,
481 r11: self.r11,
482 r12: self.r12,
483 r13: self.r13,
484 r14: self.r14,
485 r15: self.r15,
486 rip: self.rip,
487 rflags: self.rflags,
488 }
489 }
490
491 fn set_gp_registers(&mut self, gp: &GpRegisters) {
492 self.rax = gp.rax;
493 self.rbx = gp.rbx;
494 self.rcx = gp.rcx;
495 self.rdx = gp.rdx;
496 self.rbp = gp.rbp;
497 self.rsi = gp.rsi;
498 self.rdi = gp.rdi;
499 self.rsp = gp.rsp;
500 self.r8 = gp.r8;
501 self.r9 = gp.r9;
502 self.r10 = gp.r10;
503 self.r11 = gp.r11;
504 self.r12 = gp.r12;
505 self.r13 = gp.r13;
506 self.r14 = gp.r14;
507 self.r15 = gp.r15;
508 self.rip = gp.rip;
509 self.rflags = gp.rflags;
510 }
511
512 fn address_width(&self) -> usize {
513 Amd64::paging_mode(self).map_or(0, PagingMode::address_width)
514 }
515
516 fn effective_address_width(&self) -> usize {
517 match Amd64::paging_mode(self) {
538 Some(PagingMode::Ia32e | PagingMode::Ia32eLA57) if !self.cs.access.long_mode() => 4,
539 Some(paging_mode) => paging_mode.address_width(),
540 _ => 0,
541 }
542 }
543
544 fn access_context(&self, va: Va) -> AccessContext {
545 self.address_context(va).into()
546 }
547
548 fn address_context(&self, va: Va) -> AddressContext {
549 (va, self.cr3.into()).into()
550 }
551
552 fn translation_root(&self, _va: Va) -> Pa {
553 self.cr3.into()
554 }
555
556 fn set_translation_root(&mut self, root: u64, _va: Va) {
557 self.cr3 = Cr3(root);
558 }
559
560 fn return_address<Driver>(&self, vmi: &VmiCore<Driver>) -> Result<Va, VmiError>
561 where
562 Driver: VmiRead,
563 {
564 vmi.read_va(
565 (self.rsp.into(), self.cr3.into()),
566 self.effective_address_width(),
567 )
568 }
569
570 fn return_from_function<Driver>(
571 &self,
572 vmi: &VmiCore<Driver>,
573 value: u64,
574 ) -> Result<Self::GpRegisters, VmiError>
575 where
576 Driver: VmiRead<Architecture = Amd64>,
577 {
578 let return_address = self.return_address(vmi)?;
579
580 let mut gp = self.gp_registers();
581 gp.set_result(value);
582 gp.set_instruction_pointer(return_address.into());
583 gp.set_stack_pointer(self.rsp + self.effective_address_width() as u64);
584
585 Ok(gp)
586 }
587}
588
589impl vmi_core::arch::EventMemoryAccess for EventMemoryAccess {
590 type Architecture = Amd64;
591
592 fn pa(&self) -> Pa {
593 self.pa
594 }
595
596 fn va(&self) -> Va {
597 self.va
598 }
599
600 fn access(&self) -> MemoryAccess {
601 self.access
602 }
603}
604
605impl vmi_core::arch::EventInterrupt for EventInterrupt {
606 type Architecture = Amd64;
607
608 fn gfn(&self) -> Gfn {
609 self.gfn
610 }
611}
612
613impl vmi_core::arch::EventReason for EventReason {
614 type Architecture = Amd64;
615
616 fn as_memory_access(
617 &self,
618 ) -> Option<&impl vmi_core::arch::EventMemoryAccess<Architecture = Amd64>> {
619 match self {
620 EventReason::MemoryAccess(memory_access) => Some(memory_access),
621 _ => None,
622 }
623 }
624
625 fn as_interrupt(&self) -> Option<&impl vmi_core::arch::EventInterrupt<Architecture = Amd64>> {
626 match self {
627 EventReason::Interrupt(interrupt) => Some(interrupt),
628 _ => None,
629 }
630 }
631
632 fn as_software_breakpoint(
633 &self,
634 ) -> Option<&impl vmi_core::arch::EventInterrupt<Architecture = Amd64>> {
635 match self {
636 EventReason::Interrupt(interrupt)
637 if interrupt.interrupt.vector == ExceptionVector::Breakpoint
638 && interrupt.interrupt.typ == InterruptType::SoftwareException =>
639 {
640 Some(interrupt)
641 }
642 _ => None,
643 }
644 }
645}