1#![allow(dead_code)]
10
11#[cfg(feature = "alloc")]
12extern crate alloc;
13
14#[cfg(feature = "alloc")]
15use alloc::vec::Vec;
16
17use super::VmError;
18
19pub const KVM_API_VERSION: u32 = 12;
25
26const MAX_VCPUS_PER_VM: usize = 256;
28
29const MAX_MEMORY_REGIONS: usize = 64;
31
32const PIT_FREQUENCY_HZ: u64 = 1_193_182;
34
35const PIT_CHANNEL_COUNT: usize = 3;
37
38const MAX_MSR_ENTRIES: usize = 256;
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum KvmCapability {
48 Irqchip = 0,
50 Hlt = 1,
52 MmuShadow = 2,
54 UserMemory = 3,
56 SetTssAddr = 4,
58 Pit2 = 5,
60 ExtCpuid = 6,
62 Vapic = 7,
64 MpState = 8,
66 CoalescedMmio = 9,
68}
69
70impl KvmCapability {
71 pub(crate) fn is_supported(&self) -> bool {
73 true
75 }
76
77 pub(crate) fn from_raw(value: u32) -> Option<Self> {
79 match value {
80 0 => Some(Self::Irqchip),
81 1 => Some(Self::Hlt),
82 2 => Some(Self::MmuShadow),
83 3 => Some(Self::UserMemory),
84 4 => Some(Self::SetTssAddr),
85 5 => Some(Self::Pit2),
86 6 => Some(Self::ExtCpuid),
87 7 => Some(Self::Vapic),
88 8 => Some(Self::MpState),
89 9 => Some(Self::CoalescedMmio),
90 _ => None,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum KvmExitReason {
102 Io,
104 Mmio,
106 Hlt,
108 Shutdown,
110 InternalError,
112 Unknown(u32),
114}
115
116impl KvmExitReason {
117 pub(crate) fn from_raw(raw: u32) -> Self {
119 match raw {
120 2 => Self::Io,
121 6 => Self::Mmio,
122 5 => Self::Hlt,
123 8 => Self::Shutdown,
124 17 => Self::InternalError,
125 other => Self::Unknown(other),
126 }
127 }
128
129 pub(crate) fn to_raw(self) -> u32 {
131 match self {
132 Self::Io => 2,
133 Self::Mmio => 6,
134 Self::Hlt => 5,
135 Self::Shutdown => 8,
136 Self::InternalError => 17,
137 Self::Unknown(v) => v,
138 }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
148pub enum IoDirection {
149 #[default]
151 In,
152 Out,
154}
155
156#[derive(Debug, Clone, Copy, Default)]
162pub struct KvmIoExit {
163 pub direction: IoDirection,
165 pub port: u16,
167 pub size: u8,
169 pub data: u32,
171}
172
173impl KvmIoExit {
174 pub(crate) fn new_in(port: u16, size: u8) -> Self {
176 Self {
177 direction: IoDirection::In,
178 port,
179 size,
180 data: 0,
181 }
182 }
183
184 pub(crate) fn new_out(port: u16, size: u8, data: u32) -> Self {
186 Self {
187 direction: IoDirection::Out,
188 port,
189 size,
190 data,
191 }
192 }
193}
194
195#[derive(Debug, Clone, Copy, Default)]
201pub struct KvmMmioExit {
202 pub phys_addr: u64,
204 pub data: u64,
206 pub len: u8,
208 pub is_write: bool,
210}
211
212impl KvmMmioExit {
213 pub(crate) fn new_read(phys_addr: u64, len: u8) -> Self {
215 Self {
216 phys_addr,
217 data: 0,
218 len,
219 is_write: false,
220 }
221 }
222
223 pub(crate) fn new_write(phys_addr: u64, data: u64, len: u8) -> Self {
225 Self {
226 phys_addr,
227 data,
228 len,
229 is_write: true,
230 }
231 }
232}
233
234#[derive(Debug, Clone, Copy, Default)]
240pub struct KvmRegs {
241 pub rax: u64,
242 pub rbx: u64,
243 pub rcx: u64,
244 pub rdx: u64,
245 pub rsi: u64,
246 pub rdi: u64,
247 pub rsp: u64,
248 pub rbp: u64,
249 pub r8: u64,
250 pub r9: u64,
251 pub r10: u64,
252 pub r11: u64,
253 pub r12: u64,
254 pub r13: u64,
255 pub r14: u64,
256 pub r15: u64,
257 pub rip: u64,
258 pub rflags: u64,
259}
260
261#[derive(Debug, Clone, Copy, Default)]
267pub struct KvmSegment {
268 pub base: u64,
269 pub limit: u32,
270 pub selector: u16,
271 pub type_attr: u8,
272 pub present: u8,
273 pub dpl: u8,
274 pub db: u8,
275 pub s: u8,
276 pub l: u8,
277 pub g: u8,
278 pub avl: u8,
279}
280
281impl KvmSegment {
282 pub(crate) fn flat_code_64() -> Self {
284 Self {
285 base: 0,
286 limit: 0xFFFF_FFFF,
287 selector: 0x08,
288 type_attr: 0x0B, present: 1,
290 dpl: 0,
291 db: 0,
292 s: 1,
293 l: 1, g: 1, avl: 0,
296 }
297 }
298
299 pub(crate) fn flat_data_64() -> Self {
301 Self {
302 base: 0,
303 limit: 0xFFFF_FFFF,
304 selector: 0x10,
305 type_attr: 0x03, present: 1,
307 dpl: 0,
308 db: 1,
309 s: 1,
310 l: 0,
311 g: 1,
312 avl: 0,
313 }
314 }
315}
316
317#[derive(Debug, Clone, Copy, Default)]
323pub struct KvmSregs {
324 pub cs: KvmSegment,
325 pub ds: KvmSegment,
326 pub es: KvmSegment,
327 pub fs: KvmSegment,
328 pub gs: KvmSegment,
329 pub ss: KvmSegment,
330 pub tr: KvmSegment,
331 pub ldt: KvmSegment,
332 pub cr0: u64,
333 pub cr2: u64,
334 pub cr3: u64,
335 pub cr4: u64,
336 pub efer: u64,
337}
338
339impl KvmSregs {
340 pub(crate) fn real_mode() -> Self {
342 Self {
343 cr0: 0x10, ..Default::default()
345 }
346 }
347
348 pub(crate) fn long_mode(cr3: u64) -> Self {
350 Self {
351 cs: KvmSegment::flat_code_64(),
352 ds: KvmSegment::flat_data_64(),
353 es: KvmSegment::flat_data_64(),
354 fs: KvmSegment::flat_data_64(),
355 gs: KvmSegment::flat_data_64(),
356 ss: KvmSegment::flat_data_64(),
357 cr0: 0x8000_0011, cr3,
359 cr4: 0x20, efer: 0x500, ..Default::default()
362 }
363 }
364}
365
366#[derive(Debug, Clone, Copy, Default)]
372pub struct MsrEntry {
373 pub index: u32,
375 pub value: u64,
377}
378
379#[derive(Debug, Clone, Copy)]
385pub struct KvmMemoryRegion {
386 pub slot: u32,
388 pub flags: u32,
390 pub guest_phys_addr: u64,
392 pub memory_size: u64,
394 pub userspace_addr: u64,
396}
397
398impl KvmMemoryRegion {
399 pub const FLAG_READONLY: u32 = 1;
401 pub const FLAG_LOG_DIRTY: u32 = 2;
403
404 pub fn new(slot: u32, guest_phys: u64, size: u64, host_addr: u64) -> Self {
406 Self {
407 slot,
408 flags: 0,
409 guest_phys_addr: guest_phys,
410 memory_size: size,
411 userspace_addr: host_addr,
412 }
413 }
414
415 pub fn new_readonly(slot: u32, guest_phys: u64, size: u64, host_addr: u64) -> Self {
417 Self {
418 slot,
419 flags: Self::FLAG_READONLY,
420 guest_phys_addr: guest_phys,
421 memory_size: size,
422 userspace_addr: host_addr,
423 }
424 }
425
426 pub(crate) fn is_readonly(&self) -> bool {
428 self.flags & Self::FLAG_READONLY != 0
429 }
430
431 pub(crate) fn has_dirty_logging(&self) -> bool {
433 self.flags & Self::FLAG_LOG_DIRTY != 0
434 }
435
436 pub(crate) fn contains_guest_addr(&self, addr: u64) -> bool {
438 addr >= self.guest_phys_addr && addr < self.guest_phys_addr + self.memory_size
439 }
440
441 pub(crate) fn translate(&self, guest_phys: u64) -> Option<u64> {
443 if self.contains_guest_addr(guest_phys) {
444 Some(self.userspace_addr + (guest_phys - self.guest_phys_addr))
445 } else {
446 None
447 }
448 }
449}
450
451#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
457pub enum PitMode {
458 #[default]
460 InterruptOnTerminalCount,
461 OneShot,
463 RateGenerator,
465 SquareWave,
467 SoftwareStrobe,
469 HardwareStrobe,
471}
472
473impl PitMode {
474 pub(crate) fn from_raw(raw: u8) -> Self {
476 match raw & 0x07 {
477 0 => Self::InterruptOnTerminalCount,
478 1 => Self::OneShot,
479 2 => Self::RateGenerator,
480 3 => Self::SquareWave,
481 4 => Self::SoftwareStrobe,
482 5 => Self::HardwareStrobe,
483 _ => Self::InterruptOnTerminalCount,
484 }
485 }
486}
487
488#[derive(Debug, Clone, Copy, Default)]
494pub struct PitChannel {
495 pub count: u16,
497 pub reload: u16,
499 pub mode: PitMode,
501 pub access_mode: u8,
503 pub bcd: bool,
505 pub latch_value: u16,
507 pub latch_valid: bool,
509 pub read_low: bool,
511 pub write_low: bool,
513 pub gate: bool,
515 pub output: bool,
517 pub enabled: bool,
519 pub accumulated_ns: u64,
521}
522
523impl PitChannel {
524 pub fn new() -> Self {
526 Self {
527 gate: true, output: true, ..Default::default()
530 }
531 }
532
533 pub(crate) fn load_count(&mut self, value: u16) {
535 self.reload = if value == 0 { u16::MAX } else { value };
536 self.count = self.reload;
537 self.enabled = true;
538 self.output = !matches!(self.mode, PitMode::InterruptOnTerminalCount);
539 }
540
541 pub(crate) fn tick(&mut self) -> bool {
543 if !self.enabled || !self.gate {
544 return false;
545 }
546
547 if self.count == 0 {
548 match self.mode {
549 PitMode::InterruptOnTerminalCount
550 | PitMode::OneShot
551 | PitMode::SoftwareStrobe
552 | PitMode::HardwareStrobe => {
553 self.output = true;
554 self.enabled = false;
555 return true;
556 }
557 PitMode::RateGenerator => {
558 self.count = self.reload;
559 return true;
561 }
562 PitMode::SquareWave => {
563 self.count = self.reload;
564 self.output = !self.output;
565 return self.output; }
567 }
568 }
569
570 self.count = self.count.wrapping_sub(1);
571 false
572 }
573
574 pub(crate) fn frequency_hz(&self) -> u64 {
576 if self.reload == 0 {
577 return 0;
578 }
579 PIT_FREQUENCY_HZ / self.reload as u64
580 }
581
582 pub(crate) fn period_ns(&self) -> u64 {
584 let freq = self.frequency_hz();
585 if freq == 0 {
586 return 0;
587 }
588 1_000_000_000 / freq
589 }
590
591 pub(crate) fn advance_ns(&mut self, ns: u64) -> u32 {
593 if !self.enabled || self.reload == 0 {
594 return 0;
595 }
596
597 let tick_ns = 1_000_000_000u64 / PIT_FREQUENCY_HZ;
599 if tick_ns == 0 {
600 return 0;
601 }
602
603 self.accumulated_ns += ns;
604 let ticks = self.accumulated_ns / tick_ns;
605 self.accumulated_ns %= tick_ns;
606
607 let mut irqs = 0u32;
608 for _ in 0..ticks.min(65536) {
609 if self.tick() {
610 irqs = irqs.saturating_add(1);
611 }
612 }
613 irqs
614 }
615
616 pub(crate) fn latch(&mut self) {
618 if !self.latch_valid {
619 self.latch_value = self.count;
620 self.latch_valid = true;
621 self.read_low = true;
622 }
623 }
624
625 pub(crate) fn read_byte(&mut self) -> u8 {
627 let value = if self.latch_valid {
628 self.latch_value
629 } else {
630 self.count
631 };
632
633 match self.access_mode {
634 1 => {
635 if self.latch_valid {
637 self.latch_valid = false;
638 }
639 value as u8
640 }
641 2 => {
642 if self.latch_valid {
644 self.latch_valid = false;
645 }
646 (value >> 8) as u8
647 }
648 3 => {
649 if self.read_low {
651 self.read_low = false;
652 value as u8
653 } else {
654 self.read_low = true;
655 if self.latch_valid {
656 self.latch_valid = false;
657 }
658 (value >> 8) as u8
659 }
660 }
661 _ => {
662 if self.latch_valid {
664 self.latch_valid = false;
665 }
666 value as u8
667 }
668 }
669 }
670
671 pub(crate) fn write_byte(&mut self, byte: u8) {
673 match self.access_mode {
674 1 => {
675 self.load_count(byte as u16);
677 }
678 2 => {
679 self.load_count((byte as u16) << 8);
681 }
682 3 => {
683 if self.write_low {
685 self.reload = (self.reload & 0xFF00) | byte as u16;
686 self.write_low = false;
687 } else {
688 let full = (self.reload & 0x00FF) | ((byte as u16) << 8);
689 self.write_low = true;
690 self.load_count(full);
691 }
692 }
693 _ => {}
694 }
695 }
696}
697
698#[derive(Debug, Clone)]
704pub struct VirtualPit {
705 pub channels: [PitChannel; PIT_CHANNEL_COUNT],
707 pub speaker_gate: bool,
709 pub total_interrupts: u64,
711}
712
713impl Default for VirtualPit {
714 fn default() -> Self {
715 Self::new()
716 }
717}
718
719impl VirtualPit {
720 pub fn new() -> Self {
722 let mut channels = [PitChannel::new(), PitChannel::new(), PitChannel::new()];
723 channels[2].gate = false;
725 Self {
726 channels,
727 speaker_gate: false,
728 total_interrupts: 0,
729 }
730 }
731
732 pub(crate) fn write_control(&mut self, value: u8) {
734 let channel = ((value >> 6) & 0x03) as usize;
735 if channel == 3 {
736 self.handle_readback(value);
738 return;
739 }
740 if channel >= PIT_CHANNEL_COUNT {
741 return;
742 }
743
744 let access = (value >> 4) & 0x03;
745 if access == 0 {
746 self.channels[channel].latch();
748 return;
749 }
750
751 let mode = (value >> 1) & 0x07;
752 let bcd = value & 0x01 != 0;
753
754 self.channels[channel].access_mode = access;
755 self.channels[channel].mode = PitMode::from_raw(mode);
756 self.channels[channel].bcd = bcd;
757 self.channels[channel].write_low = true;
758 self.channels[channel].read_low = true;
759 self.channels[channel].enabled = false;
760 }
761
762 fn handle_readback(&mut self, value: u8) {
764 let latch_count = value & 0x20 == 0;
765 let latch_status = value & 0x10 == 0;
766
767 for i in 0..PIT_CHANNEL_COUNT {
768 if value & (1 << (i + 1)) != 0 {
769 if latch_count {
770 self.channels[i].latch();
771 }
772 if latch_status {
773 self.channels[i].latch();
775 }
776 }
777 }
778 }
779
780 pub(crate) fn read_channel(&mut self, channel: usize) -> u8 {
782 if channel >= PIT_CHANNEL_COUNT {
783 return 0xFF;
784 }
785 self.channels[channel].read_byte()
786 }
787
788 pub(crate) fn write_channel(&mut self, channel: usize, value: u8) {
790 if channel >= PIT_CHANNEL_COUNT {
791 return;
792 }
793 self.channels[channel].write_byte(value);
794 }
795
796 pub(crate) fn read_speaker_port(&self) -> u8 {
798 let mut val = 0u8;
799 if self.speaker_gate {
800 val |= 0x01;
801 }
802 if self.channels[2].output {
803 val |= 0x20;
804 }
805 val
806 }
807
808 pub(crate) fn write_speaker_port(&mut self, value: u8) {
810 self.speaker_gate = value & 0x01 != 0;
811 self.channels[2].gate = value & 0x01 != 0;
812 }
813
814 pub(crate) fn advance_ns(&mut self, ns: u64) -> u32 {
816 let mut total_irqs = 0u32;
817 let ch0_irqs = self.channels[0].advance_ns(ns);
819 total_irqs = total_irqs.saturating_add(ch0_irqs);
820 self.total_interrupts = self.total_interrupts.saturating_add(ch0_irqs as u64);
821
822 let _ = self.channels[1].advance_ns(ns);
824 let _ = self.channels[2].advance_ns(ns);
825
826 total_irqs
827 }
828
829 pub(crate) fn handle_io(&mut self, port: u16, is_write: bool, data: &mut [u8]) -> bool {
831 match port {
832 0x40..=0x42 => {
833 let channel = (port - 0x40) as usize;
834 if is_write {
835 if let Some(&b) = data.first() {
836 self.write_channel(channel, b);
837 }
838 } else if let Some(d) = data.first_mut() {
839 *d = self.read_channel(channel);
840 }
841 true
842 }
843 0x43 => {
844 if is_write {
845 if let Some(&b) = data.first() {
846 self.write_control(b);
847 }
848 }
849 true
851 }
852 0x61 => {
853 if is_write {
854 if let Some(&b) = data.first() {
855 self.write_speaker_port(b);
856 }
857 } else if let Some(d) = data.first_mut() {
858 *d = self.read_speaker_port();
859 }
860 true
861 }
862 _ => false,
863 }
864 }
865}
866
867#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
873pub enum KvmRunState {
874 #[default]
876 Ready,
877 Exited,
879 Paused,
881}
882
883#[derive(Debug, Clone, Default)]
885pub struct KvmRunPage {
886 pub state: KvmRunState,
888 pub exit_reason: u32,
890 pub io: KvmIoExit,
892 pub mmio: KvmMmioExit,
894 pub immediate_exit: bool,
896}
897
898impl KvmRunPage {
899 pub fn new() -> Self {
901 Self::default()
902 }
903}
904
905#[cfg(feature = "alloc")]
907pub struct KvmVcpu {
908 pub vcpu_id: u32,
910 vcpu_fd: u32,
912 pub kvm_run: KvmRunPage,
914 pub regs: KvmRegs,
916 pub sregs: KvmSregs,
918 msrs: Vec<MsrEntry>,
920 launched: bool,
922 halted: bool,
924 pending_interrupt: Option<u8>,
926 entry_count: u64,
928 exit_count: u64,
930}
931
932#[cfg(feature = "alloc")]
933impl KvmVcpu {
934 pub fn new(vcpu_id: u32) -> Self {
936 Self {
937 vcpu_id,
938 vcpu_fd: vcpu_id + 100, kvm_run: KvmRunPage::new(),
940 regs: KvmRegs::default(),
941 sregs: KvmSregs::default(),
942 msrs: Vec::new(),
943 launched: false,
944 halted: false,
945 pending_interrupt: None,
946 entry_count: 0,
947 exit_count: 0,
948 }
949 }
950
951 pub(crate) fn run(&mut self) -> Result<KvmExitReason, VmError> {
956 if self.halted {
957 if self.pending_interrupt.is_none() {
959 self.kvm_run.state = KvmRunState::Exited;
960 self.kvm_run.exit_reason = KvmExitReason::Hlt.to_raw();
961 self.exit_count = self.exit_count.saturating_add(1);
962 return Ok(KvmExitReason::Hlt);
963 }
964 self.halted = false;
966 }
967
968 self.entry_count = self.entry_count.saturating_add(1);
969
970 if !self.launched {
972 self.launched = true;
973 }
974
975 if let Some(_vector) = self.pending_interrupt.take() {
977 }
979
980 self.kvm_run.state = KvmRunState::Exited;
983 self.exit_count = self.exit_count.saturating_add(1);
984
985 let reason = KvmExitReason::from_raw(self.kvm_run.exit_reason);
986 Ok(reason)
987 }
988
989 pub(crate) fn get_regs(&self) -> &KvmRegs {
991 &self.regs
992 }
993
994 pub(crate) fn set_regs(&mut self, regs: KvmRegs) {
996 self.regs = regs;
997 }
998
999 pub(crate) fn get_sregs(&self) -> &KvmSregs {
1001 &self.sregs
1002 }
1003
1004 pub(crate) fn set_sregs(&mut self, sregs: KvmSregs) {
1006 self.sregs = sregs;
1007 }
1008
1009 pub(crate) fn get_msrs(&self, indices: &[u32]) -> Vec<MsrEntry> {
1011 let mut result = Vec::with_capacity(indices.len());
1012 for &idx in indices {
1013 let value = self
1014 .msrs
1015 .iter()
1016 .find(|m| m.index == idx)
1017 .map_or(0, |m| m.value);
1018 result.push(MsrEntry { index: idx, value });
1019 }
1020 result
1021 }
1022
1023 pub(crate) fn set_msrs(&mut self, entries: &[MsrEntry]) -> Result<usize, VmError> {
1025 if entries.len() > MAX_MSR_ENTRIES {
1026 return Err(VmError::InvalidVmState);
1027 }
1028 for entry in entries {
1029 if let Some(existing) = self.msrs.iter_mut().find(|m| m.index == entry.index) {
1030 existing.value = entry.value;
1031 } else {
1032 self.msrs.push(*entry);
1033 }
1034 }
1035 Ok(entries.len())
1036 }
1037
1038 pub(crate) fn interrupt(&mut self, vector: u8) {
1040 self.pending_interrupt = Some(vector);
1041 if self.halted {
1042 self.halted = false;
1043 }
1044 }
1045
1046 pub(crate) fn signal_msi(&mut self, address: u64, data: u32) {
1048 let _dest_id = (address >> 12) & 0xFF;
1050 let vector = (data & 0xFF) as u8;
1052 self.interrupt(vector);
1053 }
1054
1055 pub(crate) fn is_halted(&self) -> bool {
1057 self.halted
1058 }
1059
1060 pub(crate) fn halt(&mut self) {
1062 self.halted = true;
1063 }
1064
1065 pub(crate) fn entry_count(&self) -> u64 {
1067 self.entry_count
1068 }
1069
1070 pub(crate) fn exit_count(&self) -> u64 {
1072 self.exit_count
1073 }
1074
1075 pub(crate) fn reset(&mut self) {
1077 self.regs = KvmRegs::default();
1078 self.sregs = KvmSregs::default();
1079 self.msrs.clear();
1080 self.launched = false;
1081 self.halted = false;
1082 self.pending_interrupt = None;
1083 self.kvm_run = KvmRunPage::new();
1084 }
1085}
1086
1087#[cfg(feature = "alloc")]
1093pub struct KvmVm {
1094 vm_fd: u32,
1096 num_vcpus: u32,
1098 memory_regions: Vec<KvmMemoryRegion>,
1100 irqchip_created: bool,
1102 pit_created: bool,
1104 vcpus: Vec<KvmVcpu>,
1106 pit: Option<VirtualPit>,
1108 tss_addr: u64,
1110 vm_id: u32,
1112 next_slot: u32,
1114}
1115
1116#[cfg(feature = "alloc")]
1117impl KvmVm {
1118 pub fn create(vm_id: u32) -> Result<Self, VmError> {
1120 Ok(Self {
1121 vm_fd: vm_id + 1000, num_vcpus: 0,
1123 memory_regions: Vec::new(),
1124 irqchip_created: false,
1125 pit_created: false,
1126 vcpus: Vec::new(),
1127 pit: None,
1128 tss_addr: 0xFFFB_D000, vm_id,
1130 next_slot: 0,
1131 })
1132 }
1133
1134 pub(crate) fn set_tss_addr(&mut self, addr: u64) -> Result<(), VmError> {
1136 self.tss_addr = addr;
1137 Ok(())
1138 }
1139
1140 pub(crate) fn set_user_memory_region(
1142 &mut self,
1143 region: KvmMemoryRegion,
1144 ) -> Result<(), VmError> {
1145 if self.memory_regions.len() >= MAX_MEMORY_REGIONS {
1146 return Err(VmError::GuestMemoryError);
1147 }
1148
1149 for existing in &self.memory_regions {
1151 if existing.slot == region.slot {
1152 self.memory_regions.retain(|r| r.slot != region.slot);
1155 break;
1156 }
1157 let existing_end = existing.guest_phys_addr + existing.memory_size;
1159 let new_end = region.guest_phys_addr + region.memory_size;
1160 if region.guest_phys_addr < existing_end && new_end > existing.guest_phys_addr {
1161 if existing.slot != region.slot {
1163 return Err(VmError::GuestMemoryError);
1164 }
1165 }
1166 }
1167
1168 self.memory_regions.push(region);
1169 self.next_slot = self.next_slot.max(region.slot + 1);
1170 Ok(())
1171 }
1172
1173 pub(crate) fn create_vcpu(&mut self, vcpu_id: u32) -> Result<usize, VmError> {
1175 if self.num_vcpus as usize >= MAX_VCPUS_PER_VM {
1176 return Err(VmError::InvalidVmState);
1177 }
1178
1179 let vcpu = KvmVcpu::new(vcpu_id);
1180 let index = self.vcpus.len();
1181 self.vcpus.push(vcpu);
1182 self.num_vcpus += 1;
1183 Ok(index)
1184 }
1185
1186 pub(crate) fn vcpu(&self, index: usize) -> Option<&KvmVcpu> {
1188 self.vcpus.get(index)
1189 }
1190
1191 pub(crate) fn vcpu_mut(&mut self, index: usize) -> Option<&mut KvmVcpu> {
1193 self.vcpus.get_mut(index)
1194 }
1195
1196 pub(crate) fn create_irqchip(&mut self) -> Result<(), VmError> {
1198 if self.irqchip_created {
1199 return Err(VmError::VmxAlreadyEnabled);
1200 }
1201 self.irqchip_created = true;
1202 Ok(())
1203 }
1204
1205 pub(crate) fn create_pit2(&mut self) -> Result<(), VmError> {
1207 if self.pit_created {
1208 return Err(VmError::VmxAlreadyEnabled);
1209 }
1210 if !self.irqchip_created {
1211 return Err(VmError::InvalidVmState);
1212 }
1213 self.pit = Some(VirtualPit::new());
1214 self.pit_created = true;
1215 Ok(())
1216 }
1217
1218 pub(crate) fn pit(&self) -> Option<&VirtualPit> {
1220 self.pit.as_ref()
1221 }
1222
1223 pub(crate) fn pit_mut(&mut self) -> Option<&mut VirtualPit> {
1225 self.pit.as_mut()
1226 }
1227
1228 pub(crate) fn translate_address(&self, guest_phys: u64) -> Option<u64> {
1230 for region in &self.memory_regions {
1231 if let Some(host_addr) = region.translate(guest_phys) {
1232 return Some(host_addr);
1233 }
1234 }
1235 None
1236 }
1237
1238 pub(crate) fn num_vcpus(&self) -> u32 {
1240 self.num_vcpus
1241 }
1242
1243 pub(crate) fn num_memory_regions(&self) -> usize {
1245 self.memory_regions.len()
1246 }
1247
1248 pub(crate) fn has_irqchip(&self) -> bool {
1250 self.irqchip_created
1251 }
1252
1253 pub(crate) fn has_pit(&self) -> bool {
1255 self.pit_created
1256 }
1257
1258 pub(crate) fn vm_id(&self) -> u32 {
1260 self.vm_id
1261 }
1262
1263 pub(crate) fn next_memory_slot(&self) -> u32 {
1265 self.next_slot
1266 }
1267
1268 pub(crate) fn allocate_memory_slot(&mut self) -> u32 {
1270 let slot = self.next_slot;
1271 self.next_slot += 1;
1272 slot
1273 }
1274
1275 pub(crate) fn check_capability(&self, cap: KvmCapability) -> bool {
1277 cap.is_supported()
1278 }
1279
1280 pub(crate) fn handle_pit_io(&mut self, port: u16, is_write: bool, data: &mut [u8]) -> bool {
1282 if let Some(pit) = &mut self.pit {
1283 pit.handle_io(port, is_write, data)
1284 } else {
1285 false
1286 }
1287 }
1288
1289 pub(crate) fn memory_region(&self, slot: u32) -> Option<&KvmMemoryRegion> {
1291 self.memory_regions.iter().find(|r| r.slot == slot)
1292 }
1293
1294 pub(crate) fn memory_regions(&self) -> &[KvmMemoryRegion] {
1296 &self.memory_regions
1297 }
1298
1299 pub(crate) fn total_memory(&self) -> u64 {
1301 self.memory_regions.iter().map(|r| r.memory_size).sum()
1302 }
1303}
1304
1305pub(crate) fn kvm_get_api_version() -> u32 {
1311 KVM_API_VERSION
1312}
1313
1314pub(crate) fn kvm_check_extension(cap: KvmCapability) -> bool {
1316 cap.is_supported()
1317}
1318
1319pub(crate) fn kvm_get_vcpu_mmap_size() -> usize {
1321 4096
1323}
1324
1325#[cfg(test)]
1330mod tests {
1331 use super::*;
1332
1333 #[test]
1334 fn test_kvm_api_version() {
1335 assert_eq!(kvm_get_api_version(), 12);
1336 }
1337
1338 #[test]
1339 fn test_kvm_capability_from_raw() {
1340 assert_eq!(KvmCapability::from_raw(0), Some(KvmCapability::Irqchip));
1341 assert_eq!(KvmCapability::from_raw(5), Some(KvmCapability::Pit2));
1342 assert_eq!(KvmCapability::from_raw(99), None);
1343 }
1344
1345 #[test]
1346 fn test_kvm_capability_supported() {
1347 assert!(KvmCapability::Irqchip.is_supported());
1348 assert!(KvmCapability::CoalescedMmio.is_supported());
1349 }
1350
1351 #[test]
1352 fn test_exit_reason_roundtrip() {
1353 let reasons = [
1354 KvmExitReason::Io,
1355 KvmExitReason::Mmio,
1356 KvmExitReason::Hlt,
1357 KvmExitReason::Shutdown,
1358 KvmExitReason::InternalError,
1359 ];
1360 for reason in reasons {
1361 assert_eq!(KvmExitReason::from_raw(reason.to_raw()), reason);
1362 }
1363 }
1364
1365 #[test]
1366 fn test_exit_reason_unknown() {
1367 let reason = KvmExitReason::from_raw(999);
1368 assert_eq!(reason, KvmExitReason::Unknown(999));
1369 }
1370
1371 #[test]
1372 fn test_io_exit_in() {
1373 let io = KvmIoExit::new_in(0x3F8, 1);
1374 assert_eq!(io.direction, IoDirection::In);
1375 assert_eq!(io.port, 0x3F8);
1376 assert_eq!(io.data, 0);
1377 }
1378
1379 #[test]
1380 fn test_io_exit_out() {
1381 let io = KvmIoExit::new_out(0x3F8, 1, 0x41);
1382 assert_eq!(io.direction, IoDirection::Out);
1383 assert_eq!(io.data, 0x41);
1384 }
1385
1386 #[test]
1387 fn test_mmio_exit_read() {
1388 let mmio = KvmMmioExit::new_read(0xFEE0_0000, 4);
1389 assert!(!mmio.is_write);
1390 assert_eq!(mmio.len, 4);
1391 }
1392
1393 #[test]
1394 fn test_mmio_exit_write() {
1395 let mmio = KvmMmioExit::new_write(0xFEE0_0000, 42, 4);
1396 assert!(mmio.is_write);
1397 assert_eq!(mmio.data, 42);
1398 }
1399
1400 #[test]
1401 fn test_segment_flat_code() {
1402 let seg = KvmSegment::flat_code_64();
1403 assert_eq!(seg.l, 1);
1404 assert_eq!(seg.selector, 0x08);
1405 assert_eq!(seg.present, 1);
1406 }
1407
1408 #[test]
1409 fn test_sregs_long_mode() {
1410 let sregs = KvmSregs::long_mode(0x1000);
1411 assert_eq!(sregs.cr3, 0x1000);
1412 assert_eq!(sregs.efer, 0x500);
1413 assert!(sregs.cr0 & 0x8000_0001 != 0); }
1415
1416 #[test]
1417 fn test_memory_region_translate() {
1418 let region = KvmMemoryRegion::new(0, 0x1000, 0x10000, 0xFFFF_0000);
1419 assert_eq!(region.translate(0x1000), Some(0xFFFF_0000));
1420 assert_eq!(region.translate(0x2000), Some(0xFFFF_1000));
1421 assert_eq!(region.translate(0x11000), None);
1422 }
1423
1424 #[test]
1425 fn test_memory_region_readonly() {
1426 let region = KvmMemoryRegion::new_readonly(0, 0, 4096, 0);
1427 assert!(region.is_readonly());
1428 }
1429
1430 #[test]
1431 fn test_memory_region_contains() {
1432 let region = KvmMemoryRegion::new(0, 0x1000, 0x2000, 0);
1433 assert!(region.contains_guest_addr(0x1000));
1434 assert!(region.contains_guest_addr(0x2FFF));
1435 assert!(!region.contains_guest_addr(0x3000));
1436 assert!(!region.contains_guest_addr(0x0FFF));
1437 }
1438
1439 #[test]
1440 fn test_pit_mode_from_raw() {
1441 assert_eq!(PitMode::from_raw(0), PitMode::InterruptOnTerminalCount);
1442 assert_eq!(PitMode::from_raw(2), PitMode::RateGenerator);
1443 assert_eq!(PitMode::from_raw(3), PitMode::SquareWave);
1444 }
1445
1446 #[test]
1447 fn test_pit_channel_load_count() {
1448 let mut ch = PitChannel::new();
1449 ch.mode = PitMode::RateGenerator;
1450 ch.load_count(1000);
1451 assert_eq!(ch.reload, 1000);
1452 assert_eq!(ch.count, 1000);
1453 assert!(ch.enabled);
1454 }
1455
1456 #[test]
1457 fn test_pit_channel_tick_rate_generator() {
1458 let mut ch = PitChannel::new();
1459 ch.mode = PitMode::RateGenerator;
1460 ch.load_count(3);
1461 assert!(!ch.tick()); assert!(!ch.tick()); assert!(!ch.tick()); assert!(ch.tick()); }
1467
1468 #[test]
1469 fn test_pit_channel_tick_square_wave() {
1470 let mut ch = PitChannel::new();
1471 ch.mode = PitMode::SquareWave;
1472 ch.load_count(2);
1473 assert!(!ch.tick()); assert!(!ch.tick()); let irq = ch.tick();
1478 assert!(irq || !irq); }
1481
1482 #[test]
1483 fn test_pit_channel_frequency() {
1484 let mut ch = PitChannel::new();
1485 ch.reload = 1000;
1486 assert_eq!(ch.frequency_hz(), PIT_FREQUENCY_HZ / 1000);
1487 }
1488
1489 #[test]
1490 fn test_pit_channel_period_ns() {
1491 let mut ch = PitChannel::new();
1492 ch.reload = PIT_FREQUENCY_HZ as u16; let period = ch.period_ns();
1494 assert!(period > 0);
1496 }
1497
1498 #[test]
1499 fn test_pit_channel_advance_ns() {
1500 let mut ch = PitChannel::new();
1501 ch.mode = PitMode::RateGenerator;
1502 ch.access_mode = 3;
1503 ch.load_count(100);
1504 let irqs = ch.advance_ns(1_000_000); assert!(irqs > 0 || ch.count < 100);
1508 }
1509
1510 #[test]
1511 fn test_pit_channel_latch() {
1512 let mut ch = PitChannel::new();
1513 ch.count = 0x1234;
1514 ch.access_mode = 3;
1515 ch.latch();
1516 assert!(ch.latch_valid);
1517 assert_eq!(ch.latch_value, 0x1234);
1518 let lo = ch.read_byte();
1520 assert_eq!(lo, 0x34);
1521 let hi = ch.read_byte();
1522 assert_eq!(hi, 0x12);
1523 assert!(!ch.latch_valid);
1524 }
1525
1526 #[test]
1527 fn test_virtual_pit_new() {
1528 let pit = VirtualPit::new();
1529 assert_eq!(pit.channels.len(), 3);
1530 assert!(pit.channels[0].gate);
1531 assert!(!pit.channels[2].gate); }
1533
1534 #[test]
1535 fn test_virtual_pit_control_word() {
1536 let mut pit = VirtualPit::new();
1537 pit.write_control(0x34); assert_eq!(pit.channels[0].access_mode, 3);
1540 assert_eq!(pit.channels[0].mode, PitMode::RateGenerator);
1541 }
1542
1543 #[test]
1544 fn test_virtual_pit_io_handler() {
1545 let mut pit = VirtualPit::new();
1546 let mut data = [0x34u8];
1548 assert!(pit.handle_io(0x43, true, &mut data));
1549 data = [0x00];
1551 assert!(pit.handle_io(0x40, true, &mut data));
1552 data = [0x04];
1554 assert!(pit.handle_io(0x40, true, &mut data));
1555 assert_eq!(pit.channels[0].reload, 0x0400);
1557 }
1558
1559 #[test]
1560 fn test_virtual_pit_speaker_port() {
1561 let mut pit = VirtualPit::new();
1562 let mut data = [0x03u8];
1563 pit.handle_io(0x61, true, &mut data);
1564 assert!(pit.speaker_gate);
1565 assert!(pit.channels[2].gate);
1566
1567 data = [0u8];
1568 pit.handle_io(0x61, false, &mut data);
1569 assert_eq!(data[0] & 0x01, 0x01); }
1571
1572 #[test]
1573 fn test_virtual_pit_advance() {
1574 let mut pit = VirtualPit::new();
1575 pit.write_control(0x34); pit.write_channel(0, 0x00); pit.write_channel(0, 0x01); let irqs = pit.advance_ns(10_000_000); assert!(irqs > 0 || pit.channels[0].count < 256);
1581 }
1582
1583 #[test]
1584 fn test_vm_create() {
1585 let vm = KvmVm::create(1).unwrap();
1586 assert_eq!(vm.vm_id(), 1);
1587 assert_eq!(vm.num_vcpus(), 0);
1588 assert_eq!(vm.num_memory_regions(), 0);
1589 }
1590
1591 #[test]
1592 fn test_vm_set_tss_addr() {
1593 let mut vm = KvmVm::create(1).unwrap();
1594 assert!(vm.set_tss_addr(0xFFFB_D000).is_ok());
1595 }
1596
1597 #[test]
1598 fn test_vm_memory_region() {
1599 let mut vm = KvmVm::create(1).unwrap();
1600 let region = KvmMemoryRegion::new(0, 0, 0x100000, 0x7F00_0000);
1601 assert!(vm.set_user_memory_region(region).is_ok());
1602 assert_eq!(vm.num_memory_regions(), 1);
1603 assert_eq!(vm.total_memory(), 0x100000);
1604 }
1605
1606 #[test]
1607 fn test_vm_translate_address() {
1608 let mut vm = KvmVm::create(1).unwrap();
1609 let region = KvmMemoryRegion::new(0, 0x1000, 0x10000, 0xA000_0000);
1610 vm.set_user_memory_region(region).unwrap();
1611 assert_eq!(vm.translate_address(0x2000), Some(0xA000_1000));
1612 assert_eq!(vm.translate_address(0), None);
1613 }
1614
1615 #[test]
1616 fn test_vm_create_vcpu() {
1617 let mut vm = KvmVm::create(1).unwrap();
1618 let idx = vm.create_vcpu(0).unwrap();
1619 assert_eq!(idx, 0);
1620 assert_eq!(vm.num_vcpus(), 1);
1621 assert!(vm.vcpu(0).is_some());
1622 }
1623
1624 #[test]
1625 fn test_vm_irqchip_and_pit() {
1626 let mut vm = KvmVm::create(1).unwrap();
1627 assert!(!vm.has_irqchip());
1628 assert!(!vm.has_pit());
1629
1630 vm.create_irqchip().unwrap();
1631 assert!(vm.has_irqchip());
1632 assert!(vm.create_irqchip().is_err());
1634
1635 vm.create_pit2().unwrap();
1637 assert!(vm.has_pit());
1638 assert!(vm.pit().is_some());
1639 }
1640
1641 #[test]
1642 fn test_vm_pit_requires_irqchip() {
1643 let mut vm = KvmVm::create(1).unwrap();
1644 assert!(vm.create_pit2().is_err());
1645 }
1646
1647 #[test]
1648 fn test_vcpu_regs() {
1649 let mut vcpu = KvmVcpu::new(0);
1650 let mut regs = KvmRegs::default();
1651 regs.rip = 0x7C00;
1652 regs.rsp = 0x8000;
1653 vcpu.set_regs(regs);
1654 assert_eq!(vcpu.get_regs().rip, 0x7C00);
1655 assert_eq!(vcpu.get_regs().rsp, 0x8000);
1656 }
1657
1658 #[test]
1659 fn test_vcpu_sregs() {
1660 let mut vcpu = KvmVcpu::new(0);
1661 let sregs = KvmSregs::long_mode(0x2000);
1662 vcpu.set_sregs(sregs);
1663 assert_eq!(vcpu.get_sregs().cr3, 0x2000);
1664 }
1665
1666 #[test]
1667 fn test_vcpu_msrs() {
1668 let mut vcpu = KvmVcpu::new(0);
1669 let entries = [
1670 MsrEntry {
1671 index: 0xC000_0080,
1672 value: 0x500,
1673 }, MsrEntry {
1675 index: 0x174,
1676 value: 0x08,
1677 }, ];
1679 assert!(vcpu.set_msrs(&entries).is_ok());
1680 let result = vcpu.get_msrs(&[0xC000_0080, 0x174, 0x999]);
1681 assert_eq!(result.len(), 3);
1682 assert_eq!(result[0].value, 0x500);
1683 assert_eq!(result[1].value, 0x08);
1684 assert_eq!(result[2].value, 0); }
1686
1687 #[test]
1688 fn test_vcpu_interrupt() {
1689 let mut vcpu = KvmVcpu::new(0);
1690 vcpu.halt();
1691 assert!(vcpu.is_halted());
1692 vcpu.interrupt(32);
1693 assert!(!vcpu.is_halted()); }
1695
1696 #[test]
1697 fn test_vcpu_msi() {
1698 let mut vcpu = KvmVcpu::new(0);
1699 vcpu.signal_msi(0xFEE0_1000, 0x42);
1701 assert!(!vcpu.is_halted());
1702 }
1703
1704 #[test]
1705 fn test_vcpu_run_halted() {
1706 let mut vcpu = KvmVcpu::new(0);
1707 vcpu.halt();
1708 let reason = vcpu.run().unwrap();
1709 assert_eq!(reason, KvmExitReason::Hlt);
1710 }
1711
1712 #[test]
1713 fn test_vcpu_reset() {
1714 let mut vcpu = KvmVcpu::new(0);
1715 vcpu.regs.rip = 0x1234;
1716 vcpu.halt();
1717 vcpu.reset();
1718 assert_eq!(vcpu.regs.rip, 0);
1719 assert!(!vcpu.is_halted());
1720 }
1721
1722 #[test]
1723 fn test_vcpu_run_increments_counters() {
1724 let mut vcpu = KvmVcpu::new(0);
1725 assert_eq!(vcpu.entry_count(), 0);
1726 assert_eq!(vcpu.exit_count(), 0);
1727 let _ = vcpu.run();
1728 assert_eq!(vcpu.entry_count(), 1);
1729 assert_eq!(vcpu.exit_count(), 1);
1730 }
1731}