1#[cfg(target_arch = "aarch64")]
6mod aarch64;
7#[cfg(target_arch = "riscv64")]
8mod riscv64;
9#[cfg(target_arch = "x86_64")]
10mod x86_64;
11
12mod cap;
13
14use std::cmp::Reverse;
15use std::collections::BTreeMap;
16use std::collections::BinaryHeap;
17use std::convert::TryFrom;
18use std::ffi::CString;
19use std::fs::File;
20use std::os::raw::c_ulong;
21use std::os::raw::c_void;
22use std::os::unix::prelude::OsStrExt;
23use std::path::Path;
24use std::sync::Arc;
25use std::sync::OnceLock;
26
27#[cfg(target_arch = "aarch64")]
28pub use aarch64::*;
29use base::errno_result;
30use base::error;
31use base::ioctl;
32use base::ioctl_with_mut_ref;
33use base::ioctl_with_ref;
34use base::ioctl_with_val;
35use base::pagesize;
36use base::warn;
37use base::AsRawDescriptor;
38use base::Error;
39use base::Event;
40use base::FromRawDescriptor;
41use base::MappedRegion;
42use base::MemoryMapping;
43use base::MemoryMappingBuilder;
44use base::MmapError;
45use base::Protection;
46use base::RawDescriptor;
47use base::Result;
48use base::SafeDescriptor;
49pub use cap::KvmCap;
50use cfg_if::cfg_if;
51use kvm_sys::*;
52use libc::open64;
53use libc::EFAULT;
54use libc::EINVAL;
55use libc::EIO;
56use libc::ENOENT;
57use libc::ENOSPC;
58use libc::ENOSYS;
59#[cfg(not(target_arch = "aarch64"))]
60use libc::ENOTSUP;
61use libc::EOVERFLOW;
62use libc::O_CLOEXEC;
63use libc::O_RDWR;
64#[cfg(target_arch = "riscv64")]
65use riscv64::*;
66use sync::Mutex;
67use vm_memory::GuestAddress;
68use vm_memory::GuestMemory;
69#[cfg(target_arch = "x86_64")]
70pub use x86_64::*;
71use zerocopy::FromZeros;
72
73use crate::BalloonEvent;
74use crate::ClockState;
75use crate::Config;
76use crate::Datamatch;
77use crate::DeviceKind;
78use crate::HypercallAbi;
79use crate::Hypervisor;
80use crate::HypervisorCap;
81use crate::HypervisorKind;
82use crate::IoEventAddress;
83use crate::IoOperation;
84use crate::IoParams;
85use crate::IrqRoute;
86use crate::IrqSource;
87use crate::MPState;
88use crate::MemCacheType;
89use crate::MemSlot;
90use crate::Vcpu;
91use crate::VcpuExit;
92use crate::VcpuSignalHandle;
93use crate::VcpuSignalHandleInner;
94use crate::Vm;
95use crate::VmCap;
96
97unsafe fn set_user_memory_region(
103 kvm: &KvmVm,
104 slot: MemSlot,
105 read_only: bool,
106 log_dirty_pages: bool,
107 cache: MemCacheType,
108 guest_addr: u64,
109 memory_size: u64,
110 userspace_addr: *mut u8,
111) -> Result<()> {
112 let mut use_2_variant = false;
113 let mut flags = 0;
114 if read_only {
115 flags |= KVM_MEM_READONLY;
116 }
117 if log_dirty_pages {
118 flags |= KVM_MEM_LOG_DIRTY_PAGES;
119 }
120
121 if kvm.caps.user_noncoherent_dma_or_another_conflict_cap
136 && cache == MemCacheType::CacheNonCoherent
137 {
138 flags |= KVM_MEM_NON_COHERENT_DMA;
139 use_2_variant = kvm.caps.user_memory_region2;
140 }
141
142 let untagged_userspace_addr = untagged_addr(userspace_addr as usize);
143 let mut ret = if use_2_variant {
144 let region2 = kvm_userspace_memory_region2 {
145 slot,
146 flags,
147 guest_phys_addr: guest_addr,
148 memory_size,
149 userspace_addr: untagged_userspace_addr as u64,
150 guest_memfd_offset: 0,
151 guest_memfd: 0,
152 ..Default::default()
153 };
154 ioctl_with_ref(&kvm.vm, KVM_SET_USER_MEMORY_REGION2, ®ion2)
155 } else {
156 let region = kvm_userspace_memory_region {
157 slot,
158 flags,
159 guest_phys_addr: guest_addr,
160 memory_size,
161 userspace_addr: (untagged_userspace_addr as u64),
162 };
163 ioctl_with_ref(&kvm.vm, KVM_SET_USER_MEMORY_REGION, ®ion)
164 };
165
166 if ret != 0 && (flags & KVM_MEM_NON_COHERENT_DMA != 0) && Error::last().errno() == EINVAL {
168 let fallback_flags = flags & !KVM_MEM_NON_COHERENT_DMA;
169 warn!(
170 "KVM_MEM_NON_COHERENT_DMA rejected by host kernel, retrying without flag (flags={:#x})",
171 fallback_flags
172 );
173 ret = if use_2_variant {
174 let region2 = kvm_userspace_memory_region2 {
175 slot,
176 flags: fallback_flags,
177 guest_phys_addr: guest_addr,
178 memory_size,
179 userspace_addr: untagged_userspace_addr as u64,
180 guest_memfd_offset: 0,
181 guest_memfd: 0,
182 ..Default::default()
183 };
184 ioctl_with_ref(&kvm.vm, KVM_SET_USER_MEMORY_REGION2, ®ion2)
185 } else {
186 let region = kvm_userspace_memory_region {
187 slot,
188 flags: fallback_flags,
189 guest_phys_addr: guest_addr,
190 memory_size,
191 userspace_addr: (untagged_userspace_addr as u64),
192 };
193 ioctl_with_ref(&kvm.vm, KVM_SET_USER_MEMORY_REGION, ®ion)
194 };
195 }
196
197 if ret == 0 {
198 Ok(())
199 } else {
200 errno_result()
201 }
202}
203
204#[inline]
208fn untagged_addr(addr: usize) -> usize {
209 let tag_bits_mask: u64 = if cfg!(target_arch = "aarch64") {
210 0xFF00000000000000
211 } else {
212 0
213 };
214 addr & !tag_bits_mask as usize
215}
216
217pub fn dirty_log_bitmap_size(size: usize) -> usize {
224 let page_size = pagesize();
225 size.div_ceil(page_size).div_ceil(8)
226}
227
228pub struct Kvm {
229 kvm: SafeDescriptor,
230 vcpu_mmap_size: usize,
231}
232
233impl Kvm {
234 pub fn new_with_path(device_path: &Path) -> Result<Kvm> {
235 let c_path = CString::new(device_path.as_os_str().as_bytes()).unwrap();
236 let ret = unsafe { open64(c_path.as_ptr(), O_RDWR | O_CLOEXEC) };
239 if ret < 0 {
240 return errno_result();
241 }
242 let kvm = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
245
246 let version = unsafe { ioctl(&kvm, KVM_GET_API_VERSION) };
249 if version < 0 {
250 return errno_result();
251 }
252
253 if version as u32 != KVM_API_VERSION {
256 error!(
257 "KVM_GET_API_VERSION: expected {}, got {}",
258 KVM_API_VERSION, version,
259 );
260 return Err(Error::new(ENOSYS));
261 }
262
263 let res = unsafe { ioctl(&kvm, KVM_GET_VCPU_MMAP_SIZE) };
266 if res <= 0 {
267 return errno_result();
268 }
269 let vcpu_mmap_size = res as usize;
270
271 Ok(Kvm {
272 kvm,
273 vcpu_mmap_size,
274 })
275 }
276
277 pub fn new() -> Result<Kvm> {
279 Kvm::new_with_path(Path::new("/dev/kvm"))
280 }
281}
282
283impl AsRawDescriptor for Kvm {
284 fn as_raw_descriptor(&self) -> RawDescriptor {
285 self.kvm.as_raw_descriptor()
286 }
287}
288
289impl Hypervisor for Kvm {
290 fn try_clone(&self) -> Result<Self> {
291 Ok(Kvm {
292 kvm: self.kvm.try_clone()?,
293 vcpu_mmap_size: self.vcpu_mmap_size,
294 })
295 }
296
297 fn check_capability(&self, cap: HypervisorCap) -> bool {
298 if let Ok(kvm_cap) = KvmCap::try_from(cap) {
299 unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, kvm_cap as c_ulong) == 1 }
303 } else {
304 false
306 }
307 }
308}
309
310#[derive(Clone, Default)]
312struct KvmVmCaps {
313 kvmclock_ctrl: bool,
314 user_noncoherent_dma_or_another_conflict_cap: bool,
315 user_memory_region2: bool,
316 msi_devid: Arc<OnceLock<bool>>,
319}
320
321pub struct KvmVm {
323 kvm: Kvm,
324 vm: SafeDescriptor,
325 guest_mem: GuestMemory,
326 mem_regions: Mutex<BTreeMap<MemSlot, Box<dyn MappedRegion>>>,
327 mem_slot_gaps: Mutex<BinaryHeap<Reverse<MemSlot>>>,
329 caps: KvmVmCaps,
330 force_disable_readonly_mem: bool,
331}
332
333impl KvmVm {
334 pub fn new(kvm: &Kvm, guest_mem: GuestMemory, cfg: Config) -> Result<KvmVm> {
336 let ret = unsafe {
340 ioctl_with_val(
341 kvm,
342 KVM_CREATE_VM,
343 kvm.get_vm_type(cfg.protection_type)? as c_ulong,
344 )
345 };
346 if ret < 0 {
347 return errno_result();
348 }
349 let vm_descriptor = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
352 let mut vm = KvmVm {
353 kvm: kvm.try_clone()?,
354 vm: vm_descriptor,
355 guest_mem,
356 mem_regions: Default::default(),
357 mem_slot_gaps: Default::default(),
358 caps: Default::default(),
359 force_disable_readonly_mem: cfg.force_disable_readonly_mem,
360 };
361 vm.caps.kvmclock_ctrl = vm.check_raw_capability(KvmCap::KvmclockCtrl);
362 vm.caps.user_noncoherent_dma_or_another_conflict_cap = vm
367 .check_raw_capability(KvmCap::MemNoncoherentDmaOrPreFaultMemory)
368 || vm.check_raw_capability(KvmCap::MemNoncoherentDmaOrArmWritableImpIdRegs);
369 vm.caps.user_memory_region2 = vm.check_raw_capability(KvmCap::UserMemory2);
370
371 vm.init_arch(&cfg)?;
372
373 for region in vm.guest_mem.regions() {
374 unsafe {
377 set_user_memory_region(
378 &vm,
379 region.index as MemSlot,
380 false,
381 false,
382 MemCacheType::CacheCoherent,
383 region.guest_addr.offset(),
384 region.size as u64,
385 region.host_addr as *mut u8,
386 )
387 }?;
388 }
389
390 Ok(vm)
391 }
392
393 pub fn create_kvm_vcpu(&self, id: usize) -> Result<KvmVcpu> {
394 let fd = unsafe { ioctl_with_val(self, KVM_CREATE_VCPU, c_ulong::try_from(id).unwrap()) };
397 if fd < 0 {
398 return errno_result();
399 }
400
401 let vcpu = unsafe { File::from_raw_descriptor(fd) };
405
406 let run_mmap = MemoryMappingBuilder::new(self.kvm.vcpu_mmap_size)
411 .from_file(&vcpu)
412 .build()
413 .map_err(|_| Error::new(ENOSPC))?;
414
415 Ok(KvmVcpu {
416 #[cfg(target_arch = "x86_64")]
417 kvm: self.kvm.try_clone()?,
418 #[cfg(not(target_arch = "riscv64"))]
419 vm: self.vm.try_clone()?,
420 vcpu,
421 id,
422 cap_kvmclock_ctrl: self.caps.kvmclock_ctrl,
423 run_mmap: Arc::new(run_mmap),
424 })
425 }
426
427 pub fn create_irq_chip(&self) -> Result<()> {
431 let ret = unsafe { ioctl(self, KVM_CREATE_IRQCHIP) };
434 if ret == 0 {
435 Ok(())
436 } else {
437 errno_result()
438 }
439 }
440
441 pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> {
443 let mut irq_level = kvm_irq_level::default();
444 irq_level.__bindgen_anon_1.irq = irq;
445 irq_level.level = active.into();
446
447 let ret = unsafe { ioctl_with_ref(self, KVM_IRQ_LINE, &irq_level) };
451 if ret == 0 {
452 Ok(())
453 } else {
454 errno_result()
455 }
456 }
457
458 pub fn register_irqfd(
461 &self,
462 gsi: u32,
463 evt: &Event,
464 resample_evt: Option<&Event>,
465 ) -> Result<()> {
466 let mut irqfd = kvm_irqfd {
467 fd: evt.as_raw_descriptor() as u32,
468 gsi,
469 ..Default::default()
470 };
471
472 if let Some(r_evt) = resample_evt {
473 irqfd.flags = KVM_IRQFD_FLAG_RESAMPLE;
474 irqfd.resamplefd = r_evt.as_raw_descriptor() as u32;
475 }
476
477 let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD, &irqfd) };
481 if ret == 0 {
482 Ok(())
483 } else {
484 errno_result()
485 }
486 }
487
488 pub fn unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()> {
494 let irqfd = kvm_irqfd {
495 fd: evt.as_raw_descriptor() as u32,
496 gsi,
497 flags: KVM_IRQFD_FLAG_DEASSIGN,
498 ..Default::default()
499 };
500 let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD, &irqfd) };
504 if ret == 0 {
505 Ok(())
506 } else {
507 errno_result()
508 }
509 }
510
511 pub fn set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()> {
514 let mut irq_routing =
515 kvm_irq_routing::<[kvm_irq_routing_entry]>::new_box_zeroed_with_elems(routes.len())
516 .unwrap();
517 irq_routing.nr = routes.len() as u32;
518
519 let cap_msi_devid = *self
520 .caps
521 .msi_devid
522 .get_or_init(|| self.check_raw_capability(KvmCap::MsiDevid));
523
524 for (route, irq_route) in routes.iter().zip(irq_routing.entries.iter_mut()) {
525 *irq_route = to_kvm_irq_routing_entry(route, cap_msi_devid);
526 }
527
528 #[allow(clippy::undocumented_unsafe_blocks)]
530 let ret = unsafe { ioctl_with_ref(self, KVM_SET_GSI_ROUTING, &*irq_routing) };
531 if ret == 0 {
532 Ok(())
533 } else {
534 errno_result()
535 }
536 }
537
538 fn ioeventfd(
539 &self,
540 evt: Event,
541 addr: IoEventAddress,
542 datamatch: Datamatch,
543 deassign: bool,
544 ) -> Result<()> {
545 let (do_datamatch, datamatch_value, datamatch_len) = match datamatch {
546 Datamatch::AnyLength => (false, 0, 0),
547 Datamatch::U8(v) => match v {
548 Some(u) => (true, u as u64, 1),
549 None => (false, 0, 1),
550 },
551 Datamatch::U16(v) => match v {
552 Some(u) => (true, u as u64, 2),
553 None => (false, 0, 2),
554 },
555 Datamatch::U32(v) => match v {
556 Some(u) => (true, u as u64, 4),
557 None => (false, 0, 4),
558 },
559 Datamatch::U64(v) => match v {
560 Some(u) => (true, u, 8),
561 None => (false, 0, 8),
562 },
563 };
564 let mut flags = 0;
565 if deassign {
566 flags |= 1 << kvm_ioeventfd_flag_nr_deassign;
567 }
568 if do_datamatch {
569 flags |= 1 << kvm_ioeventfd_flag_nr_datamatch
570 }
571 if let IoEventAddress::Pio(_) = addr {
572 flags |= 1 << kvm_ioeventfd_flag_nr_pio;
573 }
574 let ioeventfd = kvm_ioeventfd {
575 datamatch: datamatch_value,
576 len: datamatch_len,
577 addr: match addr {
578 IoEventAddress::Pio(p) => p,
579 IoEventAddress::Mmio(m) => m,
580 },
581 fd: evt.as_raw_descriptor(),
582 flags,
583 ..Default::default()
584 };
585 let ret = unsafe { ioctl_with_ref(self, KVM_IOEVENTFD, &ioeventfd) };
589 if ret == 0 {
590 Ok(())
591 } else {
592 errno_result()
593 }
594 }
595
596 pub fn check_raw_capability(&self, capability: KvmCap) -> bool {
598 let ret = unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, capability as c_ulong) };
602 match capability {
603 #[cfg(target_arch = "x86_64")]
604 KvmCap::BusLockDetect => {
605 if ret > 0 {
606 ret as u32 & KVM_BUS_LOCK_DETECTION_EXIT == KVM_BUS_LOCK_DETECTION_EXIT
607 } else {
608 false
609 }
610 }
611 _ => ret == 1,
612 }
613 }
614
615 #[allow(dead_code)]
617 unsafe fn enable_raw_capability(
624 &self,
625 capability: KvmCap,
626 flags: u32,
627 args: &[u64; 4],
628 ) -> Result<()> {
629 let kvm_cap = kvm_enable_cap {
630 cap: capability as u32,
631 args: *args,
632 flags,
633 ..Default::default()
634 };
635 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
639 if ret == 0 {
640 Ok(())
641 } else {
642 errno_result()
643 }
644 }
645
646 fn handle_inflate(&self, guest_address: GuestAddress, size: u64) -> Result<()> {
647 match self.guest_mem.remove_range(guest_address, size) {
648 Ok(_) => Ok(()),
649 Err(vm_memory::Error::MemoryAccess(_, MmapError::SystemCallFailed(e))) => Err(e),
650 Err(_) => Err(Error::new(EIO)),
651 }
652 }
653
654 fn handle_deflate(&self, _guest_address: GuestAddress, _size: u64) -> Result<()> {
655 Ok(())
657 }
658}
659
660impl Vm for KvmVm {
661 fn try_clone_descriptor(&self) -> Result<SafeDescriptor> {
662 self.vm.try_clone()
663 }
664
665 fn hypervisor_kind(&self) -> HypervisorKind {
666 HypervisorKind::Kvm
667 }
668
669 fn check_capability(&self, c: VmCap) -> bool {
670 if let Some(val) = self.check_capability_arch(c) {
671 return val;
672 }
673 match c {
674 #[cfg(target_arch = "aarch64")]
675 VmCap::ArmPmuV3 => self.check_raw_capability(KvmCap::ArmPmuV3),
676 VmCap::DirtyLog => true,
677 VmCap::PvClock => false,
678 VmCap::Protected => self.check_raw_capability(KvmCap::ArmProtectedVm),
679 VmCap::EarlyInitCpuid => false,
680 #[cfg(target_arch = "x86_64")]
681 VmCap::BusLockDetect => self.check_raw_capability(KvmCap::BusLockDetect),
682 VmCap::ReadOnlyMemoryRegion => {
683 !self.force_disable_readonly_mem && self.check_raw_capability(KvmCap::ReadonlyMem)
684 }
685 VmCap::MemNoncoherentDma => {
686 cfg!(feature = "noncoherent-dma")
687 && (self.check_raw_capability(KvmCap::MemNoncoherentDmaOrPreFaultMemory)
688 || self
689 .check_raw_capability(KvmCap::MemNoncoherentDmaOrArmWritableImpIdRegs))
690 }
691 #[cfg(target_arch = "aarch64")]
692 VmCap::Mte => self.check_raw_capability(KvmCap::ArmMte),
693 #[cfg(target_arch = "aarch64")]
694 VmCap::Sve => self.check_raw_capability(KvmCap::Sve),
695 #[cfg(target_arch = "aarch64")]
696 VmCap::NestedVirt => self.check_raw_capability(KvmCap::El2),
697 }
698 }
699
700 fn enable_capability(&self, c: VmCap, _flags: u32) -> Result<bool> {
701 match c {
702 #[cfg(target_arch = "x86_64")]
703 VmCap::BusLockDetect => {
704 let args = [KVM_BUS_LOCK_DETECTION_EXIT as u64, 0, 0, 0];
705 Ok(
706 #[allow(clippy::undocumented_unsafe_blocks)]
708 unsafe {
709 self.enable_raw_capability(KvmCap::BusLockDetect, _flags, &args) == Ok(())
710 },
711 )
712 }
713 _ => Ok(false),
714 }
715 }
716
717 fn get_guest_phys_addr_bits(&self) -> u8 {
718 self.kvm.get_guest_phys_addr_bits()
719 }
720
721 fn get_memory(&self) -> &GuestMemory {
722 &self.guest_mem
723 }
724
725 fn add_memory_region(
726 &self,
727 guest_addr: GuestAddress,
728 mem: Box<dyn MappedRegion>,
729 read_only: bool,
730 log_dirty_pages: bool,
731 cache: MemCacheType,
732 ) -> Result<MemSlot> {
733 let pgsz = pagesize() as u64;
734 let size = (mem.size() as u64).next_multiple_of(pgsz);
738 let end_addr = guest_addr
739 .checked_add(size)
740 .ok_or_else(|| Error::new(EOVERFLOW))?;
741 if self.guest_mem.range_overlap(guest_addr, end_addr) {
742 return Err(Error::new(ENOSPC));
743 }
744 let mut regions = self.mem_regions.lock();
745 let mut gaps = self.mem_slot_gaps.lock();
746 let slot = match gaps.pop() {
747 Some(gap) => gap.0,
748 None => (regions.len() + self.guest_mem.num_regions() as usize) as MemSlot,
749 };
750
751 let res = unsafe {
757 set_user_memory_region(
758 self,
759 slot,
760 read_only,
761 log_dirty_pages,
762 cache,
763 guest_addr.offset(),
764 size,
765 mem.as_ptr(),
766 )
767 };
768
769 if let Err(e) = res {
770 error!(
771 "set_user_memory_region failed: slot={}, guest_addr={:#x}, size={:#x}, ptr={:p}, cache={:?}, err={:?}",
772 slot, guest_addr.offset(), size, mem.as_ptr(), cache, e
773 );
774 gaps.push(Reverse(slot));
775 return Err(e);
776 }
777 regions.insert(slot, mem);
778 Ok(slot)
779 }
780
781 fn enable_hypercalls(&self, nr: u64, count: usize) -> Result<()> {
782 cfg_if! {
783 if #[cfg(target_arch = "aarch64")] {
784 let base = u32::try_from(nr).unwrap();
785 let nr_functions = u32::try_from(count).unwrap();
786 self.enable_smccc_forwarding(base, nr_functions)
787 } else {
788 let _ = nr;
789 let _ = count;
790 Err(Error::new(ENOTSUP))
791 }
792 }
793 }
794
795 fn msync_memory_region(&self, slot: MemSlot, offset: usize, size: usize) -> Result<()> {
796 let mut regions = self.mem_regions.lock();
797 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
798
799 mem.msync(offset, size).map_err(|err| match err {
800 MmapError::InvalidAddress => Error::new(EFAULT),
801 MmapError::NotPageAligned => Error::new(EINVAL),
802 MmapError::SystemCallFailed(e) => e,
803 _ => Error::new(EIO),
804 })
805 }
806
807 fn madvise_pageout_memory_region(
808 &self,
809 slot: MemSlot,
810 offset: usize,
811 size: usize,
812 ) -> Result<()> {
813 let mut regions = self.mem_regions.lock();
814 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
815
816 mem.madvise(offset, size, libc::MADV_PAGEOUT)
817 .map_err(|err| match err {
818 MmapError::InvalidAddress => Error::new(EFAULT),
819 MmapError::NotPageAligned => Error::new(EINVAL),
820 MmapError::SystemCallFailed(e) => e,
821 _ => Error::new(EIO),
822 })
823 }
824
825 fn madvise_remove_memory_region(
826 &self,
827 slot: MemSlot,
828 offset: usize,
829 size: usize,
830 ) -> Result<()> {
831 let mut regions = self.mem_regions.lock();
832 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
833
834 mem.madvise(offset, size, libc::MADV_REMOVE)
835 .map_err(|err| match err {
836 MmapError::InvalidAddress => Error::new(EFAULT),
837 MmapError::NotPageAligned => Error::new(EINVAL),
838 MmapError::SystemCallFailed(e) => e,
839 _ => Error::new(EIO),
840 })
841 }
842
843 fn remove_memory_region(&self, slot: MemSlot) -> Result<Box<dyn MappedRegion>> {
844 let mut regions = self.mem_regions.lock();
845 if !regions.contains_key(&slot) {
846 return Err(Error::new(ENOENT));
847 }
848 unsafe {
851 set_user_memory_region(
852 self,
853 slot,
854 false,
855 false,
856 MemCacheType::CacheCoherent,
857 0,
858 0,
859 std::ptr::null_mut(),
860 )?;
861 }
862 self.mem_slot_gaps.lock().push(Reverse(slot));
863 Ok(regions.remove(&slot).unwrap())
865 }
866
867 fn create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor> {
868 let mut device = if let Some(dev) = self.get_device_params_arch(kind) {
869 dev
870 } else {
871 match kind {
872 DeviceKind::Vfio => kvm_create_device {
873 type_: kvm_device_type_KVM_DEV_TYPE_VFIO,
874 fd: 0,
875 flags: 0,
876 },
877
878 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
880 _ => return Err(Error::new(libc::ENXIO)),
881 }
882 };
883
884 let ret = unsafe { base::ioctl_with_mut_ref(self, KVM_CREATE_DEVICE, &mut device) };
888 if ret == 0 {
889 Ok(
890 unsafe { SafeDescriptor::from_raw_descriptor(device.fd as i32) },
893 )
894 } else {
895 errno_result()
896 }
897 }
898
899 fn get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()> {
900 let regions = self.mem_regions.lock();
901 let mmap = regions.get(&slot).ok_or_else(|| Error::new(ENOENT))?;
902 if dirty_log_bitmap_size(mmap.size()) > dirty_log.len() {
904 return Err(Error::new(EINVAL));
905 }
906
907 let mut dirty_log_kvm = kvm_dirty_log {
908 slot,
909 ..Default::default()
910 };
911 dirty_log_kvm.__bindgen_anon_1.dirty_bitmap = dirty_log.as_ptr() as *mut c_void;
912 let ret = unsafe { ioctl_with_ref(self, KVM_GET_DIRTY_LOG, &dirty_log_kvm) };
916 if ret == 0 {
917 Ok(())
918 } else {
919 errno_result()
920 }
921 }
922
923 fn register_ioevent(
924 &self,
925 evt: Event,
926 addr: IoEventAddress,
927 datamatch: Datamatch,
928 ) -> Result<()> {
929 self.ioeventfd(evt, addr, datamatch, false)
930 }
931
932 fn unregister_ioevent(
933 &self,
934 evt: Event,
935 addr: IoEventAddress,
936 datamatch: Datamatch,
937 ) -> Result<()> {
938 self.ioeventfd(evt, addr, datamatch, true)
939 }
940
941 fn handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()> {
942 Ok(())
944 }
945
946 fn get_pvclock(&self) -> Result<ClockState> {
947 self.get_pvclock_arch()
948 }
949
950 fn set_pvclock(&self, state: &ClockState) -> Result<()> {
951 self.set_pvclock_arch(state)
952 }
953
954 fn add_fd_mapping(
955 &self,
956 slot: u32,
957 offset: usize,
958 size: usize,
959 fd: &dyn AsRawDescriptor,
960 fd_offset: u64,
961 prot: Protection,
962 ) -> Result<()> {
963 let mut regions = self.mem_regions.lock();
964 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
965
966 match region.add_fd_mapping(offset, size, fd, fd_offset, prot) {
967 Ok(()) => Ok(()),
968 Err(MmapError::SystemCallFailed(e)) => Err(e),
969 Err(_) => Err(Error::new(EIO)),
970 }
971 }
972
973 fn remove_mapping(&self, slot: u32, offset: usize, size: usize) -> Result<()> {
974 let mut regions = self.mem_regions.lock();
975 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
976
977 match region.remove_mapping(offset, size) {
978 Ok(()) => Ok(()),
979 Err(MmapError::SystemCallFailed(e)) => Err(e),
980 Err(_) => Err(Error::new(EIO)),
981 }
982 }
983
984 fn handle_balloon_event(&self, event: BalloonEvent) -> Result<()> {
985 match event {
986 BalloonEvent::Inflate(m) => self.handle_inflate(m.guest_address, m.size),
987 BalloonEvent::Deflate(m) => self.handle_deflate(m.guest_address, m.size),
988 BalloonEvent::BalloonTargetReached(_) => Ok(()),
989 }
990 }
991}
992
993impl AsRawDescriptor for KvmVm {
994 fn as_raw_descriptor(&self) -> RawDescriptor {
995 self.vm.as_raw_descriptor()
996 }
997}
998
999struct KvmVcpuSignalHandle {
1000 run_mmap: Arc<MemoryMapping>,
1001}
1002
1003impl VcpuSignalHandleInner for KvmVcpuSignalHandle {
1004 fn signal_immediate_exit(&self) {
1005 unsafe {
1008 let run = self.run_mmap.as_ptr() as *mut kvm_run;
1009 (*run).immediate_exit = 1;
1010 }
1011 }
1012}
1013
1014pub struct KvmVcpu {
1016 #[cfg(target_arch = "x86_64")]
1017 kvm: Kvm,
1018 #[cfg(not(target_arch = "riscv64"))]
1019 vm: SafeDescriptor,
1020 vcpu: File,
1021 id: usize,
1022 cap_kvmclock_ctrl: bool,
1023 run_mmap: Arc<MemoryMapping>,
1024}
1025
1026impl Vcpu for KvmVcpu {
1027 fn id(&self) -> usize {
1028 self.id
1029 }
1030
1031 #[allow(clippy::cast_ptr_alignment)]
1032 fn set_immediate_exit(&self, exit: bool) {
1033 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1038 run.immediate_exit = exit.into();
1039 }
1040
1041 fn signal_handle(&self) -> VcpuSignalHandle {
1042 VcpuSignalHandle {
1043 inner: Box::new(KvmVcpuSignalHandle {
1044 run_mmap: self.run_mmap.clone(),
1045 }),
1046 }
1047 }
1048
1049 fn on_suspend(&self) -> Result<()> {
1050 if self.cap_kvmclock_ctrl {
1055 if unsafe { ioctl(self, KVM_KVMCLOCK_CTRL) } != 0 {
1058 if Error::last().errno() != libc::EINVAL {
1061 return errno_result();
1062 }
1063 }
1064 }
1065
1066 Ok(())
1067 }
1068
1069 unsafe fn enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()> {
1070 let kvm_cap = kvm_enable_cap {
1071 cap,
1072 args: *args,
1073 ..Default::default()
1074 };
1075 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
1079 if ret == 0 {
1080 Ok(())
1081 } else {
1082 errno_result()
1083 }
1084 }
1085
1086 #[allow(clippy::cast_ptr_alignment)]
1087 fn run(&self) -> Result<VcpuExit> {
1090 let ret = unsafe { ioctl(self, KVM_RUN) };
1093 if ret != 0 {
1094 return errno_result();
1095 }
1096
1097 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1101
1102 if let Some(vcpu_exit) = self.handle_vm_exit_arch(run) {
1105 return Ok(vcpu_exit);
1106 }
1107
1108 match run.exit_reason {
1109 KVM_EXIT_MMIO => Ok(VcpuExit::Mmio),
1110 KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception),
1111 KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall),
1112 KVM_EXIT_DEBUG => Ok(VcpuExit::Debug),
1113 KVM_EXIT_IRQ_WINDOW_OPEN => Ok(VcpuExit::IrqWindowOpen),
1114 KVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown(Ok(()))),
1115 KVM_EXIT_FAIL_ENTRY => {
1116 let hardware_entry_failure_reason = unsafe {
1120 run.__bindgen_anon_1
1121 .fail_entry
1122 .hardware_entry_failure_reason
1123 };
1124 Ok(VcpuExit::FailEntry {
1125 hardware_entry_failure_reason,
1126 })
1127 }
1128 KVM_EXIT_INTR => Ok(VcpuExit::Intr),
1129 KVM_EXIT_INTERNAL_ERROR => Ok(VcpuExit::InternalError),
1130 KVM_EXIT_SYSTEM_EVENT => {
1131 let event_type = unsafe { run.__bindgen_anon_1.system_event.type_ };
1135 let event_flags =
1136 unsafe { run.__bindgen_anon_1.system_event.__bindgen_anon_1.flags };
1140 match event_type {
1141 KVM_SYSTEM_EVENT_SHUTDOWN => Ok(VcpuExit::SystemEventShutdown),
1142 KVM_SYSTEM_EVENT_RESET => self.system_event_reset(event_flags),
1143 KVM_SYSTEM_EVENT_CRASH => Ok(VcpuExit::SystemEventCrash),
1144 _ => {
1145 error!(
1146 "Unknown KVM system event {} with flags {}",
1147 event_type, event_flags
1148 );
1149 Err(Error::new(EINVAL))
1150 }
1151 }
1152 }
1153 r => panic!("unknown kvm exit reason: {r}"),
1154 }
1155 }
1156
1157 fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> {
1158 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1162 assert!(run.exit_reason == KVM_EXIT_MMIO);
1164 let mmio = unsafe { &mut run.__bindgen_anon_1.mmio };
1168 let address = mmio.phys_addr;
1169 let data = &mut mmio.data[..mmio.len as usize];
1170 if mmio.is_write != 0 {
1171 handle_fn(IoParams {
1172 address,
1173 operation: IoOperation::Write(data),
1174 })
1175 } else {
1176 handle_fn(IoParams {
1177 address,
1178 operation: IoOperation::Read(data),
1179 })
1180 }
1181 }
1182
1183 fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> {
1184 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1188 assert!(run.exit_reason == KVM_EXIT_IO);
1190 let io = unsafe { run.__bindgen_anon_1.io };
1194 let address = u64::from(io.port);
1195 let size = usize::from(io.size);
1196 let count = io.count as usize;
1197 let data_len = count * size;
1198 let data_offset = io.data_offset as usize;
1199 assert!(data_offset + data_len <= self.run_mmap.size());
1200
1201 let buffer: &mut [u8] = unsafe {
1205 std::slice::from_raw_parts_mut(
1206 (run as *mut kvm_run as *mut u8).add(data_offset),
1207 data_len,
1208 )
1209 };
1210 let data_chunks = buffer.chunks_mut(size);
1211
1212 if io.direction == KVM_EXIT_IO_IN as u8 {
1213 for data in data_chunks {
1214 handle_fn(IoParams {
1215 address,
1216 operation: IoOperation::Read(data),
1217 });
1218 }
1219 } else {
1220 debug_assert_eq!(io.direction, KVM_EXIT_IO_OUT as u8);
1221 for data in data_chunks {
1222 handle_fn(IoParams {
1223 address,
1224 operation: IoOperation::Write(data),
1225 });
1226 }
1227 }
1228
1229 Ok(())
1230 }
1231
1232 fn handle_hypercall(
1233 &self,
1234 handle_fn: &mut dyn FnMut(&mut HypercallAbi) -> anyhow::Result<()>,
1235 ) -> anyhow::Result<()> {
1236 cfg_if! {
1237 if #[cfg(target_arch = "aarch64")] {
1238 self.handle_smccc_call(handle_fn)
1240 } else {
1241 let _ = handle_fn;
1242 unimplemented!("KvmVcpu::handle_hypercall() not supported");
1243 }
1244 }
1245 }
1246}
1247
1248impl KvmVcpu {
1249 pub fn get_mp_state(&self) -> Result<kvm_mp_state> {
1257 let mut state: kvm_mp_state = unsafe { std::mem::zeroed() };
1259 let ret = {
1260 unsafe { ioctl_with_mut_ref(self, KVM_GET_MP_STATE, &mut state) }
1265 };
1266 if ret < 0 {
1267 return errno_result();
1268 }
1269 Ok(state)
1270 }
1271
1272 pub fn set_mp_state(&self, state: &kvm_mp_state) -> Result<()> {
1280 let ret = {
1281 unsafe { ioctl_with_ref(self, KVM_SET_MP_STATE, state) }
1284 };
1285 if ret < 0 {
1286 return errno_result();
1287 }
1288 Ok(())
1289 }
1290}
1291
1292impl AsRawDescriptor for KvmVcpu {
1293 fn as_raw_descriptor(&self) -> RawDescriptor {
1294 self.vcpu.as_raw_descriptor()
1295 }
1296}
1297
1298impl TryFrom<HypervisorCap> for KvmCap {
1299 type Error = Error;
1300
1301 fn try_from(cap: HypervisorCap) -> Result<KvmCap> {
1302 match cap {
1303 HypervisorCap::ImmediateExit => Ok(KvmCap::ImmediateExit),
1304 HypervisorCap::UserMemory => Ok(KvmCap::UserMemory),
1305 #[cfg(target_arch = "x86_64")]
1306 HypervisorCap::Xcrs => Ok(KvmCap::Xcrs),
1307 #[cfg(target_arch = "x86_64")]
1308 HypervisorCap::CalibratedTscLeafRequired => Err(Error::new(libc::EINVAL)),
1309 HypervisorCap::StaticSwiotlbAllocationRequired => Err(Error::new(libc::EINVAL)),
1310 HypervisorCap::HypervisorInitializedBootContext => Err(Error::new(libc::EINVAL)),
1311 }
1312 }
1313}
1314
1315fn to_kvm_irq_routing_entry(item: &IrqRoute, cap_msi_devid: bool) -> kvm_irq_routing_entry {
1316 match &item.source {
1317 IrqSource::Irqchip { chip, pin } => kvm_irq_routing_entry {
1318 gsi: item.gsi,
1319 type_: KVM_IRQ_ROUTING_IRQCHIP,
1320 u: kvm_irq_routing_entry__bindgen_ty_1 {
1321 irqchip: kvm_irq_routing_irqchip {
1322 irqchip: chip_to_kvm_chip(*chip),
1323 pin: *pin,
1324 },
1325 },
1326 ..Default::default()
1327 },
1328 IrqSource::Msi {
1329 address,
1330 data,
1331 #[cfg(target_arch = "aarch64")]
1332 pci_address,
1333 } => {
1334 let devid = if cap_msi_devid {
1338 #[cfg(not(target_arch = "aarch64"))]
1339 panic!("unexpected KVM_CAP_MSI_DEVID");
1340 #[cfg(target_arch = "aarch64")]
1341 Some(pci_address.to_u32())
1342 } else {
1343 None
1344 };
1345 kvm_irq_routing_entry {
1346 gsi: item.gsi,
1347 type_: KVM_IRQ_ROUTING_MSI,
1348 flags: if devid.is_some() {
1349 KVM_MSI_VALID_DEVID
1350 } else {
1351 0
1352 },
1353 u: kvm_irq_routing_entry__bindgen_ty_1 {
1354 msi: kvm_irq_routing_msi {
1355 address_lo: *address as u32,
1356 address_hi: (*address >> 32) as u32,
1357 data: *data,
1358 __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1 {
1359 devid: devid.unwrap_or_default(),
1360 },
1361 },
1362 },
1363 ..Default::default()
1364 }
1365 }
1366 }
1367}
1368
1369impl From<&kvm_mp_state> for MPState {
1370 fn from(item: &kvm_mp_state) -> Self {
1371 match item.mp_state {
1372 KVM_MP_STATE_RUNNABLE => MPState::Runnable,
1373 KVM_MP_STATE_UNINITIALIZED => MPState::Uninitialized,
1374 KVM_MP_STATE_INIT_RECEIVED => MPState::InitReceived,
1375 KVM_MP_STATE_HALTED => MPState::Halted,
1376 KVM_MP_STATE_SIPI_RECEIVED => MPState::SipiReceived,
1377 KVM_MP_STATE_STOPPED => MPState::Stopped,
1378 state => {
1379 error!(
1380 "unrecognized kvm_mp_state {}, setting to KVM_MP_STATE_RUNNABLE",
1381 state
1382 );
1383 MPState::Runnable
1384 }
1385 }
1386 }
1387}
1388
1389impl From<&MPState> for kvm_mp_state {
1390 fn from(item: &MPState) -> Self {
1391 kvm_mp_state {
1392 mp_state: match item {
1393 MPState::Runnable => KVM_MP_STATE_RUNNABLE,
1394 MPState::Uninitialized => KVM_MP_STATE_UNINITIALIZED,
1395 MPState::InitReceived => KVM_MP_STATE_INIT_RECEIVED,
1396 MPState::Halted => KVM_MP_STATE_HALTED,
1397 MPState::SipiReceived => KVM_MP_STATE_SIPI_RECEIVED,
1398 MPState::Stopped => KVM_MP_STATE_STOPPED,
1399 },
1400 }
1401 }
1402}