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,
326 guest_mem: GuestMemory,
327 mem_regions: Mutex<BTreeMap<MemSlot, Box<dyn MappedRegion>>>,
328 mem_slot_gaps: Mutex<BinaryHeap<Reverse<MemSlot>>>,
330 caps: KvmVmCaps,
331 force_disable_readonly_mem: bool,
332}
333
334impl KvmVm {
335 pub fn new(kvm: &Kvm, guest_mem: GuestMemory, cfg: Config) -> Result<KvmVm> {
337 let ret = unsafe {
341 ioctl_with_val(
342 kvm,
343 KVM_CREATE_VM,
344 kvm.get_vm_type(cfg.protection_type)? as c_ulong,
345 )
346 };
347 if ret < 0 {
348 return errno_result();
349 }
350 let vm_descriptor = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
353 let mut vm = KvmVm {
354 kvm: kvm.try_clone()?,
355 vm: vm_descriptor,
356 guest_mem,
357 mem_regions: Default::default(),
358 mem_slot_gaps: Default::default(),
359 caps: Default::default(),
360 force_disable_readonly_mem: cfg.force_disable_readonly_mem,
361 };
362 vm.caps.kvmclock_ctrl = vm.check_raw_capability(KvmCap::KvmclockCtrl);
363 vm.caps.user_noncoherent_dma_or_another_conflict_cap = vm
368 .check_raw_capability(KvmCap::MemNoncoherentDmaOrPreFaultMemory)
369 || vm.check_raw_capability(KvmCap::MemNoncoherentDmaOrArmWritableImpIdRegs);
370 vm.caps.user_memory_region2 = vm.check_raw_capability(KvmCap::UserMemory2);
371
372 vm.init_arch(&cfg)?;
373
374 for region in vm.guest_mem.regions() {
375 unsafe {
378 set_user_memory_region(
379 &vm,
380 region.index as MemSlot,
381 false,
382 false,
383 MemCacheType::CacheCoherent,
384 region.guest_addr.offset(),
385 region.size as u64,
386 region.host_addr as *mut u8,
387 )
388 }?;
389 }
390
391 Ok(vm)
392 }
393
394 pub fn create_kvm_vcpu(&self, id: usize) -> Result<KvmVcpu> {
395 let fd = unsafe { ioctl_with_val(self, KVM_CREATE_VCPU, c_ulong::try_from(id).unwrap()) };
398 if fd < 0 {
399 return errno_result();
400 }
401
402 let vcpu = unsafe { File::from_raw_descriptor(fd) };
406
407 let run_mmap = MemoryMappingBuilder::new(self.kvm.vcpu_mmap_size)
412 .from_file(&vcpu)
413 .build()
414 .map_err(|_| Error::new(ENOSPC))?;
415
416 Ok(KvmVcpu {
417 #[cfg(target_arch = "x86_64")]
418 kvm: self.kvm.try_clone()?,
419 #[cfg(not(target_arch = "riscv64"))]
420 vm: self.vm.try_clone()?,
421 vcpu,
422 id,
423 cap_kvmclock_ctrl: self.caps.kvmclock_ctrl,
424 run_mmap: Arc::new(run_mmap),
425 })
426 }
427
428 pub fn create_irq_chip(&self) -> Result<()> {
432 let ret = unsafe { ioctl(self, KVM_CREATE_IRQCHIP) };
435 if ret == 0 {
436 Ok(())
437 } else {
438 errno_result()
439 }
440 }
441
442 pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> {
444 let mut irq_level = kvm_irq_level::default();
445 irq_level.__bindgen_anon_1.irq = irq;
446 irq_level.level = active.into();
447
448 let ret = unsafe { ioctl_with_ref(self, KVM_IRQ_LINE, &irq_level) };
452 if ret == 0 {
453 Ok(())
454 } else {
455 errno_result()
456 }
457 }
458
459 pub fn register_irqfd(
462 &self,
463 gsi: u32,
464 evt: &Event,
465 resample_evt: Option<&Event>,
466 ) -> Result<()> {
467 let mut irqfd = kvm_irqfd {
468 fd: evt.as_raw_descriptor() as u32,
469 gsi,
470 ..Default::default()
471 };
472
473 if let Some(r_evt) = resample_evt {
474 irqfd.flags = KVM_IRQFD_FLAG_RESAMPLE;
475 irqfd.resamplefd = r_evt.as_raw_descriptor() as u32;
476 }
477
478 let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD, &irqfd) };
482 if ret == 0 {
483 Ok(())
484 } else {
485 errno_result()
486 }
487 }
488
489 pub fn unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()> {
495 let irqfd = kvm_irqfd {
496 fd: evt.as_raw_descriptor() as u32,
497 gsi,
498 flags: KVM_IRQFD_FLAG_DEASSIGN,
499 ..Default::default()
500 };
501 let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD, &irqfd) };
505 if ret == 0 {
506 Ok(())
507 } else {
508 errno_result()
509 }
510 }
511
512 pub fn set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()> {
515 let mut irq_routing =
516 kvm_irq_routing::<[kvm_irq_routing_entry]>::new_box_zeroed_with_elems(routes.len())
517 .unwrap();
518 irq_routing.nr = routes.len() as u32;
519
520 let cap_msi_devid = *self
521 .caps
522 .msi_devid
523 .get_or_init(|| self.check_raw_capability(KvmCap::MsiDevid));
524
525 for (route, irq_route) in routes.iter().zip(irq_routing.entries.iter_mut()) {
526 *irq_route = to_kvm_irq_routing_entry(route, cap_msi_devid);
527 }
528
529 #[allow(clippy::undocumented_unsafe_blocks)]
531 let ret = unsafe { ioctl_with_ref(self, KVM_SET_GSI_ROUTING, &*irq_routing) };
532 if ret == 0 {
533 Ok(())
534 } else {
535 errno_result()
536 }
537 }
538
539 fn ioeventfd(
540 &self,
541 evt: Event,
542 addr: IoEventAddress,
543 datamatch: Datamatch,
544 deassign: bool,
545 ) -> Result<()> {
546 let (do_datamatch, datamatch_value, datamatch_len) = match datamatch {
547 Datamatch::AnyLength => (false, 0, 0),
548 Datamatch::U8(v) => match v {
549 Some(u) => (true, u as u64, 1),
550 None => (false, 0, 1),
551 },
552 Datamatch::U16(v) => match v {
553 Some(u) => (true, u as u64, 2),
554 None => (false, 0, 2),
555 },
556 Datamatch::U32(v) => match v {
557 Some(u) => (true, u as u64, 4),
558 None => (false, 0, 4),
559 },
560 Datamatch::U64(v) => match v {
561 Some(u) => (true, u, 8),
562 None => (false, 0, 8),
563 },
564 };
565 let mut flags = 0;
566 if deassign {
567 flags |= 1 << kvm_ioeventfd_flag_nr_deassign;
568 }
569 if do_datamatch {
570 flags |= 1 << kvm_ioeventfd_flag_nr_datamatch
571 }
572 if let IoEventAddress::Pio(_) = addr {
573 flags |= 1 << kvm_ioeventfd_flag_nr_pio;
574 }
575 let ioeventfd = kvm_ioeventfd {
576 datamatch: datamatch_value,
577 len: datamatch_len,
578 addr: match addr {
579 IoEventAddress::Pio(p) => p,
580 IoEventAddress::Mmio(m) => m,
581 },
582 fd: evt.as_raw_descriptor(),
583 flags,
584 ..Default::default()
585 };
586 let ret = unsafe { ioctl_with_ref(self, KVM_IOEVENTFD, &ioeventfd) };
590 if ret == 0 {
591 Ok(())
592 } else {
593 errno_result()
594 }
595 }
596
597 pub fn signal_msi(&self, msi: &kvm_msi) -> Result<()> {
599 let ret = unsafe { ioctl_with_ref(self, KVM_SIGNAL_MSI, msi) };
603 if ret >= 0 {
604 Ok(())
605 } else {
606 errno_result()
607 }
608 }
609
610 pub fn check_raw_capability(&self, capability: KvmCap) -> bool {
612 let ret = unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, capability as c_ulong) };
616 match capability {
617 #[cfg(target_arch = "x86_64")]
618 KvmCap::BusLockDetect => {
619 if ret > 0 {
620 ret as u32 & KVM_BUS_LOCK_DETECTION_EXIT == KVM_BUS_LOCK_DETECTION_EXIT
621 } else {
622 false
623 }
624 }
625 _ => ret == 1,
626 }
627 }
628
629 #[allow(dead_code)]
631 unsafe fn enable_raw_capability(
638 &self,
639 capability: KvmCap,
640 flags: u32,
641 args: &[u64; 4],
642 ) -> Result<()> {
643 let kvm_cap = kvm_enable_cap {
644 cap: capability as u32,
645 args: *args,
646 flags,
647 ..Default::default()
648 };
649 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
653 if ret == 0 {
654 Ok(())
655 } else {
656 errno_result()
657 }
658 }
659
660 fn handle_inflate(&self, guest_address: GuestAddress, size: u64) -> Result<()> {
661 match self.guest_mem.remove_range(guest_address, size) {
662 Ok(_) => Ok(()),
663 Err(vm_memory::Error::MemoryAccess(_, MmapError::SystemCallFailed(e))) => Err(e),
664 Err(_) => Err(Error::new(EIO)),
665 }
666 }
667
668 fn handle_deflate(&self, _guest_address: GuestAddress, _size: u64) -> Result<()> {
669 Ok(())
671 }
672}
673
674impl Vm for KvmVm {
675 fn try_clone_descriptor(&self) -> Result<SafeDescriptor> {
676 self.vm.try_clone()
677 }
678
679 fn hypervisor_kind(&self) -> HypervisorKind {
680 HypervisorKind::Kvm
681 }
682
683 fn check_capability(&self, c: VmCap) -> bool {
684 if let Some(val) = self.check_capability_arch(c) {
685 return val;
686 }
687 match c {
688 #[cfg(target_arch = "aarch64")]
689 VmCap::ArmPmuV3 => self.check_raw_capability(KvmCap::ArmPmuV3),
690 VmCap::DirtyLog => true,
691 VmCap::PvClock => false,
692 VmCap::Protected => self.check_raw_capability(KvmCap::ArmProtectedVm),
693 VmCap::EarlyInitCpuid => false,
694 #[cfg(target_arch = "x86_64")]
695 VmCap::BusLockDetect => self.check_raw_capability(KvmCap::BusLockDetect),
696 VmCap::ReadOnlyMemoryRegion => {
697 !self.force_disable_readonly_mem && self.check_raw_capability(KvmCap::ReadonlyMem)
698 }
699 VmCap::MemNoncoherentDma => {
700 cfg!(feature = "noncoherent-dma")
701 && (self.check_raw_capability(KvmCap::MemNoncoherentDmaOrPreFaultMemory)
702 || self
703 .check_raw_capability(KvmCap::MemNoncoherentDmaOrArmWritableImpIdRegs))
704 }
705 #[cfg(target_arch = "aarch64")]
706 VmCap::Mte => self.check_raw_capability(KvmCap::ArmMte),
707 #[cfg(target_arch = "aarch64")]
708 VmCap::Sve => self.check_raw_capability(KvmCap::Sve),
709 #[cfg(target_arch = "aarch64")]
710 VmCap::NestedVirt => self.check_raw_capability(KvmCap::El2),
711 }
712 }
713
714 fn enable_capability(&self, c: VmCap, _flags: u32) -> Result<bool> {
715 match c {
716 #[cfg(target_arch = "x86_64")]
717 VmCap::BusLockDetect => {
718 let args = [KVM_BUS_LOCK_DETECTION_EXIT as u64, 0, 0, 0];
719 Ok(
720 #[allow(clippy::undocumented_unsafe_blocks)]
722 unsafe {
723 self.enable_raw_capability(KvmCap::BusLockDetect, _flags, &args) == Ok(())
724 },
725 )
726 }
727 _ => Ok(false),
728 }
729 }
730
731 fn get_guest_phys_addr_bits(&self) -> u8 {
732 self.kvm.get_guest_phys_addr_bits()
733 }
734
735 fn get_memory(&self) -> &GuestMemory {
736 &self.guest_mem
737 }
738
739 fn add_memory_region(
740 &self,
741 guest_addr: GuestAddress,
742 mem: Box<dyn MappedRegion>,
743 read_only: bool,
744 log_dirty_pages: bool,
745 cache: MemCacheType,
746 ) -> Result<MemSlot> {
747 let pgsz = pagesize() as u64;
748 let size = (mem.size() as u64).next_multiple_of(pgsz);
752 let end_addr = guest_addr
753 .checked_add(size)
754 .ok_or_else(|| Error::new(EOVERFLOW))?;
755 if self.guest_mem.range_overlap(guest_addr, end_addr) {
756 return Err(Error::new(ENOSPC));
757 }
758 let mut regions = self.mem_regions.lock();
759 let mut gaps = self.mem_slot_gaps.lock();
760 let slot = match gaps.pop() {
761 Some(gap) => gap.0,
762 None => (regions.len() + self.guest_mem.num_regions() as usize) as MemSlot,
763 };
764
765 let res = unsafe {
771 set_user_memory_region(
772 self,
773 slot,
774 read_only,
775 log_dirty_pages,
776 cache,
777 guest_addr.offset(),
778 size,
779 mem.as_ptr(),
780 )
781 };
782
783 if let Err(e) = res {
784 error!(
785 "set_user_memory_region failed: slot={}, guest_addr={:#x}, size={:#x}, ptr={:p}, cache={:?}, err={:?}",
786 slot, guest_addr.offset(), size, mem.as_ptr(), cache, e
787 );
788 gaps.push(Reverse(slot));
789 return Err(e);
790 }
791 regions.insert(slot, mem);
792 Ok(slot)
793 }
794
795 fn enable_hypercalls(&self, nr: u64, count: usize) -> Result<()> {
796 cfg_if! {
797 if #[cfg(target_arch = "aarch64")] {
798 let base = u32::try_from(nr).unwrap();
799 let nr_functions = u32::try_from(count).unwrap();
800 self.enable_smccc_forwarding(base, nr_functions)
801 } else {
802 let _ = nr;
803 let _ = count;
804 Err(Error::new(ENOTSUP))
805 }
806 }
807 }
808
809 fn msync_memory_region(&self, slot: MemSlot, offset: usize, size: usize) -> Result<()> {
810 let mut regions = self.mem_regions.lock();
811 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
812
813 mem.msync(offset, size).map_err(|err| match err {
814 MmapError::InvalidAddress => Error::new(EFAULT),
815 MmapError::NotPageAligned => Error::new(EINVAL),
816 MmapError::SystemCallFailed(e) => e,
817 _ => Error::new(EIO),
818 })
819 }
820
821 fn madvise_pageout_memory_region(
822 &self,
823 slot: MemSlot,
824 offset: usize,
825 size: usize,
826 ) -> Result<()> {
827 let mut regions = self.mem_regions.lock();
828 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
829
830 mem.madvise(offset, size, libc::MADV_PAGEOUT)
831 .map_err(|err| match err {
832 MmapError::InvalidAddress => Error::new(EFAULT),
833 MmapError::NotPageAligned => Error::new(EINVAL),
834 MmapError::SystemCallFailed(e) => e,
835 _ => Error::new(EIO),
836 })
837 }
838
839 fn madvise_remove_memory_region(
840 &self,
841 slot: MemSlot,
842 offset: usize,
843 size: usize,
844 ) -> Result<()> {
845 let mut regions = self.mem_regions.lock();
846 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
847
848 mem.madvise(offset, size, libc::MADV_REMOVE)
849 .map_err(|err| match err {
850 MmapError::InvalidAddress => Error::new(EFAULT),
851 MmapError::NotPageAligned => Error::new(EINVAL),
852 MmapError::SystemCallFailed(e) => e,
853 _ => Error::new(EIO),
854 })
855 }
856
857 fn remove_memory_region(&self, slot: MemSlot) -> Result<Box<dyn MappedRegion>> {
858 let mut regions = self.mem_regions.lock();
859 if !regions.contains_key(&slot) {
860 return Err(Error::new(ENOENT));
861 }
862 unsafe {
865 set_user_memory_region(
866 self,
867 slot,
868 false,
869 false,
870 MemCacheType::CacheCoherent,
871 0,
872 0,
873 std::ptr::null_mut(),
874 )?;
875 }
876 self.mem_slot_gaps.lock().push(Reverse(slot));
877 Ok(regions.remove(&slot).unwrap())
879 }
880
881 fn create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor> {
882 let mut device = if let Some(dev) = self.get_device_params_arch(kind) {
883 dev
884 } else {
885 match kind {
886 DeviceKind::Vfio => kvm_create_device {
887 type_: kvm_device_type_KVM_DEV_TYPE_VFIO,
888 fd: 0,
889 flags: 0,
890 },
891
892 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
894 _ => return Err(Error::new(libc::ENXIO)),
895 }
896 };
897
898 let ret = unsafe { base::ioctl_with_mut_ref(self, KVM_CREATE_DEVICE, &mut device) };
902 if ret == 0 {
903 Ok(
904 unsafe { SafeDescriptor::from_raw_descriptor(device.fd as i32) },
907 )
908 } else {
909 errno_result()
910 }
911 }
912
913 fn get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()> {
914 let regions = self.mem_regions.lock();
915 let mmap = regions.get(&slot).ok_or_else(|| Error::new(ENOENT))?;
916 if dirty_log_bitmap_size(mmap.size()) > dirty_log.len() {
918 return Err(Error::new(EINVAL));
919 }
920
921 let mut dirty_log_kvm = kvm_dirty_log {
922 slot,
923 ..Default::default()
924 };
925 dirty_log_kvm.__bindgen_anon_1.dirty_bitmap = dirty_log.as_ptr() as *mut c_void;
926 let ret = unsafe { ioctl_with_ref(self, KVM_GET_DIRTY_LOG, &dirty_log_kvm) };
930 if ret == 0 {
931 Ok(())
932 } else {
933 errno_result()
934 }
935 }
936
937 fn register_ioevent(
938 &self,
939 evt: Event,
940 addr: IoEventAddress,
941 datamatch: Datamatch,
942 ) -> Result<()> {
943 self.ioeventfd(evt, addr, datamatch, false)
944 }
945
946 fn unregister_ioevent(
947 &self,
948 evt: Event,
949 addr: IoEventAddress,
950 datamatch: Datamatch,
951 ) -> Result<()> {
952 self.ioeventfd(evt, addr, datamatch, true)
953 }
954
955 fn handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()> {
956 Ok(())
958 }
959
960 fn get_pvclock(&self) -> Result<ClockState> {
961 self.get_pvclock_arch()
962 }
963
964 fn set_pvclock(&self, state: &ClockState) -> Result<()> {
965 self.set_pvclock_arch(state)
966 }
967
968 fn add_fd_mapping(
969 &self,
970 slot: u32,
971 offset: usize,
972 size: usize,
973 fd: &dyn AsRawDescriptor,
974 fd_offset: u64,
975 prot: Protection,
976 ) -> Result<()> {
977 let mut regions = self.mem_regions.lock();
978 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
979
980 match region.add_fd_mapping(offset, size, fd, fd_offset, prot) {
981 Ok(()) => Ok(()),
982 Err(MmapError::SystemCallFailed(e)) => Err(e),
983 Err(_) => Err(Error::new(EIO)),
984 }
985 }
986
987 fn remove_mapping(&self, slot: u32, offset: usize, size: usize) -> Result<()> {
988 let mut regions = self.mem_regions.lock();
989 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
990
991 match region.remove_mapping(offset, size) {
992 Ok(()) => Ok(()),
993 Err(MmapError::SystemCallFailed(e)) => Err(e),
994 Err(_) => Err(Error::new(EIO)),
995 }
996 }
997
998 fn handle_balloon_event(&self, event: BalloonEvent) -> Result<()> {
999 match event {
1000 BalloonEvent::Inflate(m) => self.handle_inflate(m.guest_address, m.size),
1001 BalloonEvent::Deflate(m) => self.handle_deflate(m.guest_address, m.size),
1002 BalloonEvent::BalloonTargetReached(_) => Ok(()),
1003 }
1004 }
1005}
1006
1007impl AsRawDescriptor for KvmVm {
1008 fn as_raw_descriptor(&self) -> RawDescriptor {
1009 self.vm.as_raw_descriptor()
1010 }
1011}
1012
1013struct KvmVcpuSignalHandle {
1014 run_mmap: Arc<MemoryMapping>,
1015}
1016
1017impl VcpuSignalHandleInner for KvmVcpuSignalHandle {
1018 fn signal_immediate_exit(&self) {
1019 unsafe {
1022 let run = self.run_mmap.as_ptr() as *mut kvm_run;
1023 (*run).immediate_exit = 1;
1024 }
1025 }
1026}
1027
1028pub struct KvmVcpu {
1030 #[cfg(target_arch = "x86_64")]
1031 kvm: Kvm,
1032 #[cfg(not(target_arch = "riscv64"))]
1033 vm: SafeDescriptor,
1034 vcpu: File,
1035 id: usize,
1036 cap_kvmclock_ctrl: bool,
1037 run_mmap: Arc<MemoryMapping>,
1038}
1039
1040impl Vcpu for KvmVcpu {
1041 fn id(&self) -> usize {
1042 self.id
1043 }
1044
1045 #[allow(clippy::cast_ptr_alignment)]
1046 fn set_immediate_exit(&self, exit: bool) {
1047 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1052 run.immediate_exit = exit.into();
1053 }
1054
1055 fn signal_handle(&self) -> VcpuSignalHandle {
1056 VcpuSignalHandle {
1057 inner: Box::new(KvmVcpuSignalHandle {
1058 run_mmap: self.run_mmap.clone(),
1059 }),
1060 }
1061 }
1062
1063 fn on_suspend(&self) -> Result<()> {
1064 if self.cap_kvmclock_ctrl {
1069 if unsafe { ioctl(self, KVM_KVMCLOCK_CTRL) } != 0 {
1072 if Error::last().errno() != libc::EINVAL {
1075 return errno_result();
1076 }
1077 }
1078 }
1079
1080 Ok(())
1081 }
1082
1083 unsafe fn enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()> {
1084 let kvm_cap = kvm_enable_cap {
1085 cap,
1086 args: *args,
1087 ..Default::default()
1088 };
1089 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
1093 if ret == 0 {
1094 Ok(())
1095 } else {
1096 errno_result()
1097 }
1098 }
1099
1100 #[allow(clippy::cast_ptr_alignment)]
1101 fn run(&self) -> Result<VcpuExit> {
1104 let ret = unsafe { ioctl(self, KVM_RUN) };
1107 if ret != 0 {
1108 return errno_result();
1109 }
1110
1111 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1115
1116 if let Some(vcpu_exit) = self.handle_vm_exit_arch(run) {
1119 return Ok(vcpu_exit);
1120 }
1121
1122 match run.exit_reason {
1123 KVM_EXIT_MMIO => Ok(VcpuExit::Mmio),
1124 KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception),
1125 KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall),
1126 KVM_EXIT_DEBUG => Ok(VcpuExit::Debug),
1127 KVM_EXIT_IRQ_WINDOW_OPEN => Ok(VcpuExit::IrqWindowOpen),
1128 KVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown(Ok(()))),
1129 KVM_EXIT_FAIL_ENTRY => {
1130 let hardware_entry_failure_reason = unsafe {
1134 run.__bindgen_anon_1
1135 .fail_entry
1136 .hardware_entry_failure_reason
1137 };
1138 Ok(VcpuExit::FailEntry {
1139 hardware_entry_failure_reason,
1140 })
1141 }
1142 KVM_EXIT_INTR => Ok(VcpuExit::Intr),
1143 KVM_EXIT_INTERNAL_ERROR => Ok(VcpuExit::InternalError),
1144 KVM_EXIT_SYSTEM_EVENT => {
1145 let event_type = unsafe { run.__bindgen_anon_1.system_event.type_ };
1149 let event_flags =
1150 unsafe { run.__bindgen_anon_1.system_event.__bindgen_anon_1.flags };
1154 match event_type {
1155 KVM_SYSTEM_EVENT_SHUTDOWN => Ok(VcpuExit::SystemEventShutdown),
1156 KVM_SYSTEM_EVENT_RESET => self.system_event_reset(event_flags),
1157 KVM_SYSTEM_EVENT_CRASH => Ok(VcpuExit::SystemEventCrash),
1158 _ => {
1159 error!(
1160 "Unknown KVM system event {} with flags {}",
1161 event_type, event_flags
1162 );
1163 Err(Error::new(EINVAL))
1164 }
1165 }
1166 }
1167 r => panic!("unknown kvm exit reason: {r}"),
1168 }
1169 }
1170
1171 fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> {
1172 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1176 assert!(run.exit_reason == KVM_EXIT_MMIO);
1178 let mmio = unsafe { &mut run.__bindgen_anon_1.mmio };
1182 let address = mmio.phys_addr;
1183 let data = &mut mmio.data[..mmio.len as usize];
1184 if mmio.is_write != 0 {
1185 handle_fn(IoParams {
1186 address,
1187 operation: IoOperation::Write(data),
1188 })
1189 } else {
1190 handle_fn(IoParams {
1191 address,
1192 operation: IoOperation::Read(data),
1193 })
1194 }
1195 }
1196
1197 fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> {
1198 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1202 assert!(run.exit_reason == KVM_EXIT_IO);
1204 let io = unsafe { run.__bindgen_anon_1.io };
1208 let address = u64::from(io.port);
1209 let size = usize::from(io.size);
1210 let count = io.count as usize;
1211 let data_len = count * size;
1212 let data_offset = io.data_offset as usize;
1213 assert!(data_offset + data_len <= self.run_mmap.size());
1214
1215 let buffer: &mut [u8] = unsafe {
1219 std::slice::from_raw_parts_mut(
1220 (run as *mut kvm_run as *mut u8).add(data_offset),
1221 data_len,
1222 )
1223 };
1224 let data_chunks = buffer.chunks_mut(size);
1225
1226 if io.direction == KVM_EXIT_IO_IN as u8 {
1227 for data in data_chunks {
1228 handle_fn(IoParams {
1229 address,
1230 operation: IoOperation::Read(data),
1231 });
1232 }
1233 } else {
1234 debug_assert_eq!(io.direction, KVM_EXIT_IO_OUT as u8);
1235 for data in data_chunks {
1236 handle_fn(IoParams {
1237 address,
1238 operation: IoOperation::Write(data),
1239 });
1240 }
1241 }
1242
1243 Ok(())
1244 }
1245
1246 fn handle_hypercall(
1247 &self,
1248 handle_fn: &mut dyn FnMut(&mut HypercallAbi) -> anyhow::Result<()>,
1249 ) -> anyhow::Result<()> {
1250 cfg_if! {
1251 if #[cfg(target_arch = "aarch64")] {
1252 self.handle_smccc_call(handle_fn)
1254 } else {
1255 let _ = handle_fn;
1256 unimplemented!("KvmVcpu::handle_hypercall() not supported");
1257 }
1258 }
1259 }
1260}
1261
1262impl KvmVcpu {
1263 pub fn get_mp_state(&self) -> Result<kvm_mp_state> {
1271 let mut state: kvm_mp_state = unsafe { std::mem::zeroed() };
1273 let ret = {
1274 unsafe { ioctl_with_mut_ref(self, KVM_GET_MP_STATE, &mut state) }
1279 };
1280 if ret < 0 {
1281 return errno_result();
1282 }
1283 Ok(state)
1284 }
1285
1286 pub fn set_mp_state(&self, state: &kvm_mp_state) -> Result<()> {
1294 let ret = {
1295 unsafe { ioctl_with_ref(self, KVM_SET_MP_STATE, state) }
1298 };
1299 if ret < 0 {
1300 return errno_result();
1301 }
1302 Ok(())
1303 }
1304}
1305
1306impl AsRawDescriptor for KvmVcpu {
1307 fn as_raw_descriptor(&self) -> RawDescriptor {
1308 self.vcpu.as_raw_descriptor()
1309 }
1310}
1311
1312impl TryFrom<HypervisorCap> for KvmCap {
1313 type Error = Error;
1314
1315 fn try_from(cap: HypervisorCap) -> Result<KvmCap> {
1316 match cap {
1317 HypervisorCap::ImmediateExit => Ok(KvmCap::ImmediateExit),
1318 HypervisorCap::UserMemory => Ok(KvmCap::UserMemory),
1319 #[cfg(target_arch = "x86_64")]
1320 HypervisorCap::Xcrs => Ok(KvmCap::Xcrs),
1321 #[cfg(target_arch = "x86_64")]
1322 HypervisorCap::CalibratedTscLeafRequired => Err(Error::new(libc::EINVAL)),
1323 HypervisorCap::StaticSwiotlbAllocationRequired => Err(Error::new(libc::EINVAL)),
1324 HypervisorCap::HypervisorInitializedBootContext => Err(Error::new(libc::EINVAL)),
1325 }
1326 }
1327}
1328
1329fn to_kvm_irq_routing_entry(item: &IrqRoute, cap_msi_devid: bool) -> kvm_irq_routing_entry {
1330 match &item.source {
1331 IrqSource::Irqchip { chip, pin } => kvm_irq_routing_entry {
1332 gsi: item.gsi,
1333 type_: KVM_IRQ_ROUTING_IRQCHIP,
1334 u: kvm_irq_routing_entry__bindgen_ty_1 {
1335 irqchip: kvm_irq_routing_irqchip {
1336 irqchip: chip_to_kvm_chip(*chip),
1337 pin: *pin,
1338 },
1339 },
1340 ..Default::default()
1341 },
1342 IrqSource::Msi {
1343 address,
1344 data,
1345 #[cfg(target_arch = "aarch64")]
1346 pci_address,
1347 } => {
1348 let devid = if cap_msi_devid {
1352 #[cfg(not(target_arch = "aarch64"))]
1353 panic!("unexpected KVM_CAP_MSI_DEVID");
1354 #[cfg(target_arch = "aarch64")]
1355 Some(pci_address.to_u32())
1356 } else {
1357 None
1358 };
1359 kvm_irq_routing_entry {
1360 gsi: item.gsi,
1361 type_: KVM_IRQ_ROUTING_MSI,
1362 flags: if devid.is_some() {
1363 KVM_MSI_VALID_DEVID
1364 } else {
1365 0
1366 },
1367 u: kvm_irq_routing_entry__bindgen_ty_1 {
1368 msi: kvm_irq_routing_msi {
1369 address_lo: *address as u32,
1370 address_hi: (*address >> 32) as u32,
1371 data: *data,
1372 __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1 {
1373 devid: devid.unwrap_or_default(),
1374 },
1375 },
1376 },
1377 ..Default::default()
1378 }
1379 }
1380 }
1381}
1382
1383impl From<&kvm_mp_state> for MPState {
1384 fn from(item: &kvm_mp_state) -> Self {
1385 match item.mp_state {
1386 KVM_MP_STATE_RUNNABLE => MPState::Runnable,
1387 KVM_MP_STATE_UNINITIALIZED => MPState::Uninitialized,
1388 KVM_MP_STATE_INIT_RECEIVED => MPState::InitReceived,
1389 KVM_MP_STATE_HALTED => MPState::Halted,
1390 KVM_MP_STATE_SIPI_RECEIVED => MPState::SipiReceived,
1391 KVM_MP_STATE_STOPPED => MPState::Stopped,
1392 state => {
1393 error!(
1394 "unrecognized kvm_mp_state {}, setting to KVM_MP_STATE_RUNNABLE",
1395 state
1396 );
1397 MPState::Runnable
1398 }
1399 }
1400 }
1401}
1402
1403impl From<&MPState> for kvm_mp_state {
1404 fn from(item: &MPState) -> Self {
1405 kvm_mp_state {
1406 mp_state: match item {
1407 MPState::Runnable => KVM_MP_STATE_RUNNABLE,
1408 MPState::Uninitialized => KVM_MP_STATE_UNINITIALIZED,
1409 MPState::InitReceived => KVM_MP_STATE_INIT_RECEIVED,
1410 MPState::Halted => KVM_MP_STATE_HALTED,
1411 MPState::SipiReceived => KVM_MP_STATE_SIPI_RECEIVED,
1412 MPState::Stopped => KVM_MP_STATE_STOPPED,
1413 },
1414 }
1415 }
1416}