1use std::sync::Arc;
4use std::sync::atomic::{AtomicBool, Ordering};
5
6use crate::{
7 error::HypervisorError,
8 traits::Vcpu,
9 types::{CpuArch, Registers, VcpuExit, VcpuSnapshot},
10};
11
12use super::ffi::{
13 KVM_EXIT_DEBUG, KVM_EXIT_FAIL_ENTRY, KVM_EXIT_HLT, KVM_EXIT_INTERNAL_ERROR, KVM_EXIT_IO,
14 KVM_EXIT_IO_IN, KVM_EXIT_IO_OUT, KVM_EXIT_MMIO, KVM_EXIT_SHUTDOWN, KVM_EXIT_SYSTEM_EVENT,
15 KvmVcpuFd,
16};
17
18#[cfg(target_arch = "x86_64")]
19use super::ffi::{KvmRegs, KvmSegment, KvmSregs};
20
21pub struct KvmVcpu {
27 id: u32,
29 vcpu_fd: KvmVcpuFd,
31 running: Arc<AtomicBool>,
33}
34
35impl KvmVcpu {
36 pub(crate) fn new(id: u32, vcpu_fd: KvmVcpuFd) -> Result<Self, HypervisorError> {
38 let vcpu = Self {
39 id,
40 vcpu_fd,
41 running: Arc::new(AtomicBool::new(false)),
42 };
43
44 #[cfg(target_arch = "x86_64")]
46 vcpu.init_x86()?;
47
48 #[cfg(target_arch = "aarch64")]
49 vcpu.init_arm64()?;
50
51 Ok(vcpu)
52 }
53
54 #[cfg(target_arch = "x86_64")]
56 fn init_x86(&self) -> Result<(), HypervisorError> {
57 let mut sregs =
59 self.vcpu_fd
60 .get_sregs()
61 .map_err(|e| HypervisorError::VcpuCreationFailed {
62 id: self.id,
63 reason: format!("Failed to get sregs: {}", e),
64 })?;
65
66 sregs.cs = KvmSegment {
68 base: 0,
69 limit: 0xffff,
70 selector: 0,
71 type_: 0xb, present: 1,
73 dpl: 0,
74 db: 0,
75 s: 1,
76 l: 0,
77 g: 0,
78 avl: 0,
79 unusable: 0,
80 padding: 0,
81 };
82
83 sregs.ds = KvmSegment {
85 base: 0,
86 limit: 0xffff,
87 selector: 0,
88 type_: 0x3, present: 1,
90 dpl: 0,
91 db: 0,
92 s: 1,
93 l: 0,
94 g: 0,
95 avl: 0,
96 unusable: 0,
97 padding: 0,
98 };
99
100 sregs.es = sregs.ds.clone();
101 sregs.fs = sregs.ds.clone();
102 sregs.gs = sregs.ds.clone();
103 sregs.ss = sregs.ds.clone();
104
105 sregs.cr0 = 0x6000_0010; self.vcpu_fd
109 .set_sregs(&sregs)
110 .map_err(|e| HypervisorError::VcpuCreationFailed {
111 id: self.id,
112 reason: format!("Failed to set sregs: {}", e),
113 })?;
114
115 Ok(())
116 }
117
118 #[cfg(target_arch = "aarch64")]
120 fn init_arm64(&self) -> Result<(), HypervisorError> {
121 Ok(())
129 }
130
131 #[must_use]
133 pub fn is_running(&self) -> bool {
134 self.running.load(Ordering::SeqCst)
135 }
136
137 #[must_use]
139 pub fn running_flag(&self) -> Arc<AtomicBool> {
140 Arc::clone(&self.running)
141 }
142
143 pub fn signal_exit(&self) {
147 self.vcpu_fd.set_immediate_exit(true);
148 }
149
150 #[cfg(target_arch = "x86_64")]
152 pub fn setup_linux_boot(
153 &self,
154 entry_point: u64,
155 boot_params_addr: u64,
156 ) -> Result<(), HypervisorError> {
157 let mut sregs = self
159 .vcpu_fd
160 .get_sregs()
161 .map_err(|e| HypervisorError::VcpuRunError(format!("Failed to get sregs: {}", e)))?;
162
163 sregs.cr0 = 0x6000_0011; sregs.cr3 = 0;
167 sregs.cr4 = 0;
168
169 sregs.cs = KvmSegment {
172 base: 0,
173 limit: 0xffff_ffff,
174 selector: 0x10,
175 type_: 0xb, present: 1,
177 dpl: 0,
178 db: 1, s: 1,
180 l: 0,
181 g: 1, avl: 0,
183 unusable: 0,
184 padding: 0,
185 };
186
187 sregs.ds = KvmSegment {
189 base: 0,
190 limit: 0xffff_ffff,
191 selector: 0x18,
192 type_: 0x3, present: 1,
194 dpl: 0,
195 db: 1,
196 s: 1,
197 l: 0,
198 g: 1,
199 avl: 0,
200 unusable: 0,
201 padding: 0,
202 };
203
204 sregs.es = sregs.ds.clone();
205 sregs.fs = sregs.ds.clone();
206 sregs.gs = sregs.ds.clone();
207 sregs.ss = sregs.ds.clone();
208
209 self.vcpu_fd
210 .set_sregs(&sregs)
211 .map_err(|e| HypervisorError::VcpuRunError(format!("Failed to set sregs: {}", e)))?;
212
213 let regs = KvmRegs {
215 rip: entry_point,
216 rsi: boot_params_addr, rflags: 0x2, ..Default::default()
219 };
220
221 self.vcpu_fd
222 .set_regs(®s)
223 .map_err(|e| HypervisorError::VcpuRunError(format!("Failed to set regs: {}", e)))?;
224
225 tracing::debug!(
226 "vCPU {} setup for Linux boot: entry={:#x}, boot_params={:#x}",
227 self.id,
228 entry_point,
229 boot_params_addr
230 );
231
232 Ok(())
233 }
234
235 #[cfg(target_arch = "aarch64")]
237 pub fn setup_linux_boot(&self, entry_point: u64, dtb_addr: u64) -> Result<(), HypervisorError> {
238 use super::ffi::arm64_regs;
239
240 self.vcpu_fd
248 .set_one_reg(arm64_regs::X0, dtb_addr)
249 .map_err(|e| HypervisorError::VcpuRunError(format!("Failed to set x0: {}", e)))?;
250
251 self.vcpu_fd
253 .set_one_reg(arm64_regs::PC, entry_point)
254 .map_err(|e| HypervisorError::VcpuRunError(format!("Failed to set PC: {}", e)))?;
255
256 let pstate = arm64_regs::PSTATE_EL1H
258 | arm64_regs::PSTATE_D
259 | arm64_regs::PSTATE_A
260 | arm64_regs::PSTATE_I
261 | arm64_regs::PSTATE_F;
262 self.vcpu_fd
263 .set_one_reg(arm64_regs::PSTATE, pstate)
264 .map_err(|e| HypervisorError::VcpuRunError(format!("Failed to set PSTATE: {}", e)))?;
265
266 self.vcpu_fd.set_one_reg(arm64_regs::X1, 0).ok(); self.vcpu_fd.set_one_reg(arm64_regs::X2, 0).ok();
269 self.vcpu_fd.set_one_reg(arm64_regs::X3, 0).ok();
270 self.vcpu_fd.set_one_reg(arm64_regs::SP, 0).ok();
271
272 tracing::debug!(
273 "vCPU {} setup for Linux boot: entry={:#x}, dtb={:#x}, pstate={:#x}",
274 self.id,
275 entry_point,
276 dtb_addr,
277 pstate
278 );
279
280 Ok(())
281 }
282
283 fn convert_exit(&self) -> VcpuExit {
285 let exit_reason = self.vcpu_fd.exit_reason();
286
287 match exit_reason {
288 KVM_EXIT_HLT => VcpuExit::Halt,
289
290 KVM_EXIT_IO => {
291 let io = unsafe { (*self.vcpu_fd.kvm_run()).exit_data.io };
292 if io.direction == KVM_EXIT_IO_OUT {
293 let data_ptr = unsafe {
295 (self.vcpu_fd.kvm_run() as *const _ as *const u8)
296 .add(io.data_offset as usize)
297 };
298 let data = match io.size {
302 1 => (unsafe { *data_ptr }) as u64,
303 2 => (unsafe { std::ptr::read_unaligned(data_ptr as *const u16) }) as u64,
304 4 => (unsafe { std::ptr::read_unaligned(data_ptr as *const u32) }) as u64,
305 _ => 0,
306 };
307 VcpuExit::IoOut {
308 port: io.port,
309 size: io.size,
310 data,
311 }
312 } else {
313 VcpuExit::IoIn {
314 port: io.port,
315 size: io.size,
316 }
317 }
318 }
319
320 KVM_EXIT_MMIO => {
321 let mmio = unsafe { (*self.vcpu_fd.kvm_run()).exit_data.mmio };
322 if mmio.is_write != 0 {
323 let data = match mmio.len {
324 1 => mmio.data[0] as u64,
325 2 => u16::from_le_bytes([mmio.data[0], mmio.data[1]]) as u64,
326 4 => u32::from_le_bytes([
327 mmio.data[0],
328 mmio.data[1],
329 mmio.data[2],
330 mmio.data[3],
331 ]) as u64,
332 8 => u64::from_le_bytes([
333 mmio.data[0],
334 mmio.data[1],
335 mmio.data[2],
336 mmio.data[3],
337 mmio.data[4],
338 mmio.data[5],
339 mmio.data[6],
340 mmio.data[7],
341 ]),
342 _ => 0,
343 };
344 VcpuExit::MmioWrite {
345 addr: mmio.phys_addr,
346 size: mmio.len as u8,
347 data,
348 }
349 } else {
350 VcpuExit::MmioRead {
351 addr: mmio.phys_addr,
352 size: mmio.len as u8,
353 }
354 }
355 }
356
357 KVM_EXIT_SHUTDOWN => VcpuExit::Shutdown,
358
359 KVM_EXIT_DEBUG => VcpuExit::Debug,
360
361 KVM_EXIT_SYSTEM_EVENT => {
362 let event = unsafe { (*self.vcpu_fd.kvm_run()).exit_data.system_event };
363 match event.type_ {
364 1 => VcpuExit::Shutdown, 2 => VcpuExit::SystemReset, _ => VcpuExit::Unknown(exit_reason as i32),
367 }
368 }
369
370 KVM_EXIT_FAIL_ENTRY | KVM_EXIT_INTERNAL_ERROR => {
371 tracing::error!(
372 "vCPU {} internal error: exit_reason={}",
373 self.id,
374 exit_reason
375 );
376 VcpuExit::Unknown(exit_reason as i32)
377 }
378
379 _ => VcpuExit::Unknown(exit_reason as i32),
380 }
381 }
382
383 pub fn set_io_in_data(&self, data: &[u8]) {
385 unsafe {
386 let kvm_run = self.vcpu_fd.kvm_run_mut();
387 let io = kvm_run.exit_data.io;
388 let data_ptr = (kvm_run as *mut _ as *mut u8).add(io.data_offset as usize);
389 std::ptr::copy_nonoverlapping(data.as_ptr(), data_ptr, data.len());
390 }
391 }
392
393 pub fn set_mmio_read_data(&self, data: &[u8]) {
395 unsafe {
396 let kvm_run = self.vcpu_fd.kvm_run_mut();
397 let mmio = &mut kvm_run.exit_data.mmio;
398 let len = std::cmp::min(data.len(), mmio.data.len());
399 mmio.data[..len].copy_from_slice(&data[..len]);
400 }
401 }
402}
403
404impl Vcpu for KvmVcpu {
405 fn run(&mut self) -> Result<VcpuExit, HypervisorError> {
406 self.running.store(true, Ordering::SeqCst);
407
408 self.vcpu_fd.set_immediate_exit(false);
410
411 let result = self.vcpu_fd.run();
413
414 self.running.store(false, Ordering::SeqCst);
415
416 match result {
417 Ok(()) => Ok(self.convert_exit()),
418 Err(e) => Err(HypervisorError::VcpuRunError(format!(
419 "vCPU {} run failed: {}",
420 self.id, e
421 ))),
422 }
423 }
424
425 fn get_regs(&self) -> Result<Registers, HypervisorError> {
426 let kvm_regs = self.vcpu_fd.get_regs().map_err(|e| {
427 HypervisorError::VcpuRunError(format!("Failed to get registers: {}", e))
428 })?;
429
430 #[cfg(target_arch = "x86_64")]
431 {
432 Ok(Registers {
433 rax: kvm_regs.rax,
434 rbx: kvm_regs.rbx,
435 rcx: kvm_regs.rcx,
436 rdx: kvm_regs.rdx,
437 rsi: kvm_regs.rsi,
438 rdi: kvm_regs.rdi,
439 rsp: kvm_regs.rsp,
440 rbp: kvm_regs.rbp,
441 r8: kvm_regs.r8,
442 r9: kvm_regs.r9,
443 r10: kvm_regs.r10,
444 r11: kvm_regs.r11,
445 r12: kvm_regs.r12,
446 r13: kvm_regs.r13,
447 r14: kvm_regs.r14,
448 r15: kvm_regs.r15,
449 rip: kvm_regs.rip,
450 rflags: kvm_regs.rflags,
451 })
452 }
453
454 #[cfg(target_arch = "aarch64")]
455 {
456 Ok(Registers {
459 rax: kvm_regs.regs[0],
460 rbx: kvm_regs.regs[1],
461 rcx: kvm_regs.regs[2],
462 rdx: kvm_regs.regs[3],
463 rsi: kvm_regs.regs[4],
464 rdi: kvm_regs.regs[5],
465 rsp: kvm_regs.sp,
466 rbp: kvm_regs.regs[29],
467 r8: kvm_regs.regs[8],
468 r9: kvm_regs.regs[9],
469 r10: kvm_regs.regs[10],
470 r11: kvm_regs.regs[11],
471 r12: kvm_regs.regs[12],
472 r13: kvm_regs.regs[13],
473 r14: kvm_regs.regs[14],
474 r15: kvm_regs.regs[15],
475 rip: kvm_regs.pc,
476 rflags: kvm_regs.pstate,
477 })
478 }
479 }
480
481 fn set_regs(&mut self, regs: &Registers) -> Result<(), HypervisorError> {
482 #[cfg(target_arch = "x86_64")]
483 {
484 let kvm_regs = KvmRegs {
485 rax: regs.rax,
486 rbx: regs.rbx,
487 rcx: regs.rcx,
488 rdx: regs.rdx,
489 rsi: regs.rsi,
490 rdi: regs.rdi,
491 rsp: regs.rsp,
492 rbp: regs.rbp,
493 r8: regs.r8,
494 r9: regs.r9,
495 r10: regs.r10,
496 r11: regs.r11,
497 r12: regs.r12,
498 r13: regs.r13,
499 r14: regs.r14,
500 r15: regs.r15,
501 rip: regs.rip,
502 rflags: regs.rflags,
503 };
504
505 self.vcpu_fd.set_regs(&kvm_regs).map_err(|e| {
506 HypervisorError::VcpuRunError(format!("Failed to set registers: {}", e))
507 })?;
508 }
509
510 #[cfg(target_arch = "aarch64")]
511 {
512 let _ = regs; return Err(HypervisorError::VcpuRunError(
516 "ARM64 register setting not fully implemented".to_string(),
517 ));
518 }
519
520 Ok(())
521 }
522
523 fn id(&self) -> u32 {
524 self.id
525 }
526
527 fn set_io_result(&mut self, value: u64) -> Result<(), HypervisorError> {
528 let bytes = value.to_le_bytes();
530 unsafe {
531 let kvm_run = self.vcpu_fd.kvm_run_mut();
532 let io = kvm_run.exit_data.io;
533 let size = io.size as usize;
534 let data_ptr = (kvm_run as *mut _ as *mut u8).add(io.data_offset as usize);
535 std::ptr::copy_nonoverlapping(bytes.as_ptr(), data_ptr, size.min(8));
536 }
537 Ok(())
538 }
539
540 fn set_mmio_result(&mut self, value: u64) -> Result<(), HypervisorError> {
541 let bytes = value.to_le_bytes();
543 unsafe {
544 let kvm_run = self.vcpu_fd.kvm_run_mut();
545 let mmio = &mut kvm_run.exit_data.mmio;
546 let len = (mmio.len as usize).min(8);
547 mmio.data[..len].copy_from_slice(&bytes[..len]);
548 }
549 Ok(())
550 }
551
552 fn snapshot(&self) -> Result<VcpuSnapshot, HypervisorError> {
553 #[cfg(target_arch = "x86_64")]
554 {
555 let regs = self.get_regs()?;
556 Ok(VcpuSnapshot::new_x86(self.id, regs))
557 }
558
559 #[cfg(target_arch = "aarch64")]
560 {
561 use super::ffi::arm64_regs;
562
563 let mut arm_regs = crate::types::Arm64Registers::default();
565
566 for i in 0..31 {
568 let reg_id = arm64_regs::X0 + (i as u64) * 2; if let Ok(val) = self.vcpu_fd.get_one_reg(reg_id) {
570 arm_regs.x[i] = val;
571 }
572 }
573
574 arm_regs.sp = self.vcpu_fd.get_one_reg(arm64_regs::SP).unwrap_or(0);
576 arm_regs.pc = self.vcpu_fd.get_one_reg(arm64_regs::PC).unwrap_or(0);
577 arm_regs.pstate = self.vcpu_fd.get_one_reg(arm64_regs::PSTATE).unwrap_or(0);
578
579 Ok(VcpuSnapshot::new_arm64(self.id, arm_regs))
582 }
583 }
584
585 fn restore(&mut self, snapshot: &VcpuSnapshot) -> Result<(), HypervisorError> {
586 if snapshot.id != self.id {
587 return Err(HypervisorError::SnapshotError(format!(
588 "vCPU ID mismatch: expected {}, got {}",
589 self.id, snapshot.id
590 )));
591 }
592
593 #[cfg(target_arch = "x86_64")]
594 {
595 if let Some(regs) = &snapshot.x86_regs {
596 self.set_regs(regs)?;
597 }
598 }
599
600 #[cfg(target_arch = "aarch64")]
601 {
602 use super::ffi::arm64_regs;
603
604 if let Some(arm_regs) = &snapshot.arm64_regs {
605 for i in 0..31 {
607 let reg_id = arm64_regs::X0 + (i as u64) * 2;
608 let _ = self.vcpu_fd.set_one_reg(reg_id, arm_regs.x[i]);
609 }
610
611 let _ = self.vcpu_fd.set_one_reg(arm64_regs::SP, arm_regs.sp);
613 let _ = self.vcpu_fd.set_one_reg(arm64_regs::PC, arm_regs.pc);
614 let _ = self
615 .vcpu_fd
616 .set_one_reg(arm64_regs::PSTATE, arm_regs.pstate);
617 }
618 }
619
620 Ok(())
621 }
622}
623
624#[cfg(target_arch = "x86_64")]
626#[derive(Debug, Clone, Default)]
627pub struct SpecialRegisters {
628 pub cs: SegmentRegister,
630 pub ds: SegmentRegister,
632 pub ss: SegmentRegister,
634 pub es: SegmentRegister,
636 pub fs: SegmentRegister,
638 pub gs: SegmentRegister,
640 pub gdt: DescriptorTable,
642 pub idt: DescriptorTable,
644 pub cr0: u64,
646 pub cr3: u64,
648 pub cr4: u64,
650 pub efer: u64,
652}
653
654#[cfg(target_arch = "x86_64")]
656#[derive(Debug, Clone, Default)]
657pub struct SegmentRegister {
658 pub base: u64,
660 pub limit: u32,
662 pub selector: u16,
664 pub type_: u8,
666 pub present: u8,
668 pub dpl: u8,
670 pub db: u8,
672 pub granularity: u8,
674 pub long_mode: u8,
676}
677
678#[cfg(target_arch = "x86_64")]
680#[derive(Debug, Clone, Default)]
681pub struct DescriptorTable {
682 pub base: u64,
684 pub limit: u16,
686}
687
688#[cfg(test)]
689mod tests {
690 use super::*;
691
692 #[test]
693 fn test_vcpu_running_flag() {
694 let running = Arc::new(AtomicBool::new(false));
696 assert!(!running.load(Ordering::SeqCst));
697 running.store(true, Ordering::SeqCst);
698 assert!(running.load(Ordering::SeqCst));
699 }
700}