arcbox_hypervisor/linux/vm/
virtual_machine.rs1use std::sync::atomic::Ordering;
2
3use crate::{
4 error::HypervisorError,
5 traits::VirtualMachine,
6 types::{DeviceSnapshot, VirtioDeviceConfig},
7};
8
9use super::virtio::{VIRTIO_MMIO_SIZE, bincode_serialize_device_config};
10use super::{KvmMemory, KvmVm, VirtioDeviceInfo, VmState};
11use crate::linux::KvmVcpu;
12
13impl VirtualMachine for KvmVm {
14 type Vcpu = KvmVcpu;
15 type Memory = KvmMemory;
16
17 fn memory(&self) -> &Self::Memory {
18 &self.memory
19 }
20
21 fn create_vcpu(&mut self, id: u32) -> Result<Self::Vcpu, HypervisorError> {
22 if id >= self.config.vcpu_count {
23 return Err(HypervisorError::VcpuCreationFailed {
24 id,
25 reason: format!(
26 "vCPU ID {} exceeds configured count {}",
27 id, self.config.vcpu_count
28 ),
29 });
30 }
31
32 {
34 let vcpus = self
35 .vcpus
36 .read()
37 .map_err(|_| HypervisorError::VcpuCreationFailed {
38 id,
39 reason: "Lock poisoned".to_string(),
40 })?;
41
42 if vcpus.contains(&id) {
43 return Err(HypervisorError::VcpuCreationFailed {
44 id,
45 reason: "vCPU already created".to_string(),
46 });
47 }
48 }
49
50 let vcpu_fd = self
52 .vm_fd
53 .create_vcpu(id, self.vcpu_mmap_size)
54 .map_err(|e| HypervisorError::VcpuCreationFailed {
55 id,
56 reason: format!("KVM error: {}", e),
57 })?;
58
59 let vcpu = KvmVcpu::new(id, vcpu_fd)?;
61
62 {
64 let mut vcpus =
65 self.vcpus
66 .write()
67 .map_err(|_| HypervisorError::VcpuCreationFailed {
68 id,
69 reason: "Lock poisoned".to_string(),
70 })?;
71 vcpus.push(id);
72 }
73
74 tracing::debug!("Created vCPU {} for VM {}", id, self.id);
75
76 Ok(vcpu)
77 }
78
79 fn add_virtio_device(&mut self, device: VirtioDeviceConfig) -> Result<(), HypervisorError> {
80 let state = self.state();
82 if state != VmState::Created {
83 return Err(HypervisorError::DeviceError(
84 "Cannot add device: VM not in Created state".to_string(),
85 ));
86 }
87
88 let mmio_base = self.allocate_mmio_region()?;
90
91 let gsi = self.allocate_irq();
93
94 let irq_fd = Self::create_eventfd()?;
96
97 if let Err(e) = self.register_irqfd(irq_fd, gsi, None) {
98 unsafe { libc::close(irq_fd) };
100 return Err(e);
101 }
102
103 let notify_fd = match self.setup_ioeventfd(mmio_base) {
105 Ok(fd) => fd,
106 Err(e) => {
107 let _ = self.unregister_irqfd(irq_fd, gsi);
109 unsafe { libc::close(irq_fd) };
110 return Err(e);
111 }
112 };
113
114 let device_info = VirtioDeviceInfo {
116 device_type: device.device_type.clone(),
117 mmio_base,
118 mmio_size: VIRTIO_MMIO_SIZE,
119 irq: gsi,
120 irq_fd,
121 notify_fd,
122 };
123
124 {
125 let mut devices = self.virtio_devices.write().map_err(|_| {
126 let _ = self.unregister_irqfd(irq_fd, gsi);
128 unsafe {
129 libc::close(irq_fd);
130 libc::close(notify_fd);
131 }
132 HypervisorError::DeviceError("Lock poisoned".to_string())
133 })?;
134
135 devices.push(device_info);
136 }
137
138 tracing::info!(
139 "Added {:?} device to VM {}: MMIO={:#x}-{:#x}, IRQ={}, irq_fd={}, notify_fd={}",
140 device.device_type,
141 self.id,
142 mmio_base,
143 mmio_base + VIRTIO_MMIO_SIZE,
144 gsi,
145 irq_fd,
146 notify_fd
147 );
148
149 Ok(())
150 }
151
152 fn start(&mut self) -> Result<(), HypervisorError> {
153 let state = self.state();
154 if state != VmState::Created && state != VmState::Stopped {
155 return Err(HypervisorError::VmStateError {
156 expected: "Created or Stopped".to_string(),
157 actual: format!("{:?}", state),
158 });
159 }
160
161 self.set_state(VmState::Starting);
162
163 self.running.store(true, Ordering::SeqCst);
165 self.set_state(VmState::Running);
166
167 tracing::info!("Started VM {}", self.id);
168
169 Ok(())
170 }
171
172 fn pause(&mut self) -> Result<(), HypervisorError> {
173 let state = self.state();
174 if state != VmState::Running {
175 return Err(HypervisorError::VmStateError {
176 expected: "Running".to_string(),
177 actual: format!("{:?}", state),
178 });
179 }
180
181 self.set_state(VmState::Paused);
186
187 tracing::info!("Paused VM {}", self.id);
188
189 Ok(())
190 }
191
192 fn resume(&mut self) -> Result<(), HypervisorError> {
193 let state = self.state();
194 if state != VmState::Paused {
195 return Err(HypervisorError::VmStateError {
196 expected: "Paused".to_string(),
197 actual: format!("{:?}", state),
198 });
199 }
200
201 self.set_state(VmState::Running);
202
203 tracing::info!("Resumed VM {}", self.id);
204
205 Ok(())
206 }
207
208 fn stop(&mut self) -> Result<(), HypervisorError> {
209 let state = self.state();
210 if state != VmState::Running && state != VmState::Paused {
211 return Err(HypervisorError::VmStateError {
212 expected: "Running or Paused".to_string(),
213 actual: format!("{:?}", state),
214 });
215 }
216
217 self.set_state(VmState::Stopping);
218
219 self.running.store(false, Ordering::SeqCst);
221
222 self.set_state(VmState::Stopped);
223
224 tracing::info!("Stopped VM {}", self.id);
225
226 Ok(())
227 }
228
229 fn as_any(&self) -> &dyn std::any::Any {
230 self
231 }
232
233 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
234 self
235 }
236
237 fn vcpu_count(&self) -> u32 {
238 self.config.vcpu_count
239 }
240
241 fn snapshot_devices(&self) -> Result<Vec<DeviceSnapshot>, HypervisorError> {
242 let devices = self
243 .virtio_devices
244 .read()
245 .map_err(|_| HypervisorError::SnapshotError("Lock poisoned".to_string()))?;
246
247 let mut snapshots = Vec::with_capacity(devices.len());
248
249 for device in devices.iter() {
250 let state_bytes = bincode_serialize_device_config(device);
255
256 snapshots.push(DeviceSnapshot {
257 device_type: device.device_type.clone(),
258 name: format!("{:?}-{}", device.device_type, snapshots.len()),
259 state: state_bytes,
260 });
261 }
262
263 tracing::debug!(
264 "snapshot_devices: captured {} device configurations",
265 snapshots.len()
266 );
267
268 Ok(snapshots)
269 }
270
271 fn restore_devices(&mut self, snapshots: &[DeviceSnapshot]) -> Result<(), HypervisorError> {
272 let devices = self
279 .virtio_devices
280 .read()
281 .map_err(|_| HypervisorError::SnapshotError("Lock poisoned".to_string()))?;
282
283 if snapshots.len() != devices.len() {
284 return Err(HypervisorError::SnapshotError(format!(
285 "Device count mismatch: snapshot has {}, VM has {}",
286 snapshots.len(),
287 devices.len()
288 )));
289 }
290
291 for (snapshot, device) in snapshots.iter().zip(devices.iter()) {
292 if snapshot.device_type != device.device_type {
293 return Err(HypervisorError::SnapshotError(format!(
294 "Device type mismatch: snapshot has {:?}, VM has {:?}",
295 snapshot.device_type, device.device_type
296 )));
297 }
298 }
299
300 tracing::debug!(
301 "restore_devices: verified {} device configurations",
302 snapshots.len()
303 );
304
305 Ok(())
306 }
307}