arcbox_hypervisor/linux/vm/
mod.rs1mod dirty;
4mod drop;
5mod irq;
6#[cfg(test)]
7mod tests;
8mod virtio;
9mod virtual_machine;
10
11use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering};
12use std::sync::{Arc, RwLock};
13
14use crate::{config::VmConfig, error::HypervisorError};
15
16#[cfg(target_arch = "x86_64")]
17use super::ffi::KvmPitConfig;
18use super::ffi::{self, KvmSystem, KvmUserspaceMemoryRegion, KvmVmFd};
19use super::memory::KvmMemory;
20pub use virtio::VirtioDeviceInfo;
21
22static VM_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
24
25#[derive(Debug, Clone)]
27pub(super) struct MemorySlotInfo {
28 slot: u32,
30 guest_phys_addr: u64,
32 size: u64,
34 userspace_addr: u64,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum VmState {
41 Created,
43 Starting,
45 Running,
47 Paused,
49 Stopping,
51 Stopped,
53 Error,
55}
56
57pub struct KvmVm {
61 id: u64,
63 config: VmConfig,
65 #[allow(dead_code)]
67 kvm: Arc<KvmSystem>,
68 vm_fd: KvmVmFd,
70 vcpu_mmap_size: usize,
72 memory: KvmMemory,
74 next_slot: AtomicU32,
76 vcpus: RwLock<Vec<u32>>,
78 state: RwLock<VmState>,
80 running: AtomicBool,
82 virtio_devices: RwLock<Vec<VirtioDeviceInfo>>,
84 next_virtio_irq: AtomicU32,
86 memory_slots: RwLock<Vec<MemorySlotInfo>>,
88 dirty_tracking_enabled: AtomicBool,
90}
91
92unsafe impl Send for KvmVm {}
94unsafe impl Sync for KvmVm {}
95
96impl KvmVm {
97 pub(crate) fn new(
99 kvm: Arc<KvmSystem>,
100 vcpu_mmap_size: usize,
101 config: VmConfig,
102 ) -> Result<Self, HypervisorError> {
103 let id = VM_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
104
105 let vm_fd = kvm.create_vm().map_err(|e| {
107 HypervisorError::VmCreationFailed(format!("Failed to create KVM VM: {}", e))
108 })?;
109
110 #[cfg(target_arch = "x86_64")]
112 Self::setup_x86_vm(&vm_fd)?;
113
114 let memory = KvmMemory::new(config.memory_size)?;
116
117 let region = KvmUserspaceMemoryRegion {
119 slot: 0,
120 flags: 0,
121 guest_phys_addr: 0,
122 memory_size: config.memory_size,
123 userspace_addr: memory.host_address() as u64,
124 };
125
126 vm_fd.set_user_memory_region(®ion).map_err(|e| {
127 HypervisorError::VmCreationFailed(format!("Failed to map guest memory: {}", e))
128 })?;
129
130 let main_slot = MemorySlotInfo {
132 slot: 0,
133 guest_phys_addr: 0,
134 size: config.memory_size,
135 userspace_addr: memory.host_address() as u64,
136 };
137
138 memory.attach_vm_fd(vm_fd.as_raw_fd());
139 memory.register_slot(
140 main_slot.slot,
141 main_slot.guest_phys_addr,
142 main_slot.size,
143 main_slot.userspace_addr,
144 0,
145 )?;
146
147 tracing::info!(
148 "Created KVM VM {}: vcpus={}, memory={}MB",
149 id,
150 config.vcpu_count,
151 config.memory_size / (1024 * 1024)
152 );
153
154 Ok(Self {
155 id,
156 config,
157 kvm,
158 vm_fd,
159 vcpu_mmap_size,
160 memory,
161 next_slot: AtomicU32::new(1), vcpus: RwLock::new(Vec::new()),
163 state: RwLock::new(VmState::Created),
164 running: AtomicBool::new(false),
165 virtio_devices: RwLock::new(Vec::new()),
166 next_virtio_irq: AtomicU32::new(0),
167 memory_slots: RwLock::new(vec![main_slot]),
168 dirty_tracking_enabled: AtomicBool::new(false),
169 })
170 }
171
172 #[cfg(target_arch = "x86_64")]
174 fn setup_x86_vm(vm_fd: &KvmVmFd) -> Result<(), HypervisorError> {
175 const TSS_ADDR: u64 = 0xfffb_d000;
178 vm_fd
179 .set_tss_addr(TSS_ADDR)
180 .map_err(|e| HypervisorError::VmCreationFailed(format!("Failed to set TSS: {}", e)))?;
181
182 const IDENTITY_MAP_ADDR: u64 = 0xfffb_c000;
184 vm_fd
185 .set_identity_map_addr(IDENTITY_MAP_ADDR)
186 .map_err(|e| {
187 HypervisorError::VmCreationFailed(format!("Failed to set identity map: {}", e))
188 })?;
189
190 vm_fd.create_irqchip().map_err(|e| {
192 HypervisorError::VmCreationFailed(format!("Failed to create IRQ chip: {}", e))
193 })?;
194
195 let pit_config = KvmPitConfig::default();
197 vm_fd.create_pit2(&pit_config).map_err(|e| {
198 HypervisorError::VmCreationFailed(format!("Failed to create PIT: {}", e))
199 })?;
200
201 Ok(())
202 }
203
204 #[must_use]
206 pub fn id(&self) -> u64 {
207 self.id
208 }
209
210 #[must_use]
212 pub fn config(&self) -> &VmConfig {
213 &self.config
214 }
215
216 pub fn state(&self) -> VmState {
218 *self.state.read().unwrap()
219 }
220
221 #[must_use]
223 pub fn is_running(&self) -> bool {
224 self.running.load(Ordering::SeqCst)
225 }
226
227 pub(super) fn set_state(&self, new_state: VmState) {
229 let mut state = self.state.write().unwrap();
230 tracing::debug!("VM {} state: {:?} -> {:?}", self.id, *state, new_state);
231 *state = new_state;
232 }
233
234 pub(crate) fn vm_fd(&self) -> &KvmVmFd {
236 &self.vm_fd
237 }
238
239 pub(crate) fn vcpu_mmap_size(&self) -> usize {
241 self.vcpu_mmap_size
242 }
243}