1#[cfg(any(unix, feature = "haxm", feature = "whpx"))]
6use std::arch::x86_64::__cpuid;
7use std::arch::x86_64::_rdtsc;
8use std::arch::x86_64::CpuidResult;
9use std::collections::BTreeMap;
10use std::collections::HashSet;
11use std::sync::Arc;
12
13use anyhow::Context;
14use base::custom_serde::deserialize_seq_to_arr;
15use base::custom_serde::serialize_arr;
16use base::error;
17use base::warn;
18use base::Result;
19use bit_field::*;
20use libc::c_void;
21use serde::Deserialize;
22use serde::Serialize;
23use snapshot::AnySnapshot;
24use vm_memory::GuestAddress;
25
26use crate::Hypervisor;
27use crate::IrqRoute;
28use crate::IrqSource;
29use crate::IrqSourceChip;
30use crate::NestedMode;
31use crate::Vcpu;
32use crate::Vm;
33
34const MSR_F15H_PERF_CTL0: u32 = 0xc0010200;
35const MSR_F15H_PERF_CTL1: u32 = 0xc0010202;
36const MSR_F15H_PERF_CTL2: u32 = 0xc0010204;
37const MSR_F15H_PERF_CTL3: u32 = 0xc0010206;
38const MSR_F15H_PERF_CTL4: u32 = 0xc0010208;
39const MSR_F15H_PERF_CTL5: u32 = 0xc001020a;
40const MSR_F15H_PERF_CTR0: u32 = 0xc0010201;
41const MSR_F15H_PERF_CTR1: u32 = 0xc0010203;
42const MSR_F15H_PERF_CTR2: u32 = 0xc0010205;
43const MSR_F15H_PERF_CTR3: u32 = 0xc0010207;
44const MSR_F15H_PERF_CTR4: u32 = 0xc0010209;
45const MSR_F15H_PERF_CTR5: u32 = 0xc001020b;
46const MSR_IA32_PERF_CAPABILITIES: u32 = 0x00000345;
47
48pub trait HypervisorX86_64: Hypervisor {
50 fn get_supported_cpuid(&self) -> Result<CpuId>;
52
53 fn get_msr_index_list(&self) -> Result<Vec<u32>>;
55}
56
57pub trait VmX86_64: Vm {
59 fn get_hypervisor(&self) -> &dyn HypervisorX86_64;
61
62 fn create_vcpu(&self, id: usize) -> Result<Arc<dyn VcpuX86_64>>;
64
65 fn set_tss_addr(&self, addr: GuestAddress) -> Result<()>;
67
68 fn set_identity_map_addr(&self, addr: GuestAddress) -> Result<()>;
70
71 fn load_protected_vm_firmware(&self, fw_addr: GuestAddress, fw_max_size: u64) -> Result<()>;
75}
76
77pub trait VcpuX86_64: Vcpu {
79 fn set_interrupt_window_requested(&self, requested: bool);
82
83 fn ready_for_interrupt(&self) -> bool;
85
86 fn interrupt(&self, irq: u8) -> Result<()>;
98
99 fn inject_nmi(&self) -> Result<()>;
101
102 fn get_regs(&self) -> Result<Regs>;
104
105 fn set_regs(&self, regs: &Regs) -> Result<()>;
107
108 fn get_sregs(&self) -> Result<Sregs>;
110
111 fn set_sregs(&self, sregs: &Sregs) -> Result<()>;
113
114 fn get_fpu(&self) -> Result<Fpu>;
116
117 fn set_fpu(&self, fpu: &Fpu) -> Result<()>;
119
120 fn get_debugregs(&self) -> Result<DebugRegs>;
122
123 fn set_debugregs(&self, debugregs: &DebugRegs) -> Result<()>;
125
126 fn get_xcrs(&self) -> Result<BTreeMap<u32, u64>>;
128
129 fn set_xcr(&self, xcr: u32, value: u64) -> Result<()>;
131
132 fn get_xsave(&self) -> Result<Xsave>;
134
135 fn set_xsave(&self, xsave: &Xsave) -> Result<()>;
137
138 fn get_hypervisor_specific_state(&self) -> Result<AnySnapshot>;
142
143 fn set_hypervisor_specific_state(&self, data: AnySnapshot) -> Result<()>;
146
147 fn get_msr(&self, msr_index: u32) -> Result<u64>;
149
150 fn get_all_msrs(&self) -> Result<BTreeMap<u32, u64>>;
152
153 fn set_msr(&self, msr_index: u32, value: u64) -> Result<()>;
155
156 fn set_cpuid(&self, cpuid: &CpuId) -> Result<()>;
158
159 fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>;
161
162 fn handle_cpuid(&self, entry: &CpuIdEntry) -> Result<()>;
166
167 fn get_tsc_offset(&self) -> Result<u64> {
171 let host_before_tsc = unsafe { _rdtsc() };
174
175 let guest_tsc = self.get_msr(crate::MSR_IA32_TSC)?;
177
178 let host_after_tsc = unsafe { _rdtsc() };
181
182 let host_tsc = ((host_before_tsc as u128 + host_after_tsc as u128) / 2) as u64;
184
185 Ok(guest_tsc.wrapping_sub(host_tsc))
186 }
187
188 fn set_tsc_offset(&self, offset: u64) -> Result<()> {
209 let host_tsc = unsafe { _rdtsc() };
211 self.set_tsc_value(host_tsc.wrapping_add(offset))
212 }
213
214 fn set_tsc_value(&self, value: u64) -> Result<()> {
221 self.set_msr(crate::MSR_IA32_TSC, value)
222 }
223
224 fn restore_timekeeping(&self, host_tsc_reference_moment: u64, tsc_offset: u64) -> Result<()>;
229
230 fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> {
232 Ok(VcpuSnapshot {
233 vcpu_id: self.id(),
234 regs: self.get_regs()?,
235 sregs: self.get_sregs()?,
236 debug_regs: self.get_debugregs()?,
237 xcrs: self.get_xcrs()?,
238 msrs: self.get_all_msrs()?,
239 xsave: self.get_xsave()?,
240 hypervisor_data: self.get_hypervisor_specific_state()?,
241 tsc_offset: self.get_tsc_offset()?,
242 })
243 }
244
245 fn restore(
246 &self,
247 snapshot: &VcpuSnapshot,
248 host_tsc_reference_moment: u64,
249 ) -> anyhow::Result<()> {
250 let msr_allowlist = HashSet::from([
255 MSR_F15H_PERF_CTL0,
256 MSR_F15H_PERF_CTL1,
257 MSR_F15H_PERF_CTL2,
258 MSR_F15H_PERF_CTL3,
259 MSR_F15H_PERF_CTL4,
260 MSR_F15H_PERF_CTL5,
261 MSR_F15H_PERF_CTR0,
262 MSR_F15H_PERF_CTR1,
263 MSR_F15H_PERF_CTR2,
264 MSR_F15H_PERF_CTR3,
265 MSR_F15H_PERF_CTR4,
266 MSR_F15H_PERF_CTR5,
267 MSR_IA32_PERF_CAPABILITIES,
268 ]);
269 assert_eq!(snapshot.vcpu_id, self.id());
270 self.set_regs(&snapshot.regs)?;
271 self.set_sregs(&snapshot.sregs)?;
272 self.set_debugregs(&snapshot.debug_regs)?;
273 for (xcr_index, value) in &snapshot.xcrs {
274 self.set_xcr(*xcr_index, *value)?;
275 }
276
277 for (msr_index, value) in snapshot.msrs.iter() {
278 if self.get_msr(*msr_index) == Ok(*value) {
279 continue; }
281 if let Err(e) = self.set_msr(*msr_index, *value) {
282 if msr_allowlist.contains(msr_index) {
283 warn!(
284 "Failed to set MSR. MSR might not be supported in this kernel. Err: {}",
285 e
286 );
287 } else {
288 return Err(e).context(
289 "Failed to set MSR. MSR might not be supported by the CPU or by the kernel,
290 and was not allow-listed.",
291 );
292 }
293 };
294 }
295 self.set_xsave(&snapshot.xsave)?;
296 self.set_hypervisor_specific_state(snapshot.hypervisor_data.clone())?;
297 self.restore_timekeeping(host_tsc_reference_moment, snapshot.tsc_offset)?;
298 Ok(())
299 }
300}
301
302#[derive(Clone, Debug, Serialize, Deserialize)]
304pub struct VcpuSnapshot {
305 pub vcpu_id: usize,
306 regs: Regs,
307 sregs: Sregs,
308 debug_regs: DebugRegs,
309 xcrs: BTreeMap<u32, u64>,
310 msrs: BTreeMap<u32, u64>,
311 xsave: Xsave,
312 hypervisor_data: AnySnapshot,
313 tsc_offset: u64,
314}
315
316pub const MSR_IA32_TSC: u32 = 0x00000010;
318
319#[cfg(any(unix, feature = "haxm", feature = "whpx"))]
321pub(crate) fn host_phys_addr_bits() -> u8 {
322 let highest_ext_function = unsafe { __cpuid(0x80000000) };
324 if highest_ext_function.eax >= 0x80000008 {
325 let addr_size = unsafe { __cpuid(0x80000008) };
327 addr_size.eax as u8
329 } else {
330 36
331 }
332}
333
334#[derive(Clone, Default)]
336pub struct VcpuInitX86_64 {
337 pub regs: Regs,
339
340 pub sregs: Sregs,
342
343 pub fpu: Fpu,
345
346 pub msrs: BTreeMap<u32, u64>,
348}
349
350#[derive(Clone, Debug, PartialEq, Eq)]
352pub struct CpuConfigX86_64 {
353 pub force_calibrated_tsc_leaf: bool,
355
356 pub host_cpu_topology: bool,
358
359 pub enable_hwp: bool,
361
362 pub no_smt: bool,
364
365 pub itmt: bool,
367
368 pub hybrid_type: Option<CpuHybridType>,
370
371 pub nested: NestedMode,
373}
374
375impl CpuConfigX86_64 {
376 pub fn new(
377 force_calibrated_tsc_leaf: bool,
378 host_cpu_topology: bool,
379 enable_hwp: bool,
380 no_smt: bool,
381 itmt: bool,
382 hybrid_type: Option<CpuHybridType>,
383 nested: NestedMode,
384 ) -> Self {
385 CpuConfigX86_64 {
386 force_calibrated_tsc_leaf,
387 host_cpu_topology,
388 enable_hwp,
389 no_smt,
390 itmt,
391 hybrid_type,
392 nested,
393 }
394 }
395}
396
397#[repr(C)]
403#[derive(Clone, Copy, Debug, PartialEq, Eq)]
404pub struct CpuIdEntry {
405 pub function: u32,
406 pub index: u32,
407 pub flags: u32,
410 pub cpuid: CpuidResult,
411}
412
413pub struct CpuId {
415 pub cpu_id_entries: Vec<CpuIdEntry>,
416}
417
418impl CpuId {
419 pub fn new(initial_capacity: usize) -> Self {
421 CpuId {
422 cpu_id_entries: Vec::with_capacity(initial_capacity),
423 }
424 }
425}
426
427#[bitfield]
428#[derive(Clone, Copy, Debug, PartialEq, Eq)]
429pub enum DestinationMode {
430 Physical = 0,
431 Logical = 1,
432}
433
434#[bitfield]
435#[derive(Clone, Copy, Debug, PartialEq, Eq)]
436pub enum TriggerMode {
437 Edge = 0,
438 Level = 1,
439}
440
441#[bitfield]
442#[derive(Debug, Clone, Copy, PartialEq, Eq)]
443pub enum DeliveryMode {
444 Fixed = 0b000,
445 Lowest = 0b001,
446 SMI = 0b010, RemoteRead = 0b011, NMI = 0b100, Init = 0b101,
450 Startup = 0b110,
451 External = 0b111,
452}
453
454#[bitfield]
459#[derive(Clone, Copy, PartialEq, Eq)]
460pub struct MsiAddressMessage {
461 pub reserved: BitField2,
462 #[bits = 1]
463 pub destination_mode: DestinationMode,
464 pub redirection_hint: BitField1,
465 pub reserved_2: BitField8,
466 pub destination_id: BitField8,
467 pub always_0xfee: BitField12,
469}
470
471#[bitfield]
472#[derive(Clone, Copy, PartialEq, Eq)]
473pub struct MsiDataMessage {
474 pub vector: BitField8,
475 #[bits = 3]
476 pub delivery_mode: DeliveryMode,
477 pub reserved: BitField3,
478 #[bits = 1]
479 pub level: Level,
480 #[bits = 1]
481 pub trigger: TriggerMode,
482 pub reserved2: BitField16,
483}
484
485#[bitfield]
486#[derive(Debug, Clone, Copy, PartialEq, Eq)]
487pub enum DeliveryStatus {
488 Idle = 0,
489 Pending = 1,
490}
491
492#[bitfield]
494#[derive(Debug, Clone, Copy, PartialEq, Eq)]
495pub enum Level {
496 Deassert = 0,
497 Assert = 1,
498}
499
500#[bitfield]
502#[derive(Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
503pub struct IoapicRedirectionTableEntry {
504 vector: BitField8,
505 #[bits = 3]
506 delivery_mode: DeliveryMode,
507 #[bits = 1]
508 dest_mode: DestinationMode,
509 #[bits = 1]
510 delivery_status: DeliveryStatus,
511 polarity: BitField1,
512 remote_irr: bool,
513 #[bits = 1]
514 trigger_mode: TriggerMode,
515 interrupt_mask: bool, reserved: BitField39,
517 dest_id: BitField8,
518}
519
520pub const NUM_IOAPIC_PINS: usize = 24;
522
523#[repr(C)]
525#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
526pub struct IoapicState {
527 pub base_address: u64,
529 pub ioregsel: u8,
531 pub ioapicid: u32,
533 pub current_interrupt_level_bitmap: u32,
535 #[serde(
537 serialize_with = "serialize_arr",
538 deserialize_with = "deserialize_seq_to_arr"
539 )]
540 pub redirect_table: [IoapicRedirectionTableEntry; NUM_IOAPIC_PINS],
541}
542
543impl Default for IoapicState {
544 fn default() -> IoapicState {
545 unsafe { std::mem::zeroed() }
547 }
548}
549
550#[repr(C)]
551#[derive(Debug, Clone, Copy, PartialEq, Eq)]
552pub enum PicSelect {
553 Primary = 0,
554 Secondary = 1,
555}
556
557#[repr(C)]
558#[derive(enumn::N, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
559pub enum PicInitState {
560 #[default]
561 Icw1 = 0,
562 Icw2 = 1,
563 Icw3 = 2,
564 Icw4 = 3,
565}
566
567impl From<u8> for PicInitState {
569 fn from(item: u8) -> Self {
570 PicInitState::n(item).unwrap_or_else(|| {
571 error!("Invalid PicInitState {}, setting to 0", item);
572 PicInitState::Icw1
573 })
574 }
575}
576
577#[repr(C)]
579#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
580pub struct PicState {
581 pub last_irr: u8,
583 pub irr: u8,
585 pub imr: u8,
587 pub isr: u8,
589 pub priority_add: u8,
591 pub irq_base: u8,
592 pub read_reg_select: bool,
593 pub poll: bool,
594 pub special_mask: bool,
595 pub init_state: PicInitState,
596 pub auto_eoi: bool,
597 pub rotate_on_auto_eoi: bool,
598 pub special_fully_nested_mode: bool,
599 pub use_4_byte_icw: bool,
602 pub elcr: u8,
606 pub elcr_mask: u8,
607}
608
609#[repr(C)]
613#[derive(Clone, Copy, Serialize, Deserialize)]
614pub struct LapicState {
615 #[serde(
616 serialize_with = "serialize_arr",
617 deserialize_with = "deserialize_seq_to_arr"
618 )]
619 pub regs: [LapicRegister; 64],
620}
621
622pub type LapicRegister = u32;
623
624impl std::fmt::Debug for LapicState {
626 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
627 self.regs[..].fmt(formatter)
628 }
629}
630
631impl PartialEq for LapicState {
633 fn eq(&self, other: &LapicState) -> bool {
634 self.regs[..] == other.regs[..]
635 }
636}
637
638impl Eq for LapicState {}
640
641pub const APIC_ID_REG: usize = 2;
643pub const APIC_IRR_START_REG: usize = 32;
645
646impl LapicState {
647 pub fn get_apic_id(&self) -> u32 {
649 (self.regs[APIC_ID_REG] >> 24) & 0xFF
650 }
651
652 pub fn get_pending_irr_vectors(&self) -> Vec<u8> {
654 let mut vectors = Vec::new();
655 for (i, ®) in self.regs[APIC_IRR_START_REG..=APIC_IRR_START_REG + 7]
656 .iter()
657 .enumerate()
658 {
659 if reg != 0 {
660 for bit in 0..32 {
661 if (reg & (1 << bit)) != 0 {
662 vectors.push((i * 32 + bit) as u8);
663 }
664 }
665 }
666 }
667 vectors
668 }
669}
670
671#[repr(C)]
674#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
675pub struct PitState {
676 pub channels: [PitChannelState; 3],
677 pub flags: u32,
679}
680
681#[repr(C)]
686#[derive(enumn::N, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
687pub enum PitRWMode {
688 None = 0,
690 Least = 1,
692 Most = 2,
694 Both = 3,
697}
698
699impl From<u8> for PitRWMode {
701 fn from(item: u8) -> Self {
702 PitRWMode::n(item).unwrap_or_else(|| {
703 error!("Invalid PitRWMode value {}, setting to 0", item);
704 PitRWMode::None
705 })
706 }
707}
708
709#[repr(C)]
713#[derive(enumn::N, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
714pub enum PitRWState {
715 None = 0,
717 LSB = 1,
719 MSB = 2,
721 Word0 = 3,
724 Word1 = 4,
728}
729
730impl From<u8> for PitRWState {
732 fn from(item: u8) -> Self {
733 PitRWState::n(item).unwrap_or_else(|| {
734 error!("Invalid PitRWState value {}, setting to 0", item);
735 PitRWState::None
736 })
737 }
738}
739
740#[repr(C)]
742#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
743pub struct PitChannelState {
744 pub count: u32,
746 pub latched_count: u16,
748 pub count_latched: PitRWState,
750 pub status_latched: bool,
752 pub status: u8,
756 pub read_state: PitRWState,
758 pub write_state: PitRWState,
760 pub reload_value: u16,
763 pub rw_mode: PitRWMode,
765 pub mode: u8,
767 pub bcd: bool,
769 pub gate: bool,
771 pub count_load_time: u64,
773}
774
775impl IrqRoute {
777 pub fn ioapic_irq_route(irq_num: u32) -> IrqRoute {
778 IrqRoute {
779 gsi: irq_num,
780 source: IrqSource::Irqchip {
781 chip: IrqSourceChip::Ioapic,
782 pin: irq_num,
783 },
784 }
785 }
786
787 pub fn pic_irq_route(id: IrqSourceChip, irq_num: u32) -> IrqRoute {
788 IrqRoute {
789 gsi: irq_num,
790 source: IrqSource::Irqchip {
791 chip: id,
792 pin: irq_num % 8,
793 },
794 }
795 }
796}
797
798#[repr(C)]
800#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
801pub struct Regs {
802 pub rax: u64,
803 pub rbx: u64,
804 pub rcx: u64,
805 pub rdx: u64,
806 pub rsi: u64,
807 pub rdi: u64,
808 pub rsp: u64,
809 pub rbp: u64,
810 pub r8: u64,
811 pub r9: u64,
812 pub r10: u64,
813 pub r11: u64,
814 pub r12: u64,
815 pub r13: u64,
816 pub r14: u64,
817 pub r15: u64,
818 pub rip: u64,
819 pub rflags: u64,
820}
821
822impl Default for Regs {
823 fn default() -> Self {
824 Regs {
825 rax: 0,
826 rbx: 0,
827 rcx: 0,
828 rdx: 0,
829 rsi: 0,
830 rdi: 0,
831 rsp: 0,
832 rbp: 0,
833 r8: 0,
834 r9: 0,
835 r10: 0,
836 r11: 0,
837 r12: 0,
838 r13: 0,
839 r14: 0,
840 r15: 0,
841 rip: 0xfff0, rflags: 0x2, }
844 }
845}
846
847#[repr(C)]
849#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
850pub struct Segment {
851 pub base: u64,
852 pub limit_bytes: u32,
854 pub selector: u16,
855 pub type_: u8,
856 pub present: u8,
857 pub dpl: u8,
858 pub db: u8,
859 pub s: u8,
860 pub l: u8,
861 pub g: u8,
862 pub avl: u8,
863}
864
865#[repr(C)]
867#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
868pub struct DescriptorTable {
869 pub base: u64,
870 pub limit: u16,
871}
872
873#[repr(C)]
875#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
876pub struct Sregs {
877 pub cs: Segment,
878 pub ds: Segment,
879 pub es: Segment,
880 pub fs: Segment,
881 pub gs: Segment,
882 pub ss: Segment,
883 pub tr: Segment,
884 pub ldt: Segment,
885 pub gdt: DescriptorTable,
886 pub idt: DescriptorTable,
887 pub cr0: u64,
888 pub cr2: u64,
889 pub cr3: u64,
890 pub cr4: u64,
891 pub cr8: u64,
892 pub efer: u64,
893}
894
895impl Default for Sregs {
896 fn default() -> Self {
897 const SEG_TYPE_DATA: u8 = 0b0000;
899 const SEG_TYPE_DATA_WRITABLE: u8 = 0b0010;
900
901 const SEG_TYPE_CODE: u8 = 0b1000;
902 const SEG_TYPE_CODE_READABLE: u8 = 0b0010;
903
904 const SEG_TYPE_ACCESSED: u8 = 0b0001;
905
906 const SEG_S_SYSTEM: u8 = 0; const SEG_S_CODE_OR_DATA: u8 = 1; let code_seg = Segment {
912 base: 0xffff0000,
913 limit_bytes: 0xffff,
914 selector: 0xf000,
915 type_: SEG_TYPE_CODE | SEG_TYPE_CODE_READABLE | SEG_TYPE_ACCESSED, present: 1,
917 s: SEG_S_CODE_OR_DATA,
918 ..Default::default()
919 };
920
921 let data_seg = Segment {
923 base: 0,
924 limit_bytes: 0xffff,
925 selector: 0,
926 type_: SEG_TYPE_DATA | SEG_TYPE_DATA_WRITABLE | SEG_TYPE_ACCESSED, present: 1,
928 s: SEG_S_CODE_OR_DATA,
929 ..Default::default()
930 };
931
932 let task_seg = Segment {
934 base: 0,
935 limit_bytes: 0xffff,
936 selector: 0,
937 type_: SEG_TYPE_CODE | SEG_TYPE_CODE_READABLE | SEG_TYPE_ACCESSED, present: 1,
939 s: SEG_S_SYSTEM,
940 ..Default::default()
941 };
942
943 let ldt = Segment {
945 base: 0,
946 limit_bytes: 0xffff,
947 selector: 0,
948 type_: SEG_TYPE_DATA | SEG_TYPE_DATA_WRITABLE, present: 1,
950 s: SEG_S_SYSTEM,
951 ..Default::default()
952 };
953
954 let gdt = DescriptorTable {
956 base: 0,
957 limit: 0xffff,
958 };
959
960 let idt = DescriptorTable {
962 base: 0,
963 limit: 0xffff,
964 };
965
966 let cr0 = (1 << 4) | (1 << 30); Sregs {
970 cs: code_seg,
971 ds: data_seg,
972 es: data_seg,
973 fs: data_seg,
974 gs: data_seg,
975 ss: data_seg,
976 tr: task_seg,
977 ldt,
978 gdt,
979 idt,
980 cr0,
981 cr2: 0,
982 cr3: 0,
983 cr4: 0,
984 cr8: 0,
985 efer: 0,
986 }
987 }
988}
989
990#[repr(C)]
992#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
993pub struct FpuReg {
994 pub significand: u64,
996
997 pub sign_exp: u16,
999}
1000
1001impl FpuReg {
1002 pub fn from_16byte_arrays(byte_arrays: &[[u8; 16]; 8]) -> [FpuReg; 8] {
1007 let mut regs = [FpuReg::default(); 8];
1008 for (dst, src) in regs.iter_mut().zip(byte_arrays.iter()) {
1009 let tbyte: [u8; 10] = src[0..10].try_into().unwrap();
1010 *dst = FpuReg::from(tbyte);
1011 }
1012 regs
1013 }
1014
1015 pub fn to_16byte_arrays(regs: &[FpuReg; 8]) -> [[u8; 16]; 8] {
1017 let mut byte_arrays = [[0u8; 16]; 8];
1018 for (dst, src) in byte_arrays.iter_mut().zip(regs.iter()) {
1019 *dst = (*src).into();
1020 }
1021 byte_arrays
1022 }
1023}
1024
1025impl From<[u8; 10]> for FpuReg {
1026 fn from(value: [u8; 10]) -> FpuReg {
1028 let significand_bytes = value[0..8].try_into().unwrap();
1031 let significand = u64::from_le_bytes(significand_bytes);
1032 let sign_exp_bytes = value[8..10].try_into().unwrap();
1033 let sign_exp = u16::from_le_bytes(sign_exp_bytes);
1034 FpuReg {
1035 significand,
1036 sign_exp,
1037 }
1038 }
1039}
1040
1041impl From<FpuReg> for [u8; 10] {
1042 fn from(value: FpuReg) -> [u8; 10] {
1044 let mut bytes = [0u8; 10];
1045 bytes[0..8].copy_from_slice(&value.significand.to_le_bytes());
1046 bytes[8..10].copy_from_slice(&value.sign_exp.to_le_bytes());
1047 bytes
1048 }
1049}
1050
1051impl From<FpuReg> for [u8; 16] {
1052 fn from(value: FpuReg) -> [u8; 16] {
1055 let mut bytes = [0u8; 16];
1056 bytes[0..8].copy_from_slice(&value.significand.to_le_bytes());
1057 bytes[8..10].copy_from_slice(&value.sign_exp.to_le_bytes());
1058 bytes
1059 }
1060}
1061
1062#[repr(C)]
1064#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
1065pub struct Fpu {
1066 pub fpr: [FpuReg; 8],
1067 pub fcw: u16,
1068 pub fsw: u16,
1069 pub ftwx: u8,
1070 pub last_opcode: u16,
1071 pub last_ip: u64,
1072 pub last_dp: u64,
1073 pub xmm: [[u8; 16usize]; 16usize],
1074 pub mxcsr: u32,
1075}
1076
1077impl Default for Fpu {
1078 fn default() -> Self {
1079 Fpu {
1080 fpr: Default::default(),
1081 fcw: 0x37f, fsw: 0,
1083 ftwx: 0,
1084 last_opcode: 0,
1085 last_ip: 0,
1086 last_dp: 0,
1087 xmm: Default::default(),
1088 mxcsr: 0x1f80, }
1090 }
1091}
1092
1093#[repr(C)]
1095#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
1096pub struct DebugRegs {
1097 pub db: [u64; 4usize],
1098 pub dr6: u64,
1099 pub dr7: u64,
1100}
1101
1102#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1104pub enum CpuHybridType {
1105 Atom,
1107 Core,
1109}
1110
1111#[derive(Clone, Debug, Serialize, Deserialize)]
1114pub struct Xsave {
1115 data: Vec<u32>,
1116
1117 len: usize,
1120}
1121
1122impl Xsave {
1123 pub fn new(len: usize) -> Self {
1128 Xsave {
1129 data: vec![0; len.div_ceil(4)],
1130 len,
1131 }
1132 }
1133
1134 pub fn as_ptr(&self) -> *const c_void {
1135 self.data.as_ptr() as *const c_void
1136 }
1137
1138 pub fn as_mut_ptr(&mut self) -> *mut c_void {
1139 self.data.as_mut_ptr() as *mut c_void
1140 }
1141
1142 pub fn len(&self) -> usize {
1144 self.len
1145 }
1146
1147 pub fn is_empty(&self) -> bool {
1149 self.len() == 0
1150 }
1151}
1152
1153#[cfg(test)]
1154mod tests {
1155 use super::*;
1156
1157 #[test]
1158 fn test_lapic_get_apic_id() {
1159 let mut lapic = LapicState { regs: [0; 64] };
1160 assert_eq!(lapic.get_apic_id(), 0);
1161
1162 lapic.regs[APIC_ID_REG] = 0x05000000;
1164 assert_eq!(lapic.get_apic_id(), 5);
1165
1166 lapic.regs[APIC_ID_REG] = 0xFE000000;
1167 assert_eq!(lapic.get_apic_id(), 0xFE);
1168 }
1169
1170 #[test]
1171 fn test_lapic_get_pending_irr_vectors() {
1172 let mut lapic = LapicState { regs: [0; 64] };
1173 assert!(lapic.get_pending_irr_vectors().is_empty());
1174
1175 lapic.regs[APIC_IRR_START_REG + 7] |= 1 << 12;
1177 lapic.regs[APIC_IRR_START_REG + 1] |= 1 << 16;
1179
1180 let vectors = lapic.get_pending_irr_vectors();
1181 assert_eq!(vectors, vec![48, 236]);
1182 }
1183}