⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/virt/
kvm.rs

1//! KVM-compatible virtualization API
2//!
3//! Implements a KVM-like interface for creating and managing virtual machines,
4//! vCPUs, memory regions, and interrupt controllers. Provides VMLAUNCH/VMRESUME
5//! cycle with VM exit reason decoding.
6//!
7//! Sprints W5-S1 (core API), W5-S2 (vCPU management), W5-S3 (PIT emulation).
8
9#![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
19// ---------------------------------------------------------------------------
20// Constants
21// ---------------------------------------------------------------------------
22
23/// KVM API version (matches Linux KVM_API_VERSION)
24pub const KVM_API_VERSION: u32 = 12;
25
26/// Maximum vCPUs per VM
27const MAX_VCPUS_PER_VM: usize = 256;
28
29/// Maximum memory regions per VM
30const MAX_MEMORY_REGIONS: usize = 64;
31
32/// PIT oscillator frequency in Hz (1.193182 MHz as integer)
33const PIT_FREQUENCY_HZ: u64 = 1_193_182;
34
35/// PIT channel count
36const PIT_CHANNEL_COUNT: usize = 3;
37
38/// Maximum MSR entries for get/set operations
39const MAX_MSR_ENTRIES: usize = 256;
40
41// ---------------------------------------------------------------------------
42// KVM Capability
43// ---------------------------------------------------------------------------
44
45/// KVM capability identifiers
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum KvmCapability {
48    /// In-kernel IRQ chip emulation
49    Irqchip = 0,
50    /// HLT instruction interception
51    Hlt = 1,
52    /// Shadow MMU for paging
53    MmuShadow = 2,
54    /// User-space memory region mapping
55    UserMemory = 3,
56    /// TSS address configuration (x86)
57    SetTssAddr = 4,
58    /// PIT2 timer emulation
59    Pit2 = 5,
60    /// Extended CPUID results
61    ExtCpuid = 6,
62    /// Virtual APIC page
63    Vapic = 7,
64    /// MP state get/set
65    MpState = 8,
66    /// Coalesced MMIO batching
67    CoalescedMmio = 9,
68}
69
70impl KvmCapability {
71    /// Check if this capability is supported
72    pub(crate) fn is_supported(&self) -> bool {
73        // All capabilities supported in our implementation
74        true
75    }
76
77    /// Convert from raw integer
78    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// ---------------------------------------------------------------------------
96// KVM Exit Reasons
97// ---------------------------------------------------------------------------
98
99/// VM exit reason from KVM run
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum KvmExitReason {
102    /// I/O port access
103    Io,
104    /// Memory-mapped I/O access
105    Mmio,
106    /// HLT instruction executed
107    Hlt,
108    /// VM shutdown requested
109    Shutdown,
110    /// Internal KVM error
111    InternalError,
112    /// Unknown exit reason
113    Unknown(u32),
114}
115
116impl KvmExitReason {
117    /// Convert from raw exit code
118    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    /// Convert to raw exit code
130    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// ---------------------------------------------------------------------------
143// I/O Direction
144// ---------------------------------------------------------------------------
145
146/// Direction of I/O port access
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
148pub enum IoDirection {
149    /// Reading from port
150    #[default]
151    In,
152    /// Writing to port
153    Out,
154}
155
156// ---------------------------------------------------------------------------
157// KVM I/O Exit Info
158// ---------------------------------------------------------------------------
159
160/// Information about an I/O port VM exit
161#[derive(Debug, Clone, Copy, Default)]
162pub struct KvmIoExit {
163    /// Direction of I/O access
164    pub direction: IoDirection,
165    /// I/O port number
166    pub port: u16,
167    /// Access size in bytes (1, 2, or 4)
168    pub size: u8,
169    /// Data value (for Out) or buffer for read (for In)
170    pub data: u32,
171}
172
173impl KvmIoExit {
174    /// Create a new I/O exit for an IN instruction
175    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    /// Create a new I/O exit for an OUT instruction
185    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// ---------------------------------------------------------------------------
196// KVM MMIO Exit Info
197// ---------------------------------------------------------------------------
198
199/// Information about an MMIO VM exit
200#[derive(Debug, Clone, Copy, Default)]
201pub struct KvmMmioExit {
202    /// Physical address accessed
203    pub phys_addr: u64,
204    /// Data value
205    pub data: u64,
206    /// Access length in bytes
207    pub len: u8,
208    /// True if this is a write, false for read
209    pub is_write: bool,
210}
211
212impl KvmMmioExit {
213    /// Create a new MMIO exit for a read
214    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    /// Create a new MMIO exit for a write
224    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// ---------------------------------------------------------------------------
235// General-Purpose Registers
236// ---------------------------------------------------------------------------
237
238/// x86_64 general-purpose register set
239#[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// ---------------------------------------------------------------------------
262// Segment Register
263// ---------------------------------------------------------------------------
264
265/// x86 segment register descriptor
266#[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    /// Create a flat code segment for long mode
283    pub(crate) fn flat_code_64() -> Self {
284        Self {
285            base: 0,
286            limit: 0xFFFF_FFFF,
287            selector: 0x08,
288            type_attr: 0x0B, // Execute/Read, Accessed
289            present: 1,
290            dpl: 0,
291            db: 0,
292            s: 1,
293            l: 1, // Long mode
294            g: 1, // 4K granularity
295            avl: 0,
296        }
297    }
298
299    /// Create a flat data segment for long mode
300    pub(crate) fn flat_data_64() -> Self {
301        Self {
302            base: 0,
303            limit: 0xFFFF_FFFF,
304            selector: 0x10,
305            type_attr: 0x03, // Read/Write, Accessed
306            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// ---------------------------------------------------------------------------
318// System (Special) Registers
319// ---------------------------------------------------------------------------
320
321/// x86_64 system register set (segment + control registers)
322#[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    /// Create sregs for real mode entry
341    pub(crate) fn real_mode() -> Self {
342        Self {
343            cr0: 0x10, // ET bit set
344            ..Default::default()
345        }
346    }
347
348    /// Create sregs for 64-bit long mode
349    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, // PG | PE | ET
358            cr3,
359            cr4: 0x20,   // PAE
360            efer: 0x500, // LME | LMA
361            ..Default::default()
362        }
363    }
364}
365
366// ---------------------------------------------------------------------------
367// MSR Entry
368// ---------------------------------------------------------------------------
369
370/// Model-Specific Register entry
371#[derive(Debug, Clone, Copy, Default)]
372pub struct MsrEntry {
373    /// MSR index
374    pub index: u32,
375    /// MSR value
376    pub value: u64,
377}
378
379// ---------------------------------------------------------------------------
380// Memory Region
381// ---------------------------------------------------------------------------
382
383/// A user memory region mapping guest physical to host virtual
384#[derive(Debug, Clone, Copy)]
385pub struct KvmMemoryRegion {
386    /// Slot index for this region
387    pub slot: u32,
388    /// Flags (e.g., read-only)
389    pub flags: u32,
390    /// Guest physical address
391    pub guest_phys_addr: u64,
392    /// Size in bytes
393    pub memory_size: u64,
394    /// Host virtual address (userspace pointer)
395    pub userspace_addr: u64,
396}
397
398impl KvmMemoryRegion {
399    /// Flag: memory region is read-only
400    pub const FLAG_READONLY: u32 = 1;
401    /// Flag: memory region has dirty page logging
402    pub const FLAG_LOG_DIRTY: u32 = 2;
403
404    /// Create a new memory region
405    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    /// Create a read-only memory region
416    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    /// Check if region is read-only
427    pub(crate) fn is_readonly(&self) -> bool {
428        self.flags & Self::FLAG_READONLY != 0
429    }
430
431    /// Check if region has dirty logging enabled
432    pub(crate) fn has_dirty_logging(&self) -> bool {
433        self.flags & Self::FLAG_LOG_DIRTY != 0
434    }
435
436    /// Check if an address falls within this region
437    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    /// Translate guest physical to host virtual address
442    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// ---------------------------------------------------------------------------
452// PIT Timer Modes
453// ---------------------------------------------------------------------------
454
455/// PIT counter operating mode
456#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
457pub enum PitMode {
458    /// Mode 0: Interrupt on terminal count
459    #[default]
460    InterruptOnTerminalCount,
461    /// Mode 1: Hardware retriggerable one-shot
462    OneShot,
463    /// Mode 2: Rate generator (periodic)
464    RateGenerator,
465    /// Mode 3: Square wave generator
466    SquareWave,
467    /// Mode 4: Software triggered strobe
468    SoftwareStrobe,
469    /// Mode 5: Hardware triggered strobe
470    HardwareStrobe,
471}
472
473impl PitMode {
474    /// Convert from raw mode bits
475    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// ---------------------------------------------------------------------------
489// PIT Channel
490// ---------------------------------------------------------------------------
491
492/// State for a single PIT counter channel
493#[derive(Debug, Clone, Copy, Default)]
494pub struct PitChannel {
495    /// Current counter value
496    pub count: u16,
497    /// Reload value (initial count)
498    pub reload: u16,
499    /// Operating mode
500    pub mode: PitMode,
501    /// Access mode: 0=latch, 1=lo, 2=hi, 3=lo/hi
502    pub access_mode: u8,
503    /// BCD mode if true
504    pub bcd: bool,
505    /// Latch value (captured on latch command)
506    pub latch_value: u16,
507    /// Whether latch is valid
508    pub latch_valid: bool,
509    /// Whether reading low byte next (for lo/hi mode)
510    pub read_low: bool,
511    /// Whether writing low byte next (for lo/hi mode)
512    pub write_low: bool,
513    /// Gate input state
514    pub gate: bool,
515    /// Output state
516    pub output: bool,
517    /// Whether the counter is enabled (counting)
518    pub enabled: bool,
519    /// Accumulated nanoseconds for tick tracking
520    pub accumulated_ns: u64,
521}
522
523impl PitChannel {
524    /// Create a new PIT channel with default state
525    pub fn new() -> Self {
526        Self {
527            gate: true,   // Gate high by default for channels 0,1
528            output: true, // Output high initially
529            ..Default::default()
530        }
531    }
532
533    /// Load a new count value
534    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    /// Tick the counter by one unit
542    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                    // Generate short low pulse
560                    return true;
561                }
562                PitMode::SquareWave => {
563                    self.count = self.reload;
564                    self.output = !self.output;
565                    return self.output; // IRQ on rising edge
566                }
567            }
568        }
569
570        self.count = self.count.wrapping_sub(1);
571        false
572    }
573
574    /// Calculate the frequency in Hz (integer)
575    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    /// Calculate the period in nanoseconds (integer)
583    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    /// Advance by a number of nanoseconds, return number of interrupts fired
592    pub(crate) fn advance_ns(&mut self, ns: u64) -> u32 {
593        if !self.enabled || self.reload == 0 {
594            return 0;
595        }
596
597        // Period of one tick in ns: 1_000_000_000 / PIT_FREQUENCY_HZ ~= 838 ns
598        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    /// Latch the current counter value
617    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    /// Read a byte from the channel (respects latch and access mode)
626    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                // Low byte only
636                if self.latch_valid {
637                    self.latch_valid = false;
638                }
639                value as u8
640            }
641            2 => {
642                // High byte only
643                if self.latch_valid {
644                    self.latch_valid = false;
645                }
646                (value >> 8) as u8
647            }
648            3 => {
649                // Low/high alternating
650                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                // Latch mode: read latched value
663                if self.latch_valid {
664                    self.latch_valid = false;
665                }
666                value as u8
667            }
668        }
669    }
670
671    /// Write a byte to the channel (respects access mode)
672    pub(crate) fn write_byte(&mut self, byte: u8) {
673        match self.access_mode {
674            1 => {
675                // Low byte only
676                self.load_count(byte as u16);
677            }
678            2 => {
679                // High byte only
680                self.load_count((byte as u16) << 8);
681            }
682            3 => {
683                // Low/high alternating
684                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// ---------------------------------------------------------------------------
699// Virtual PIT
700// ---------------------------------------------------------------------------
701
702/// 8254/8253-compatible Programmable Interval Timer
703#[derive(Debug, Clone)]
704pub struct VirtualPit {
705    /// Three counter channels
706    pub channels: [PitChannel; PIT_CHANNEL_COUNT],
707    /// Speaker gate (channel 2)
708    pub speaker_gate: bool,
709    /// Total interrupts generated
710    pub total_interrupts: u64,
711}
712
713impl Default for VirtualPit {
714    fn default() -> Self {
715        Self::new()
716    }
717}
718
719impl VirtualPit {
720    /// Create a new PIT with default channel configuration
721    pub fn new() -> Self {
722        let mut channels = [PitChannel::new(), PitChannel::new(), PitChannel::new()];
723        // Channel 2 gate is controlled by speaker port
724        channels[2].gate = false;
725        Self {
726            channels,
727            speaker_gate: false,
728            total_interrupts: 0,
729        }
730    }
731
732    /// Handle I/O write to PIT control word register (port 0x43)
733    pub(crate) fn write_control(&mut self, value: u8) {
734        let channel = ((value >> 6) & 0x03) as usize;
735        if channel == 3 {
736            // Read-back command
737            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            // Latch command
747            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    /// Handle read-back command
763    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                    // Status latch: not fully implemented, just latch count
774                    self.channels[i].latch();
775                }
776            }
777        }
778    }
779
780    /// Handle I/O read from a channel data port
781    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    /// Handle I/O write to a channel data port
789    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    /// Handle speaker control port (0x61) read
797    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    /// Handle speaker control port (0x61) write
809    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    /// Advance all channels by a number of nanoseconds
815    pub(crate) fn advance_ns(&mut self, ns: u64) -> u32 {
816        let mut total_irqs = 0u32;
817        // Channel 0 is typically connected to IRQ 0
818        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        // Advance channels 1 and 2 but don't count their IRQs towards total
823        let _ = self.channels[1].advance_ns(ns);
824        let _ = self.channels[2].advance_ns(ns);
825
826        total_irqs
827    }
828
829    /// Handle PIT I/O port access (ports 0x40-0x43, 0x61)
830    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                // Control port is write-only
850                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// ---------------------------------------------------------------------------
868// KVM vCPU
869// ---------------------------------------------------------------------------
870
871/// Run state for the shared KVM run page
872#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
873pub enum KvmRunState {
874    /// vCPU is ready to run
875    #[default]
876    Ready,
877    /// vCPU exited and needs handling
878    Exited,
879    /// vCPU is paused
880    Paused,
881}
882
883/// Shared run page between kernel and userspace
884#[derive(Debug, Clone, Default)]
885pub struct KvmRunPage {
886    /// Current run state
887    pub state: KvmRunState,
888    /// Exit reason from last run
889    pub exit_reason: u32,
890    /// I/O exit info (valid when exit_reason == IO)
891    pub io: KvmIoExit,
892    /// MMIO exit info (valid when exit_reason == MMIO)
893    pub mmio: KvmMmioExit,
894    /// Whether the vCPU should continue to run after handling exit
895    pub immediate_exit: bool,
896}
897
898impl KvmRunPage {
899    /// Create a new run page
900    pub fn new() -> Self {
901        Self::default()
902    }
903}
904
905/// Virtual CPU state
906#[cfg(feature = "alloc")]
907pub struct KvmVcpu {
908    /// vCPU identifier within the VM
909    pub vcpu_id: u32,
910    /// vCPU file descriptor (simulated)
911    vcpu_fd: u32,
912    /// Shared run page
913    pub kvm_run: KvmRunPage,
914    /// General-purpose registers
915    pub regs: KvmRegs,
916    /// System/special registers
917    pub sregs: KvmSregs,
918    /// MSR storage
919    msrs: Vec<MsrEntry>,
920    /// Whether the vCPU has been launched (vs needs VMLAUNCH)
921    launched: bool,
922    /// Whether the vCPU is halted (HLT)
923    halted: bool,
924    /// Pending external interrupt vector (None = no pending)
925    pending_interrupt: Option<u8>,
926    /// Number of VM entries performed
927    entry_count: u64,
928    /// Number of VM exits handled
929    exit_count: u64,
930}
931
932#[cfg(feature = "alloc")]
933impl KvmVcpu {
934    /// Create a new vCPU with the given ID
935    pub fn new(vcpu_id: u32) -> Self {
936        Self {
937            vcpu_id,
938            vcpu_fd: vcpu_id + 100, // Simulated fd
939            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    /// Run the vCPU (VMLAUNCH or VMRESUME)
952    ///
953    /// Returns the exit reason. In a real implementation this would
954    /// execute a VMX VM entry; here we simulate common exit scenarios.
955    pub(crate) fn run(&mut self) -> Result<KvmExitReason, VmError> {
956        if self.halted {
957            // If halted and no pending interrupt, exit with HLT
958            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            // Unhalt on pending interrupt
965            self.halted = false;
966        }
967
968        self.entry_count = self.entry_count.saturating_add(1);
969
970        // In a real implementation: VMLAUNCH (first time) or VMRESUME
971        if !self.launched {
972            self.launched = true;
973        }
974
975        // Inject pending interrupt if any
976        if let Some(_vector) = self.pending_interrupt.take() {
977            // Would set VM-entry interruption-information field
978        }
979
980        // Simulate: the VM ran and exited for some reason
981        // Real implementation would decode VMCS exit reason
982        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    /// Get general-purpose registers
990    pub(crate) fn get_regs(&self) -> &KvmRegs {
991        &self.regs
992    }
993
994    /// Set general-purpose registers
995    pub(crate) fn set_regs(&mut self, regs: KvmRegs) {
996        self.regs = regs;
997    }
998
999    /// Get system registers
1000    pub(crate) fn get_sregs(&self) -> &KvmSregs {
1001        &self.sregs
1002    }
1003
1004    /// Set system registers
1005    pub(crate) fn set_sregs(&mut self, sregs: KvmSregs) {
1006        self.sregs = sregs;
1007    }
1008
1009    /// Get MSR values
1010    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    /// Set MSR values
1024    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    /// Inject an external interrupt
1039    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    /// Signal an MSI interrupt
1047    pub(crate) fn signal_msi(&mut self, address: u64, data: u32) {
1048        // MSI address format: destination ID in bits 19:12
1049        let _dest_id = (address >> 12) & 0xFF;
1050        // MSI data: vector in bits 7:0
1051        let vector = (data & 0xFF) as u8;
1052        self.interrupt(vector);
1053    }
1054
1055    /// Check if vCPU is halted
1056    pub(crate) fn is_halted(&self) -> bool {
1057        self.halted
1058    }
1059
1060    /// Halt the vCPU (simulates HLT instruction)
1061    pub(crate) fn halt(&mut self) {
1062        self.halted = true;
1063    }
1064
1065    /// Get entry count
1066    pub(crate) fn entry_count(&self) -> u64 {
1067        self.entry_count
1068    }
1069
1070    /// Get exit count
1071    pub(crate) fn exit_count(&self) -> u64 {
1072        self.exit_count
1073    }
1074
1075    /// Reset the vCPU to initial state
1076    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// ---------------------------------------------------------------------------
1088// KVM VM
1089// ---------------------------------------------------------------------------
1090
1091/// Virtual Machine instance
1092#[cfg(feature = "alloc")]
1093pub struct KvmVm {
1094    /// VM file descriptor (simulated)
1095    vm_fd: u32,
1096    /// Number of vCPUs created
1097    num_vcpus: u32,
1098    /// Guest memory regions
1099    memory_regions: Vec<KvmMemoryRegion>,
1100    /// Whether in-kernel irqchip is created
1101    irqchip_created: bool,
1102    /// Whether in-kernel PIT is created
1103    pit_created: bool,
1104    /// vCPUs belonging to this VM
1105    vcpus: Vec<KvmVcpu>,
1106    /// Virtual PIT (created on demand)
1107    pit: Option<VirtualPit>,
1108    /// TSS address (x86-specific)
1109    tss_addr: u64,
1110    /// VM identifier
1111    vm_id: u32,
1112    /// Next memory region slot
1113    next_slot: u32,
1114}
1115
1116#[cfg(feature = "alloc")]
1117impl KvmVm {
1118    /// Create a new VM
1119    pub fn create(vm_id: u32) -> Result<Self, VmError> {
1120        Ok(Self {
1121            vm_fd: vm_id + 1000, // Simulated fd
1122            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, // Default TSS address
1129            vm_id,
1130            next_slot: 0,
1131        })
1132    }
1133
1134    /// Set the TSS address (x86-specific, required before creating vCPUs)
1135    pub(crate) fn set_tss_addr(&mut self, addr: u64) -> Result<(), VmError> {
1136        self.tss_addr = addr;
1137        Ok(())
1138    }
1139
1140    /// Map a user memory region into the guest physical address space
1141    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        // Check for overlapping regions
1150        for existing in &self.memory_regions {
1151            if existing.slot == region.slot {
1152                // Replace existing slot
1153                // Remove old, add new below
1154                self.memory_regions.retain(|r| r.slot != region.slot);
1155                break;
1156            }
1157            // Check for guest physical address overlap
1158            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                // Overlapping -- allow replacement by slot, otherwise error
1162                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    /// Create a vCPU and return its index
1174    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    /// Get a reference to a vCPU by index
1187    pub(crate) fn vcpu(&self, index: usize) -> Option<&KvmVcpu> {
1188        self.vcpus.get(index)
1189    }
1190
1191    /// Get a mutable reference to a vCPU by index
1192    pub(crate) fn vcpu_mut(&mut self, index: usize) -> Option<&mut KvmVcpu> {
1193        self.vcpus.get_mut(index)
1194    }
1195
1196    /// Create an in-kernel IRQ chip (LAPIC + IOAPIC)
1197    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    /// Create an in-kernel PIT (i8254)
1206    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    /// Get the PIT if created
1219    pub(crate) fn pit(&self) -> Option<&VirtualPit> {
1220        self.pit.as_ref()
1221    }
1222
1223    /// Get mutable PIT if created
1224    pub(crate) fn pit_mut(&mut self) -> Option<&mut VirtualPit> {
1225        self.pit.as_mut()
1226    }
1227
1228    /// Translate a guest physical address to host virtual
1229    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    /// Get the number of vCPUs
1239    pub(crate) fn num_vcpus(&self) -> u32 {
1240        self.num_vcpus
1241    }
1242
1243    /// Get the number of memory regions
1244    pub(crate) fn num_memory_regions(&self) -> usize {
1245        self.memory_regions.len()
1246    }
1247
1248    /// Check if irqchip is created
1249    pub(crate) fn has_irqchip(&self) -> bool {
1250        self.irqchip_created
1251    }
1252
1253    /// Check if PIT is created
1254    pub(crate) fn has_pit(&self) -> bool {
1255        self.pit_created
1256    }
1257
1258    /// Get VM identifier
1259    pub(crate) fn vm_id(&self) -> u32 {
1260        self.vm_id
1261    }
1262
1263    /// Get next available memory slot
1264    pub(crate) fn next_memory_slot(&self) -> u32 {
1265        self.next_slot
1266    }
1267
1268    /// Allocate a new memory slot and return it
1269    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    /// Check a KVM capability
1276    pub(crate) fn check_capability(&self, cap: KvmCapability) -> bool {
1277        cap.is_supported()
1278    }
1279
1280    /// Dispatch I/O to PIT if appropriate
1281    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    /// Get memory region by slot
1290    pub(crate) fn memory_region(&self, slot: u32) -> Option<&KvmMemoryRegion> {
1291        self.memory_regions.iter().find(|r| r.slot == slot)
1292    }
1293
1294    /// List all memory regions
1295    pub(crate) fn memory_regions(&self) -> &[KvmMemoryRegion] {
1296        &self.memory_regions
1297    }
1298
1299    /// Get total guest memory size in bytes
1300    pub(crate) fn total_memory(&self) -> u64 {
1301        self.memory_regions.iter().map(|r| r.memory_size).sum()
1302    }
1303}
1304
1305// ---------------------------------------------------------------------------
1306// KVM System-level Functions
1307// ---------------------------------------------------------------------------
1308
1309/// Get the KVM API version
1310pub(crate) fn kvm_get_api_version() -> u32 {
1311    KVM_API_VERSION
1312}
1313
1314/// Check if KVM extension is available
1315pub(crate) fn kvm_check_extension(cap: KvmCapability) -> bool {
1316    cap.is_supported()
1317}
1318
1319/// Get the recommended vCPU map size
1320pub(crate) fn kvm_get_vcpu_mmap_size() -> usize {
1321    // Size of the KvmRunPage structure (page-aligned)
1322    4096
1323}
1324
1325// ---------------------------------------------------------------------------
1326// Tests
1327// ---------------------------------------------------------------------------
1328
1329#[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); // PG | PE
1414    }
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        // Tick down: 3, 2, 1, 0 -> reload
1462        assert!(!ch.tick()); // 2
1463        assert!(!ch.tick()); // 1
1464        assert!(!ch.tick()); // 0
1465        assert!(ch.tick()); // reload, IRQ
1466    }
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        // Tick down to 0 then toggle output
1474        assert!(!ch.tick()); // 1
1475        assert!(!ch.tick()); // 0
1476                             // At 0: toggle output, reload
1477        let irq = ch.tick();
1478        // Output toggled
1479        assert!(irq || !irq); // just testing it doesn't panic
1480    }
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; // ~1 Hz
1493        let period = ch.period_ns();
1494        // Should be approximately 1 second
1495        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        // Advance by enough ns for multiple ticks
1505        let irqs = ch.advance_ns(1_000_000); // 1ms
1506                                             // Should have produced some IRQs
1507        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        // Reading should return latched value
1519        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); // Speaker channel gate off
1532    }
1533
1534    #[test]
1535    fn test_virtual_pit_control_word() {
1536        let mut pit = VirtualPit::new();
1537        // Set channel 0 to rate generator, lo/hi access
1538        pit.write_control(0x34); // Channel 0, lo/hi, mode 2
1539        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        // Write control word
1547        let mut data = [0x34u8];
1548        assert!(pit.handle_io(0x43, true, &mut data));
1549        // Write count low byte
1550        data = [0x00];
1551        assert!(pit.handle_io(0x40, true, &mut data));
1552        // Write count high byte
1553        data = [0x04];
1554        assert!(pit.handle_io(0x40, true, &mut data));
1555        // Channel 0 should have reload = 0x0400
1556        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); // Gate bit set
1570    }
1571
1572    #[test]
1573    fn test_virtual_pit_advance() {
1574        let mut pit = VirtualPit::new();
1575        pit.write_control(0x34); // Ch0, lo/hi, rate generator
1576        pit.write_channel(0, 0x00); // lo byte
1577        pit.write_channel(0, 0x01); // hi byte -> reload = 256
1578        let irqs = pit.advance_ns(10_000_000); // 10ms
1579                                               // Should produce IRQs
1580        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        // Double create should fail
1633        assert!(vm.create_irqchip().is_err());
1634
1635        // PIT requires irqchip
1636        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            }, // IA32_EFER
1674            MsrEntry {
1675                index: 0x174,
1676                value: 0x08,
1677            }, // IA32_SYSENTER_CS
1678        ];
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); // Not found
1685    }
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()); // Interrupt wakes from halt
1694    }
1695
1696    #[test]
1697    fn test_vcpu_msi() {
1698        let mut vcpu = KvmVcpu::new(0);
1699        // MSI address with dest_id=1, vector=0x42
1700        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}