1use std::arch::x86_64::CpuidResult;
6#[cfg(any(unix, feature = "haxm", feature = "whpx"))]
7use std::arch::x86_64::__cpuid;
8use std::arch::x86_64::_rdtsc;
9use std::collections::BTreeMap;
10use std::collections::HashSet;
11
12use anyhow::Context;
13use base::custom_serde::deserialize_seq_to_arr;
14use base::custom_serde::serialize_arr;
15use base::error;
16use base::warn;
17use base::Result;
18use bit_field::*;
19use downcast_rs::impl_downcast;
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::Vcpu;
31use crate::Vm;
32
33const MSR_F15H_PERF_CTL0: u32 = 0xc0010200;
34const MSR_F15H_PERF_CTL1: u32 = 0xc0010202;
35const MSR_F15H_PERF_CTL2: u32 = 0xc0010204;
36const MSR_F15H_PERF_CTL3: u32 = 0xc0010206;
37const MSR_F15H_PERF_CTL4: u32 = 0xc0010208;
38const MSR_F15H_PERF_CTL5: u32 = 0xc001020a;
39const MSR_F15H_PERF_CTR0: u32 = 0xc0010201;
40const MSR_F15H_PERF_CTR1: u32 = 0xc0010203;
41const MSR_F15H_PERF_CTR2: u32 = 0xc0010205;
42const MSR_F15H_PERF_CTR3: u32 = 0xc0010207;
43const MSR_F15H_PERF_CTR4: u32 = 0xc0010209;
44const MSR_F15H_PERF_CTR5: u32 = 0xc001020b;
45const MSR_IA32_PERF_CAPABILITIES: u32 = 0x00000345;
46
47pub trait HypervisorX86_64: Hypervisor {
49 fn get_supported_cpuid(&self) -> Result<CpuId>;
51
52 fn get_msr_index_list(&self) -> Result<Vec<u32>>;
54}
55
56pub trait VmX86_64: Vm {
58 fn get_hypervisor(&self) -> &dyn HypervisorX86_64;
60
61 fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuX86_64>>;
63
64 fn set_tss_addr(&self, addr: GuestAddress) -> Result<()>;
66
67 fn set_identity_map_addr(&self, addr: GuestAddress) -> Result<()>;
69
70 fn load_protected_vm_firmware(&mut self, fw_addr: GuestAddress, fw_max_size: u64)
74 -> 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(&mut 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 &mut 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
316impl_downcast!(VcpuX86_64);
317
318pub const MSR_IA32_TSC: u32 = 0x00000010;
320
321#[cfg(any(unix, feature = "haxm", feature = "whpx"))]
323pub(crate) fn host_phys_addr_bits() -> u8 {
324 let highest_ext_function = unsafe { __cpuid(0x80000000) };
326 if highest_ext_function.eax >= 0x80000008 {
327 let addr_size = unsafe { __cpuid(0x80000008) };
329 addr_size.eax as u8
331 } else {
332 36
333 }
334}
335
336#[derive(Clone, Default)]
338pub struct VcpuInitX86_64 {
339 pub regs: Regs,
341
342 pub sregs: Sregs,
344
345 pub fpu: Fpu,
347
348 pub msrs: BTreeMap<u32, u64>,
350}
351
352#[derive(Clone, Debug, PartialEq, Eq)]
354pub struct CpuConfigX86_64 {
355 pub force_calibrated_tsc_leaf: bool,
357
358 pub host_cpu_topology: bool,
360
361 pub enable_hwp: bool,
363
364 pub no_smt: bool,
366
367 pub itmt: bool,
369
370 pub hybrid_type: Option<CpuHybridType>,
372}
373
374impl CpuConfigX86_64 {
375 pub fn new(
376 force_calibrated_tsc_leaf: bool,
377 host_cpu_topology: bool,
378 enable_hwp: bool,
379 no_smt: bool,
380 itmt: bool,
381 hybrid_type: Option<CpuHybridType>,
382 ) -> Self {
383 CpuConfigX86_64 {
384 force_calibrated_tsc_leaf,
385 host_cpu_topology,
386 enable_hwp,
387 no_smt,
388 itmt,
389 hybrid_type,
390 }
391 }
392}
393
394#[repr(C)]
400#[derive(Clone, Copy, Debug, PartialEq, Eq)]
401pub struct CpuIdEntry {
402 pub function: u32,
403 pub index: u32,
404 pub flags: u32,
407 pub cpuid: CpuidResult,
408}
409
410pub struct CpuId {
412 pub cpu_id_entries: Vec<CpuIdEntry>,
413}
414
415impl CpuId {
416 pub fn new(initial_capacity: usize) -> Self {
418 CpuId {
419 cpu_id_entries: Vec::with_capacity(initial_capacity),
420 }
421 }
422}
423
424#[bitfield]
425#[derive(Clone, Copy, Debug, PartialEq, Eq)]
426pub enum DestinationMode {
427 Physical = 0,
428 Logical = 1,
429}
430
431#[bitfield]
432#[derive(Clone, Copy, Debug, PartialEq, Eq)]
433pub enum TriggerMode {
434 Edge = 0,
435 Level = 1,
436}
437
438#[bitfield]
439#[derive(Debug, Clone, Copy, PartialEq, Eq)]
440pub enum DeliveryMode {
441 Fixed = 0b000,
442 Lowest = 0b001,
443 SMI = 0b010, RemoteRead = 0b011, NMI = 0b100, Init = 0b101,
447 Startup = 0b110,
448 External = 0b111,
449}
450
451#[bitfield]
456#[derive(Clone, Copy, PartialEq, Eq)]
457pub struct MsiAddressMessage {
458 pub reserved: BitField2,
459 #[bits = 1]
460 pub destination_mode: DestinationMode,
461 pub redirection_hint: BitField1,
462 pub reserved_2: BitField8,
463 pub destination_id: BitField8,
464 pub always_0xfee: BitField12,
466}
467
468#[bitfield]
469#[derive(Clone, Copy, PartialEq, Eq)]
470pub struct MsiDataMessage {
471 pub vector: BitField8,
472 #[bits = 3]
473 pub delivery_mode: DeliveryMode,
474 pub reserved: BitField3,
475 #[bits = 1]
476 pub level: Level,
477 #[bits = 1]
478 pub trigger: TriggerMode,
479 pub reserved2: BitField16,
480}
481
482#[bitfield]
483#[derive(Debug, Clone, Copy, PartialEq, Eq)]
484pub enum DeliveryStatus {
485 Idle = 0,
486 Pending = 1,
487}
488
489#[bitfield]
491#[derive(Debug, Clone, Copy, PartialEq, Eq)]
492pub enum Level {
493 Deassert = 0,
494 Assert = 1,
495}
496
497#[bitfield]
499#[derive(Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
500pub struct IoapicRedirectionTableEntry {
501 vector: BitField8,
502 #[bits = 3]
503 delivery_mode: DeliveryMode,
504 #[bits = 1]
505 dest_mode: DestinationMode,
506 #[bits = 1]
507 delivery_status: DeliveryStatus,
508 polarity: BitField1,
509 remote_irr: bool,
510 #[bits = 1]
511 trigger_mode: TriggerMode,
512 interrupt_mask: bool, reserved: BitField39,
514 dest_id: BitField8,
515}
516
517pub const NUM_IOAPIC_PINS: usize = 24;
519
520#[repr(C)]
522#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
523pub struct IoapicState {
524 pub base_address: u64,
526 pub ioregsel: u8,
528 pub ioapicid: u32,
530 pub current_interrupt_level_bitmap: u32,
532 #[serde(
534 serialize_with = "serialize_arr",
535 deserialize_with = "deserialize_seq_to_arr"
536 )]
537 pub redirect_table: [IoapicRedirectionTableEntry; NUM_IOAPIC_PINS],
538}
539
540impl Default for IoapicState {
541 fn default() -> IoapicState {
542 unsafe { std::mem::zeroed() }
544 }
545}
546
547#[repr(C)]
548#[derive(Debug, Clone, Copy, PartialEq, Eq)]
549pub enum PicSelect {
550 Primary = 0,
551 Secondary = 1,
552}
553
554#[repr(C)]
555#[derive(enumn::N, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
556pub enum PicInitState {
557 #[default]
558 Icw1 = 0,
559 Icw2 = 1,
560 Icw3 = 2,
561 Icw4 = 3,
562}
563
564impl From<u8> for PicInitState {
566 fn from(item: u8) -> Self {
567 PicInitState::n(item).unwrap_or_else(|| {
568 error!("Invalid PicInitState {}, setting to 0", item);
569 PicInitState::Icw1
570 })
571 }
572}
573
574#[repr(C)]
576#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
577pub struct PicState {
578 pub last_irr: u8,
580 pub irr: u8,
582 pub imr: u8,
584 pub isr: u8,
586 pub priority_add: u8,
588 pub irq_base: u8,
589 pub read_reg_select: bool,
590 pub poll: bool,
591 pub special_mask: bool,
592 pub init_state: PicInitState,
593 pub auto_eoi: bool,
594 pub rotate_on_auto_eoi: bool,
595 pub special_fully_nested_mode: bool,
596 pub use_4_byte_icw: bool,
599 pub elcr: u8,
603 pub elcr_mask: u8,
604}
605
606#[repr(C)]
610#[derive(Clone, Copy, Serialize, Deserialize)]
611pub struct LapicState {
612 #[serde(
613 serialize_with = "serialize_arr",
614 deserialize_with = "deserialize_seq_to_arr"
615 )]
616 pub regs: [LapicRegister; 64],
617}
618
619pub type LapicRegister = u32;
620
621impl std::fmt::Debug for LapicState {
623 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
624 self.regs[..].fmt(formatter)
625 }
626}
627
628impl PartialEq for LapicState {
630 fn eq(&self, other: &LapicState) -> bool {
631 self.regs[..] == other.regs[..]
632 }
633}
634
635impl Eq for LapicState {}
637
638#[repr(C)]
641#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
642pub struct PitState {
643 pub channels: [PitChannelState; 3],
644 pub flags: u32,
646}
647
648#[repr(C)]
653#[derive(enumn::N, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
654pub enum PitRWMode {
655 None = 0,
657 Least = 1,
659 Most = 2,
661 Both = 3,
664}
665
666impl From<u8> for PitRWMode {
668 fn from(item: u8) -> Self {
669 PitRWMode::n(item).unwrap_or_else(|| {
670 error!("Invalid PitRWMode value {}, setting to 0", item);
671 PitRWMode::None
672 })
673 }
674}
675
676#[repr(C)]
680#[derive(enumn::N, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
681pub enum PitRWState {
682 None = 0,
684 LSB = 1,
686 MSB = 2,
688 Word0 = 3,
691 Word1 = 4,
695}
696
697impl From<u8> for PitRWState {
699 fn from(item: u8) -> Self {
700 PitRWState::n(item).unwrap_or_else(|| {
701 error!("Invalid PitRWState value {}, setting to 0", item);
702 PitRWState::None
703 })
704 }
705}
706
707#[repr(C)]
709#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
710pub struct PitChannelState {
711 pub count: u32,
713 pub latched_count: u16,
715 pub count_latched: PitRWState,
717 pub status_latched: bool,
719 pub status: u8,
723 pub read_state: PitRWState,
725 pub write_state: PitRWState,
727 pub reload_value: u16,
730 pub rw_mode: PitRWMode,
732 pub mode: u8,
734 pub bcd: bool,
736 pub gate: bool,
738 pub count_load_time: u64,
740}
741
742impl IrqRoute {
744 pub fn ioapic_irq_route(irq_num: u32) -> IrqRoute {
745 IrqRoute {
746 gsi: irq_num,
747 source: IrqSource::Irqchip {
748 chip: IrqSourceChip::Ioapic,
749 pin: irq_num,
750 },
751 }
752 }
753
754 pub fn pic_irq_route(id: IrqSourceChip, irq_num: u32) -> IrqRoute {
755 IrqRoute {
756 gsi: irq_num,
757 source: IrqSource::Irqchip {
758 chip: id,
759 pin: irq_num % 8,
760 },
761 }
762 }
763}
764
765#[repr(C)]
767#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
768pub struct Regs {
769 pub rax: u64,
770 pub rbx: u64,
771 pub rcx: u64,
772 pub rdx: u64,
773 pub rsi: u64,
774 pub rdi: u64,
775 pub rsp: u64,
776 pub rbp: u64,
777 pub r8: u64,
778 pub r9: u64,
779 pub r10: u64,
780 pub r11: u64,
781 pub r12: u64,
782 pub r13: u64,
783 pub r14: u64,
784 pub r15: u64,
785 pub rip: u64,
786 pub rflags: u64,
787}
788
789impl Default for Regs {
790 fn default() -> Self {
791 Regs {
792 rax: 0,
793 rbx: 0,
794 rcx: 0,
795 rdx: 0,
796 rsi: 0,
797 rdi: 0,
798 rsp: 0,
799 rbp: 0,
800 r8: 0,
801 r9: 0,
802 r10: 0,
803 r11: 0,
804 r12: 0,
805 r13: 0,
806 r14: 0,
807 r15: 0,
808 rip: 0xfff0, rflags: 0x2, }
811 }
812}
813
814#[repr(C)]
816#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
817pub struct Segment {
818 pub base: u64,
819 pub limit_bytes: u32,
821 pub selector: u16,
822 pub type_: u8,
823 pub present: u8,
824 pub dpl: u8,
825 pub db: u8,
826 pub s: u8,
827 pub l: u8,
828 pub g: u8,
829 pub avl: u8,
830}
831
832#[repr(C)]
834#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
835pub struct DescriptorTable {
836 pub base: u64,
837 pub limit: u16,
838}
839
840#[repr(C)]
842#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
843pub struct Sregs {
844 pub cs: Segment,
845 pub ds: Segment,
846 pub es: Segment,
847 pub fs: Segment,
848 pub gs: Segment,
849 pub ss: Segment,
850 pub tr: Segment,
851 pub ldt: Segment,
852 pub gdt: DescriptorTable,
853 pub idt: DescriptorTable,
854 pub cr0: u64,
855 pub cr2: u64,
856 pub cr3: u64,
857 pub cr4: u64,
858 pub cr8: u64,
859 pub efer: u64,
860}
861
862impl Default for Sregs {
863 fn default() -> Self {
864 const SEG_TYPE_DATA: u8 = 0b0000;
866 const SEG_TYPE_DATA_WRITABLE: u8 = 0b0010;
867
868 const SEG_TYPE_CODE: u8 = 0b1000;
869 const SEG_TYPE_CODE_READABLE: u8 = 0b0010;
870
871 const SEG_TYPE_ACCESSED: u8 = 0b0001;
872
873 const SEG_S_SYSTEM: u8 = 0; const SEG_S_CODE_OR_DATA: u8 = 1; let code_seg = Segment {
879 base: 0xffff0000,
880 limit_bytes: 0xffff,
881 selector: 0xf000,
882 type_: SEG_TYPE_CODE | SEG_TYPE_CODE_READABLE | SEG_TYPE_ACCESSED, present: 1,
884 s: SEG_S_CODE_OR_DATA,
885 ..Default::default()
886 };
887
888 let data_seg = Segment {
890 base: 0,
891 limit_bytes: 0xffff,
892 selector: 0,
893 type_: SEG_TYPE_DATA | SEG_TYPE_DATA_WRITABLE | SEG_TYPE_ACCESSED, present: 1,
895 s: SEG_S_CODE_OR_DATA,
896 ..Default::default()
897 };
898
899 let task_seg = Segment {
901 base: 0,
902 limit_bytes: 0xffff,
903 selector: 0,
904 type_: SEG_TYPE_CODE | SEG_TYPE_CODE_READABLE | SEG_TYPE_ACCESSED, present: 1,
906 s: SEG_S_SYSTEM,
907 ..Default::default()
908 };
909
910 let ldt = Segment {
912 base: 0,
913 limit_bytes: 0xffff,
914 selector: 0,
915 type_: SEG_TYPE_DATA | SEG_TYPE_DATA_WRITABLE, present: 1,
917 s: SEG_S_SYSTEM,
918 ..Default::default()
919 };
920
921 let gdt = DescriptorTable {
923 base: 0,
924 limit: 0xffff,
925 };
926
927 let idt = DescriptorTable {
929 base: 0,
930 limit: 0xffff,
931 };
932
933 let cr0 = (1 << 4) | (1 << 30); Sregs {
937 cs: code_seg,
938 ds: data_seg,
939 es: data_seg,
940 fs: data_seg,
941 gs: data_seg,
942 ss: data_seg,
943 tr: task_seg,
944 ldt,
945 gdt,
946 idt,
947 cr0,
948 cr2: 0,
949 cr3: 0,
950 cr4: 0,
951 cr8: 0,
952 efer: 0,
953 }
954 }
955}
956
957#[repr(C)]
959#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
960pub struct FpuReg {
961 pub significand: u64,
963
964 pub sign_exp: u16,
966}
967
968impl FpuReg {
969 pub fn from_16byte_arrays(byte_arrays: &[[u8; 16]; 8]) -> [FpuReg; 8] {
974 let mut regs = [FpuReg::default(); 8];
975 for (dst, src) in regs.iter_mut().zip(byte_arrays.iter()) {
976 let tbyte: [u8; 10] = src[0..10].try_into().unwrap();
977 *dst = FpuReg::from(tbyte);
978 }
979 regs
980 }
981
982 pub fn to_16byte_arrays(regs: &[FpuReg; 8]) -> [[u8; 16]; 8] {
984 let mut byte_arrays = [[0u8; 16]; 8];
985 for (dst, src) in byte_arrays.iter_mut().zip(regs.iter()) {
986 *dst = (*src).into();
987 }
988 byte_arrays
989 }
990}
991
992impl From<[u8; 10]> for FpuReg {
993 fn from(value: [u8; 10]) -> FpuReg {
995 let significand_bytes = value[0..8].try_into().unwrap();
998 let significand = u64::from_le_bytes(significand_bytes);
999 let sign_exp_bytes = value[8..10].try_into().unwrap();
1000 let sign_exp = u16::from_le_bytes(sign_exp_bytes);
1001 FpuReg {
1002 significand,
1003 sign_exp,
1004 }
1005 }
1006}
1007
1008impl From<FpuReg> for [u8; 10] {
1009 fn from(value: FpuReg) -> [u8; 10] {
1011 let mut bytes = [0u8; 10];
1012 bytes[0..8].copy_from_slice(&value.significand.to_le_bytes());
1013 bytes[8..10].copy_from_slice(&value.sign_exp.to_le_bytes());
1014 bytes
1015 }
1016}
1017
1018impl From<FpuReg> for [u8; 16] {
1019 fn from(value: FpuReg) -> [u8; 16] {
1022 let mut bytes = [0u8; 16];
1023 bytes[0..8].copy_from_slice(&value.significand.to_le_bytes());
1024 bytes[8..10].copy_from_slice(&value.sign_exp.to_le_bytes());
1025 bytes
1026 }
1027}
1028
1029#[repr(C)]
1031#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
1032pub struct Fpu {
1033 pub fpr: [FpuReg; 8],
1034 pub fcw: u16,
1035 pub fsw: u16,
1036 pub ftwx: u8,
1037 pub last_opcode: u16,
1038 pub last_ip: u64,
1039 pub last_dp: u64,
1040 pub xmm: [[u8; 16usize]; 16usize],
1041 pub mxcsr: u32,
1042}
1043
1044impl Default for Fpu {
1045 fn default() -> Self {
1046 Fpu {
1047 fpr: Default::default(),
1048 fcw: 0x37f, fsw: 0,
1050 ftwx: 0,
1051 last_opcode: 0,
1052 last_ip: 0,
1053 last_dp: 0,
1054 xmm: Default::default(),
1055 mxcsr: 0x1f80, }
1057 }
1058}
1059
1060#[repr(C)]
1062#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
1063pub struct DebugRegs {
1064 pub db: [u64; 4usize],
1065 pub dr6: u64,
1066 pub dr7: u64,
1067}
1068
1069#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1071pub enum CpuHybridType {
1072 Atom,
1074 Core,
1076}
1077
1078#[derive(Clone, Debug, Serialize, Deserialize)]
1081pub struct Xsave {
1082 data: Vec<u32>,
1083
1084 len: usize,
1087}
1088
1089impl Xsave {
1090 pub fn new(len: usize) -> Self {
1095 Xsave {
1096 data: vec![0; len.div_ceil(4)],
1097 len,
1098 }
1099 }
1100
1101 pub fn as_ptr(&self) -> *const c_void {
1102 self.data.as_ptr() as *const c_void
1103 }
1104
1105 pub fn as_mut_ptr(&mut self) -> *mut c_void {
1106 self.data.as_mut_ptr() as *mut c_void
1107 }
1108
1109 pub fn len(&self) -> usize {
1111 self.len
1112 }
1113
1114 pub fn is_empty(&self) -> bool {
1116 self.len() == 0
1117 }
1118}