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 signal_msi(&self, msi: &kvm_msi) -> Result<()> {
598 let ret = unsafe { ioctl_with_ref(self, KVM_SIGNAL_MSI, msi) };
602 if ret >= 0 {
603 Ok(())
604 } else {
605 errno_result()
606 }
607 }
608
609 pub fn check_raw_capability(&self, capability: KvmCap) -> bool {
611 let ret = unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, capability as c_ulong) };
615 match capability {
616 #[cfg(target_arch = "x86_64")]
617 KvmCap::BusLockDetect => {
618 if ret > 0 {
619 ret as u32 & KVM_BUS_LOCK_DETECTION_EXIT == KVM_BUS_LOCK_DETECTION_EXIT
620 } else {
621 false
622 }
623 }
624 _ => ret == 1,
625 }
626 }
627
628 #[allow(dead_code)]
630 unsafe fn enable_raw_capability(
637 &self,
638 capability: KvmCap,
639 flags: u32,
640 args: &[u64; 4],
641 ) -> Result<()> {
642 let kvm_cap = kvm_enable_cap {
643 cap: capability as u32,
644 args: *args,
645 flags,
646 ..Default::default()
647 };
648 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
652 if ret == 0 {
653 Ok(())
654 } else {
655 errno_result()
656 }
657 }
658
659 fn handle_inflate(&self, guest_address: GuestAddress, size: u64) -> Result<()> {
660 match self.guest_mem.remove_range(guest_address, size) {
661 Ok(_) => Ok(()),
662 Err(vm_memory::Error::MemoryAccess(_, MmapError::SystemCallFailed(e))) => Err(e),
663 Err(_) => Err(Error::new(EIO)),
664 }
665 }
666
667 fn handle_deflate(&self, _guest_address: GuestAddress, _size: u64) -> Result<()> {
668 Ok(())
670 }
671}
672
673impl Vm for KvmVm {
674 fn try_clone_descriptor(&self) -> Result<SafeDescriptor> {
675 self.vm.try_clone()
676 }
677
678 fn hypervisor_kind(&self) -> HypervisorKind {
679 HypervisorKind::Kvm
680 }
681
682 fn check_capability(&self, c: VmCap) -> bool {
683 if let Some(val) = self.check_capability_arch(c) {
684 return val;
685 }
686 match c {
687 #[cfg(target_arch = "aarch64")]
688 VmCap::ArmPmuV3 => self.check_raw_capability(KvmCap::ArmPmuV3),
689 VmCap::DirtyLog => true,
690 VmCap::PvClock => false,
691 VmCap::Protected => self.check_raw_capability(KvmCap::ArmProtectedVm),
692 VmCap::EarlyInitCpuid => false,
693 #[cfg(target_arch = "x86_64")]
694 VmCap::BusLockDetect => self.check_raw_capability(KvmCap::BusLockDetect),
695 VmCap::ReadOnlyMemoryRegion => {
696 !self.force_disable_readonly_mem && self.check_raw_capability(KvmCap::ReadonlyMem)
697 }
698 VmCap::MemNoncoherentDma => {
699 cfg!(feature = "noncoherent-dma")
700 && (self.check_raw_capability(KvmCap::MemNoncoherentDmaOrPreFaultMemory)
701 || self
702 .check_raw_capability(KvmCap::MemNoncoherentDmaOrArmWritableImpIdRegs))
703 }
704 #[cfg(target_arch = "aarch64")]
705 VmCap::Mte => self.check_raw_capability(KvmCap::ArmMte),
706 #[cfg(target_arch = "aarch64")]
707 VmCap::Sve => self.check_raw_capability(KvmCap::Sve),
708 #[cfg(target_arch = "aarch64")]
709 VmCap::NestedVirt => self.check_raw_capability(KvmCap::El2),
710 }
711 }
712
713 fn enable_capability(&self, c: VmCap, _flags: u32) -> Result<bool> {
714 match c {
715 #[cfg(target_arch = "x86_64")]
716 VmCap::BusLockDetect => {
717 let args = [KVM_BUS_LOCK_DETECTION_EXIT as u64, 0, 0, 0];
718 Ok(
719 #[allow(clippy::undocumented_unsafe_blocks)]
721 unsafe {
722 self.enable_raw_capability(KvmCap::BusLockDetect, _flags, &args) == Ok(())
723 },
724 )
725 }
726 _ => Ok(false),
727 }
728 }
729
730 fn get_guest_phys_addr_bits(&self) -> u8 {
731 self.kvm.get_guest_phys_addr_bits()
732 }
733
734 fn get_memory(&self) -> &GuestMemory {
735 &self.guest_mem
736 }
737
738 fn add_memory_region(
739 &self,
740 guest_addr: GuestAddress,
741 mem: Box<dyn MappedRegion>,
742 read_only: bool,
743 log_dirty_pages: bool,
744 cache: MemCacheType,
745 ) -> Result<MemSlot> {
746 let pgsz = pagesize() as u64;
747 let size = (mem.size() as u64).next_multiple_of(pgsz);
751 let end_addr = guest_addr
752 .checked_add(size)
753 .ok_or_else(|| Error::new(EOVERFLOW))?;
754 if self.guest_mem.range_overlap(guest_addr, end_addr) {
755 return Err(Error::new(ENOSPC));
756 }
757 let mut regions = self.mem_regions.lock();
758 let mut gaps = self.mem_slot_gaps.lock();
759 let slot = match gaps.pop() {
760 Some(gap) => gap.0,
761 None => (regions.len() + self.guest_mem.num_regions() as usize) as MemSlot,
762 };
763
764 let res = unsafe {
770 set_user_memory_region(
771 self,
772 slot,
773 read_only,
774 log_dirty_pages,
775 cache,
776 guest_addr.offset(),
777 size,
778 mem.as_ptr(),
779 )
780 };
781
782 if let Err(e) = res {
783 error!(
784 "set_user_memory_region failed: slot={}, guest_addr={:#x}, size={:#x}, ptr={:p}, cache={:?}, err={:?}",
785 slot, guest_addr.offset(), size, mem.as_ptr(), cache, e
786 );
787 gaps.push(Reverse(slot));
788 return Err(e);
789 }
790 regions.insert(slot, mem);
791 Ok(slot)
792 }
793
794 fn enable_hypercalls(&self, nr: u64, count: usize) -> Result<()> {
795 cfg_if! {
796 if #[cfg(target_arch = "aarch64")] {
797 let base = u32::try_from(nr).unwrap();
798 let nr_functions = u32::try_from(count).unwrap();
799 self.enable_smccc_forwarding(base, nr_functions)
800 } else {
801 let _ = nr;
802 let _ = count;
803 Err(Error::new(ENOTSUP))
804 }
805 }
806 }
807
808 fn msync_memory_region(&self, slot: MemSlot, offset: usize, size: usize) -> Result<()> {
809 let mut regions = self.mem_regions.lock();
810 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
811
812 mem.msync(offset, size).map_err(|err| match err {
813 MmapError::InvalidAddress => Error::new(EFAULT),
814 MmapError::NotPageAligned => Error::new(EINVAL),
815 MmapError::SystemCallFailed(e) => e,
816 _ => Error::new(EIO),
817 })
818 }
819
820 fn madvise_pageout_memory_region(
821 &self,
822 slot: MemSlot,
823 offset: usize,
824 size: usize,
825 ) -> Result<()> {
826 let mut regions = self.mem_regions.lock();
827 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
828
829 mem.madvise(offset, size, libc::MADV_PAGEOUT)
830 .map_err(|err| match err {
831 MmapError::InvalidAddress => Error::new(EFAULT),
832 MmapError::NotPageAligned => Error::new(EINVAL),
833 MmapError::SystemCallFailed(e) => e,
834 _ => Error::new(EIO),
835 })
836 }
837
838 fn madvise_remove_memory_region(
839 &self,
840 slot: MemSlot,
841 offset: usize,
842 size: usize,
843 ) -> Result<()> {
844 let mut regions = self.mem_regions.lock();
845 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
846
847 mem.madvise(offset, size, libc::MADV_REMOVE)
848 .map_err(|err| match err {
849 MmapError::InvalidAddress => Error::new(EFAULT),
850 MmapError::NotPageAligned => Error::new(EINVAL),
851 MmapError::SystemCallFailed(e) => e,
852 _ => Error::new(EIO),
853 })
854 }
855
856 fn remove_memory_region(&self, slot: MemSlot) -> Result<Box<dyn MappedRegion>> {
857 let mut regions = self.mem_regions.lock();
858 if !regions.contains_key(&slot) {
859 return Err(Error::new(ENOENT));
860 }
861 unsafe {
864 set_user_memory_region(
865 self,
866 slot,
867 false,
868 false,
869 MemCacheType::CacheCoherent,
870 0,
871 0,
872 std::ptr::null_mut(),
873 )?;
874 }
875 self.mem_slot_gaps.lock().push(Reverse(slot));
876 Ok(regions.remove(&slot).unwrap())
878 }
879
880 fn create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor> {
881 let mut device = if let Some(dev) = self.get_device_params_arch(kind) {
882 dev
883 } else {
884 match kind {
885 DeviceKind::Vfio => kvm_create_device {
886 type_: kvm_device_type_KVM_DEV_TYPE_VFIO,
887 fd: 0,
888 flags: 0,
889 },
890
891 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
893 _ => return Err(Error::new(libc::ENXIO)),
894 }
895 };
896
897 let ret = unsafe { base::ioctl_with_mut_ref(self, KVM_CREATE_DEVICE, &mut device) };
901 if ret == 0 {
902 Ok(
903 unsafe { SafeDescriptor::from_raw_descriptor(device.fd as i32) },
906 )
907 } else {
908 errno_result()
909 }
910 }
911
912 fn get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()> {
913 let regions = self.mem_regions.lock();
914 let mmap = regions.get(&slot).ok_or_else(|| Error::new(ENOENT))?;
915 if dirty_log_bitmap_size(mmap.size()) > dirty_log.len() {
917 return Err(Error::new(EINVAL));
918 }
919
920 let mut dirty_log_kvm = kvm_dirty_log {
921 slot,
922 ..Default::default()
923 };
924 dirty_log_kvm.__bindgen_anon_1.dirty_bitmap = dirty_log.as_ptr() as *mut c_void;
925 let ret = unsafe { ioctl_with_ref(self, KVM_GET_DIRTY_LOG, &dirty_log_kvm) };
929 if ret == 0 {
930 Ok(())
931 } else {
932 errno_result()
933 }
934 }
935
936 fn register_ioevent(
937 &self,
938 evt: Event,
939 addr: IoEventAddress,
940 datamatch: Datamatch,
941 ) -> Result<()> {
942 self.ioeventfd(evt, addr, datamatch, false)
943 }
944
945 fn unregister_ioevent(
946 &self,
947 evt: Event,
948 addr: IoEventAddress,
949 datamatch: Datamatch,
950 ) -> Result<()> {
951 self.ioeventfd(evt, addr, datamatch, true)
952 }
953
954 fn handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()> {
955 Ok(())
957 }
958
959 fn get_pvclock(&self) -> Result<ClockState> {
960 self.get_pvclock_arch()
961 }
962
963 fn set_pvclock(&self, state: &ClockState) -> Result<()> {
964 self.set_pvclock_arch(state)
965 }
966
967 fn add_fd_mapping(
968 &self,
969 slot: u32,
970 offset: usize,
971 size: usize,
972 fd: &dyn AsRawDescriptor,
973 fd_offset: u64,
974 prot: Protection,
975 ) -> Result<()> {
976 let mut regions = self.mem_regions.lock();
977 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
978
979 match region.add_fd_mapping(offset, size, fd, fd_offset, prot) {
980 Ok(()) => Ok(()),
981 Err(MmapError::SystemCallFailed(e)) => Err(e),
982 Err(_) => Err(Error::new(EIO)),
983 }
984 }
985
986 fn remove_mapping(&self, slot: u32, offset: usize, size: usize) -> Result<()> {
987 let mut regions = self.mem_regions.lock();
988 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
989
990 match region.remove_mapping(offset, size) {
991 Ok(()) => Ok(()),
992 Err(MmapError::SystemCallFailed(e)) => Err(e),
993 Err(_) => Err(Error::new(EIO)),
994 }
995 }
996
997 fn handle_balloon_event(&self, event: BalloonEvent) -> Result<()> {
998 match event {
999 BalloonEvent::Inflate(m) => self.handle_inflate(m.guest_address, m.size),
1000 BalloonEvent::Deflate(m) => self.handle_deflate(m.guest_address, m.size),
1001 BalloonEvent::BalloonTargetReached(_) => Ok(()),
1002 }
1003 }
1004}
1005
1006impl AsRawDescriptor for KvmVm {
1007 fn as_raw_descriptor(&self) -> RawDescriptor {
1008 self.vm.as_raw_descriptor()
1009 }
1010}
1011
1012struct KvmVcpuSignalHandle {
1013 run_mmap: Arc<MemoryMapping>,
1014}
1015
1016impl VcpuSignalHandleInner for KvmVcpuSignalHandle {
1017 fn signal_immediate_exit(&self) {
1018 unsafe {
1021 let run = self.run_mmap.as_ptr() as *mut kvm_run;
1022 (*run).immediate_exit = 1;
1023 }
1024 }
1025}
1026
1027pub struct KvmVcpu {
1029 #[cfg(target_arch = "x86_64")]
1030 kvm: Kvm,
1031 #[cfg(not(target_arch = "riscv64"))]
1032 vm: SafeDescriptor,
1033 vcpu: File,
1034 id: usize,
1035 cap_kvmclock_ctrl: bool,
1036 run_mmap: Arc<MemoryMapping>,
1037}
1038
1039impl Vcpu for KvmVcpu {
1040 fn id(&self) -> usize {
1041 self.id
1042 }
1043
1044 #[allow(clippy::cast_ptr_alignment)]
1045 fn set_immediate_exit(&self, exit: bool) {
1046 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1051 run.immediate_exit = exit.into();
1052 }
1053
1054 fn signal_handle(&self) -> VcpuSignalHandle {
1055 VcpuSignalHandle {
1056 inner: Box::new(KvmVcpuSignalHandle {
1057 run_mmap: self.run_mmap.clone(),
1058 }),
1059 }
1060 }
1061
1062 fn on_suspend(&self) -> Result<()> {
1063 if self.cap_kvmclock_ctrl {
1068 if unsafe { ioctl(self, KVM_KVMCLOCK_CTRL) } != 0 {
1071 if Error::last().errno() != libc::EINVAL {
1074 return errno_result();
1075 }
1076 }
1077 }
1078
1079 Ok(())
1080 }
1081
1082 unsafe fn enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()> {
1083 let kvm_cap = kvm_enable_cap {
1084 cap,
1085 args: *args,
1086 ..Default::default()
1087 };
1088 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
1092 if ret == 0 {
1093 Ok(())
1094 } else {
1095 errno_result()
1096 }
1097 }
1098
1099 #[allow(clippy::cast_ptr_alignment)]
1100 fn run(&self) -> Result<VcpuExit> {
1103 let ret = unsafe { ioctl(self, KVM_RUN) };
1106 if ret != 0 {
1107 return errno_result();
1108 }
1109
1110 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1114
1115 if let Some(vcpu_exit) = self.handle_vm_exit_arch(run) {
1118 return Ok(vcpu_exit);
1119 }
1120
1121 match run.exit_reason {
1122 KVM_EXIT_MMIO => Ok(VcpuExit::Mmio),
1123 KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception),
1124 KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall),
1125 KVM_EXIT_DEBUG => Ok(VcpuExit::Debug),
1126 KVM_EXIT_IRQ_WINDOW_OPEN => Ok(VcpuExit::IrqWindowOpen),
1127 KVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown(Ok(()))),
1128 KVM_EXIT_FAIL_ENTRY => {
1129 let hardware_entry_failure_reason = unsafe {
1133 run.__bindgen_anon_1
1134 .fail_entry
1135 .hardware_entry_failure_reason
1136 };
1137 Ok(VcpuExit::FailEntry {
1138 hardware_entry_failure_reason,
1139 })
1140 }
1141 KVM_EXIT_INTR => Ok(VcpuExit::Intr),
1142 KVM_EXIT_INTERNAL_ERROR => Ok(VcpuExit::InternalError),
1143 KVM_EXIT_SYSTEM_EVENT => {
1144 let event_type = unsafe { run.__bindgen_anon_1.system_event.type_ };
1148 let event_flags =
1149 unsafe { run.__bindgen_anon_1.system_event.__bindgen_anon_1.flags };
1153 match event_type {
1154 KVM_SYSTEM_EVENT_SHUTDOWN => Ok(VcpuExit::SystemEventShutdown),
1155 KVM_SYSTEM_EVENT_RESET => self.system_event_reset(event_flags),
1156 KVM_SYSTEM_EVENT_CRASH => Ok(VcpuExit::SystemEventCrash),
1157 _ => {
1158 error!(
1159 "Unknown KVM system event {} with flags {}",
1160 event_type, event_flags
1161 );
1162 Err(Error::new(EINVAL))
1163 }
1164 }
1165 }
1166 r => panic!("unknown kvm exit reason: {r}"),
1167 }
1168 }
1169
1170 fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> {
1171 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1175 assert!(run.exit_reason == KVM_EXIT_MMIO);
1177 let mmio = unsafe { &mut run.__bindgen_anon_1.mmio };
1181 let address = mmio.phys_addr;
1182 let data = &mut mmio.data[..mmio.len as usize];
1183 if mmio.is_write != 0 {
1184 handle_fn(IoParams {
1185 address,
1186 operation: IoOperation::Write(data),
1187 })
1188 } else {
1189 handle_fn(IoParams {
1190 address,
1191 operation: IoOperation::Read(data),
1192 })
1193 }
1194 }
1195
1196 fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> {
1197 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1201 assert!(run.exit_reason == KVM_EXIT_IO);
1203 let io = unsafe { run.__bindgen_anon_1.io };
1207 let address = u64::from(io.port);
1208 let size = usize::from(io.size);
1209 let count = io.count as usize;
1210 let data_len = count * size;
1211 let data_offset = io.data_offset as usize;
1212 assert!(data_offset + data_len <= self.run_mmap.size());
1213
1214 let buffer: &mut [u8] = unsafe {
1218 std::slice::from_raw_parts_mut(
1219 (run as *mut kvm_run as *mut u8).add(data_offset),
1220 data_len,
1221 )
1222 };
1223 let data_chunks = buffer.chunks_mut(size);
1224
1225 if io.direction == KVM_EXIT_IO_IN as u8 {
1226 for data in data_chunks {
1227 handle_fn(IoParams {
1228 address,
1229 operation: IoOperation::Read(data),
1230 });
1231 }
1232 } else {
1233 debug_assert_eq!(io.direction, KVM_EXIT_IO_OUT as u8);
1234 for data in data_chunks {
1235 handle_fn(IoParams {
1236 address,
1237 operation: IoOperation::Write(data),
1238 });
1239 }
1240 }
1241
1242 Ok(())
1243 }
1244
1245 fn handle_hypercall(
1246 &self,
1247 handle_fn: &mut dyn FnMut(&mut HypercallAbi) -> anyhow::Result<()>,
1248 ) -> anyhow::Result<()> {
1249 cfg_if! {
1250 if #[cfg(target_arch = "aarch64")] {
1251 self.handle_smccc_call(handle_fn)
1253 } else {
1254 let _ = handle_fn;
1255 unimplemented!("KvmVcpu::handle_hypercall() not supported");
1256 }
1257 }
1258 }
1259}
1260
1261impl KvmVcpu {
1262 pub fn get_mp_state(&self) -> Result<kvm_mp_state> {
1270 let mut state: kvm_mp_state = unsafe { std::mem::zeroed() };
1272 let ret = {
1273 unsafe { ioctl_with_mut_ref(self, KVM_GET_MP_STATE, &mut state) }
1278 };
1279 if ret < 0 {
1280 return errno_result();
1281 }
1282 Ok(state)
1283 }
1284
1285 pub fn set_mp_state(&self, state: &kvm_mp_state) -> Result<()> {
1293 let ret = {
1294 unsafe { ioctl_with_ref(self, KVM_SET_MP_STATE, state) }
1297 };
1298 if ret < 0 {
1299 return errno_result();
1300 }
1301 Ok(())
1302 }
1303}
1304
1305impl AsRawDescriptor for KvmVcpu {
1306 fn as_raw_descriptor(&self) -> RawDescriptor {
1307 self.vcpu.as_raw_descriptor()
1308 }
1309}
1310
1311impl TryFrom<HypervisorCap> for KvmCap {
1312 type Error = Error;
1313
1314 fn try_from(cap: HypervisorCap) -> Result<KvmCap> {
1315 match cap {
1316 HypervisorCap::ImmediateExit => Ok(KvmCap::ImmediateExit),
1317 HypervisorCap::UserMemory => Ok(KvmCap::UserMemory),
1318 #[cfg(target_arch = "x86_64")]
1319 HypervisorCap::Xcrs => Ok(KvmCap::Xcrs),
1320 #[cfg(target_arch = "x86_64")]
1321 HypervisorCap::CalibratedTscLeafRequired => Err(Error::new(libc::EINVAL)),
1322 HypervisorCap::StaticSwiotlbAllocationRequired => Err(Error::new(libc::EINVAL)),
1323 HypervisorCap::HypervisorInitializedBootContext => Err(Error::new(libc::EINVAL)),
1324 }
1325 }
1326}
1327
1328fn to_kvm_irq_routing_entry(item: &IrqRoute, cap_msi_devid: bool) -> kvm_irq_routing_entry {
1329 match &item.source {
1330 IrqSource::Irqchip { chip, pin } => kvm_irq_routing_entry {
1331 gsi: item.gsi,
1332 type_: KVM_IRQ_ROUTING_IRQCHIP,
1333 u: kvm_irq_routing_entry__bindgen_ty_1 {
1334 irqchip: kvm_irq_routing_irqchip {
1335 irqchip: chip_to_kvm_chip(*chip),
1336 pin: *pin,
1337 },
1338 },
1339 ..Default::default()
1340 },
1341 IrqSource::Msi {
1342 address,
1343 data,
1344 #[cfg(target_arch = "aarch64")]
1345 pci_address,
1346 } => {
1347 let devid = if cap_msi_devid {
1351 #[cfg(not(target_arch = "aarch64"))]
1352 panic!("unexpected KVM_CAP_MSI_DEVID");
1353 #[cfg(target_arch = "aarch64")]
1354 Some(pci_address.to_u32())
1355 } else {
1356 None
1357 };
1358 kvm_irq_routing_entry {
1359 gsi: item.gsi,
1360 type_: KVM_IRQ_ROUTING_MSI,
1361 flags: if devid.is_some() {
1362 KVM_MSI_VALID_DEVID
1363 } else {
1364 0
1365 },
1366 u: kvm_irq_routing_entry__bindgen_ty_1 {
1367 msi: kvm_irq_routing_msi {
1368 address_lo: *address as u32,
1369 address_hi: (*address >> 32) as u32,
1370 data: *data,
1371 __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1 {
1372 devid: devid.unwrap_or_default(),
1373 },
1374 },
1375 },
1376 ..Default::default()
1377 }
1378 }
1379 }
1380}
1381
1382impl From<&kvm_mp_state> for MPState {
1383 fn from(item: &kvm_mp_state) -> Self {
1384 match item.mp_state {
1385 KVM_MP_STATE_RUNNABLE => MPState::Runnable,
1386 KVM_MP_STATE_UNINITIALIZED => MPState::Uninitialized,
1387 KVM_MP_STATE_INIT_RECEIVED => MPState::InitReceived,
1388 KVM_MP_STATE_HALTED => MPState::Halted,
1389 KVM_MP_STATE_SIPI_RECEIVED => MPState::SipiReceived,
1390 KVM_MP_STATE_STOPPED => MPState::Stopped,
1391 state => {
1392 error!(
1393 "unrecognized kvm_mp_state {}, setting to KVM_MP_STATE_RUNNABLE",
1394 state
1395 );
1396 MPState::Runnable
1397 }
1398 }
1399 }
1400}
1401
1402impl From<&MPState> for kvm_mp_state {
1403 fn from(item: &MPState) -> Self {
1404 kvm_mp_state {
1405 mp_state: match item {
1406 MPState::Runnable => KVM_MP_STATE_RUNNABLE,
1407 MPState::Uninitialized => KVM_MP_STATE_UNINITIALIZED,
1408 MPState::InitReceived => KVM_MP_STATE_INIT_RECEIVED,
1409 MPState::Halted => KVM_MP_STATE_HALTED,
1410 MPState::SipiReceived => KVM_MP_STATE_SIPI_RECEIVED,
1411 MPState::Stopped => KVM_MP_STATE_STOPPED,
1412 },
1413 }
1414 }
1415}