1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
6 mod aarch64;
7 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
8 pub use aarch64::*;
9
10 mod cap;
11 pub use cap::KvmCap;
12
13 #[cfg(target_arch = "riscv64")]
14 mod riscv64;
15
16 #[cfg(target_arch = "x86_64")]
17 mod x86_64;
18
19 use std::cmp::Reverse;
20 use std::collections::BTreeMap;
21 use std::collections::BinaryHeap;
22 use std::convert::TryFrom;
23 use std::ffi::CString;
24 use std::fs::File;
25 use std::os::raw::c_ulong;
26 use std::os::raw::c_void;
27 use std::os::unix::prelude::OsStrExt;
28 use std::path::Path;
29 use std::sync::Arc;
30
31 use base::errno_result;
32 use base::error;
33 use base::ioctl;
34 use base::ioctl_with_mut_ref;
35 use base::ioctl_with_ref;
36 use base::ioctl_with_val;
37 use base::pagesize;
38 use base::AsRawDescriptor;
39 use base::Error;
40 use base::Event;
41 use base::FromRawDescriptor;
42 use base::MappedRegion;
43 use base::MemoryMapping;
44 use base::MemoryMappingBuilder;
45 use base::MmapError;
46 use base::Protection;
47 use base::RawDescriptor;
48 use base::Result;
49 use base::SafeDescriptor;
50 use data_model::vec_with_array_field;
51 use kvm_sys::*;
52 use libc::open64;
53 use libc::EFAULT;
54 use libc::EINVAL;
55 use libc::EIO;
56 use libc::ENOENT;
57 use libc::ENOSPC;
58 use libc::ENOSYS;
59 use libc::EOVERFLOW;
60 use libc::O_CLOEXEC;
61 use libc::O_RDWR;
62 #[cfg(target_arch = "riscv64")]
63 use riscv64::*;
64 use sync::Mutex;
65 use vm_memory::GuestAddress;
66 use vm_memory::GuestMemory;
67 #[cfg(target_arch = "x86_64")]
68 pub use x86_64::*;
69
70 use crate::BalloonEvent;
71 use crate::ClockState;
72 use crate::Config;
73 use crate::Datamatch;
74 use crate::DeviceKind;
75 use crate::Hypervisor;
76 use crate::HypervisorCap;
77 use crate::IoEventAddress;
78 use crate::IoOperation;
79 use crate::IoParams;
80 use crate::IrqRoute;
81 use crate::IrqSource;
82 use crate::MPState;
83 use crate::MemCacheType;
84 use crate::MemSlot;
85 use crate::Vcpu;
86 use crate::VcpuExit;
87 use crate::VcpuSignalHandle;
88 use crate::VcpuSignalHandleInner;
89 use crate::Vm;
90 use crate::VmCap;
91
92 // Wrapper around KVM_SET_USER_MEMORY_REGION ioctl, which creates, modifies, or deletes a mapping
93 // from guest physical to host user pages.
94 //
95 // SAFETY:
96 // Safe when the guest regions are guaranteed not to overlap.
set_user_memory_region( descriptor: &SafeDescriptor, slot: MemSlot, read_only: bool, log_dirty_pages: bool, cache: MemCacheType, guest_addr: u64, memory_size: u64, userspace_addr: *mut u8, ) -> Result<()>97 unsafe fn set_user_memory_region(
98 descriptor: &SafeDescriptor,
99 slot: MemSlot,
100 read_only: bool,
101 log_dirty_pages: bool,
102 cache: MemCacheType,
103 guest_addr: u64,
104 memory_size: u64,
105 userspace_addr: *mut u8,
106 ) -> Result<()> {
107 let mut flags = if read_only { KVM_MEM_READONLY } else { 0 };
108 if log_dirty_pages {
109 flags |= KVM_MEM_LOG_DIRTY_PAGES;
110 }
111 if cache == MemCacheType::CacheNonCoherent {
112 flags |= KVM_MEM_NON_COHERENT_DMA;
113 }
114 let region = kvm_userspace_memory_region {
115 slot,
116 flags,
117 guest_phys_addr: guest_addr,
118 memory_size,
119 userspace_addr: userspace_addr as u64,
120 };
121
122 let ret = ioctl_with_ref(descriptor, KVM_SET_USER_MEMORY_REGION, ®ion);
123 if ret == 0 {
124 Ok(())
125 } else {
126 errno_result()
127 }
128 }
129
130 /// Helper function to determine the size in bytes of a dirty log bitmap for the given memory region
131 /// size.
132 ///
133 /// # Arguments
134 ///
135 /// * `size` - Number of bytes in the memory region being queried.
dirty_log_bitmap_size(size: usize) -> usize136 pub fn dirty_log_bitmap_size(size: usize) -> usize {
137 let page_size = pagesize();
138 (((size + page_size - 1) / page_size) + 7) / 8
139 }
140
141 pub struct Kvm {
142 kvm: SafeDescriptor,
143 vcpu_mmap_size: usize,
144 }
145
146 impl Kvm {
new_with_path(device_path: &Path) -> Result<Kvm>147 pub fn new_with_path(device_path: &Path) -> Result<Kvm> {
148 let c_path = CString::new(device_path.as_os_str().as_bytes()).unwrap();
149 // SAFETY:
150 // Open calls are safe because we give a nul-terminated string and verify the result.
151 let ret = unsafe { open64(c_path.as_ptr(), O_RDWR | O_CLOEXEC) };
152 if ret < 0 {
153 return errno_result();
154 }
155 // SAFETY:
156 // Safe because we verify that ret is valid and we own the fd.
157 let kvm = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
158
159 // SAFETY:
160 // Safe because we know that the descriptor is valid and we verify the return result.
161 let version = unsafe { ioctl(&kvm, KVM_GET_API_VERSION) };
162 if version < 0 {
163 return errno_result();
164 }
165
166 // Per the kernel KVM API documentation: "Applications should refuse to run if
167 // KVM_GET_API_VERSION returns a value other than 12."
168 if version as u32 != KVM_API_VERSION {
169 error!(
170 "KVM_GET_API_VERSION: expected {}, got {}",
171 KVM_API_VERSION, version,
172 );
173 return Err(Error::new(ENOSYS));
174 }
175
176 // SAFETY:
177 // Safe because we know that our file is a KVM fd and we verify the return result.
178 let res = unsafe { ioctl(&kvm, KVM_GET_VCPU_MMAP_SIZE) };
179 if res <= 0 {
180 return errno_result();
181 }
182 let vcpu_mmap_size = res as usize;
183
184 Ok(Kvm {
185 kvm,
186 vcpu_mmap_size,
187 })
188 }
189
190 /// Opens `/dev/kvm` and returns a Kvm object on success.
new() -> Result<Kvm>191 pub fn new() -> Result<Kvm> {
192 Kvm::new_with_path(Path::new("/dev/kvm"))
193 }
194 }
195
196 impl AsRawDescriptor for Kvm {
as_raw_descriptor(&self) -> RawDescriptor197 fn as_raw_descriptor(&self) -> RawDescriptor {
198 self.kvm.as_raw_descriptor()
199 }
200 }
201
202 impl Hypervisor for Kvm {
try_clone(&self) -> Result<Self>203 fn try_clone(&self) -> Result<Self> {
204 Ok(Kvm {
205 kvm: self.kvm.try_clone()?,
206 vcpu_mmap_size: self.vcpu_mmap_size,
207 })
208 }
209
check_capability(&self, cap: HypervisorCap) -> bool210 fn check_capability(&self, cap: HypervisorCap) -> bool {
211 if let Ok(kvm_cap) = KvmCap::try_from(cap) {
212 // SAFETY:
213 // this ioctl is safe because we know this kvm descriptor is valid,
214 // and we are copying over the kvm capability (u32) as a c_ulong value.
215 unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, kvm_cap as c_ulong) == 1 }
216 } else {
217 // this capability cannot be converted on this platform, so return false
218 false
219 }
220 }
221 }
222
223 /// A wrapper around creating and using a KVM VM.
224 pub struct KvmVm {
225 kvm: Kvm,
226 vm: SafeDescriptor,
227 guest_mem: GuestMemory,
228 mem_regions: Arc<Mutex<BTreeMap<MemSlot, Box<dyn MappedRegion>>>>,
229 /// A min heap of MemSlot numbers that were used and then removed and can now be re-used
230 mem_slot_gaps: Arc<Mutex<BinaryHeap<Reverse<MemSlot>>>>,
231 cap_kvmclock_ctrl: bool,
232 }
233
234 impl KvmVm {
235 /// Constructs a new `KvmVm` using the given `Kvm` instance.
new(kvm: &Kvm, guest_mem: GuestMemory, cfg: Config) -> Result<KvmVm>236 pub fn new(kvm: &Kvm, guest_mem: GuestMemory, cfg: Config) -> Result<KvmVm> {
237 // SAFETY:
238 // Safe because we know kvm is a real kvm fd as this module is the only one that can make
239 // Kvm objects.
240 let ret = unsafe {
241 ioctl_with_val(
242 kvm,
243 KVM_CREATE_VM,
244 kvm.get_vm_type(cfg.protection_type)? as c_ulong,
245 )
246 };
247 if ret < 0 {
248 return errno_result();
249 }
250 // SAFETY:
251 // Safe because we verify that ret is valid and we own the fd.
252 let vm_descriptor = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
253 for region in guest_mem.regions() {
254 // SAFETY:
255 // Safe because the guest regions are guaranteed not to overlap.
256 unsafe {
257 set_user_memory_region(
258 &vm_descriptor,
259 region.index as MemSlot,
260 false,
261 false,
262 MemCacheType::CacheCoherent,
263 region.guest_addr.offset(),
264 region.size as u64,
265 region.host_addr as *mut u8,
266 )
267 }?;
268 }
269
270 let mut vm = KvmVm {
271 kvm: kvm.try_clone()?,
272 vm: vm_descriptor,
273 guest_mem,
274 mem_regions: Arc::new(Mutex::new(BTreeMap::new())),
275 mem_slot_gaps: Arc::new(Mutex::new(BinaryHeap::new())),
276 cap_kvmclock_ctrl: false,
277 };
278 vm.cap_kvmclock_ctrl = vm.check_raw_capability(KvmCap::KvmclockCtrl);
279 vm.init_arch(&cfg)?;
280 Ok(vm)
281 }
282
create_kvm_vcpu(&self, id: usize) -> Result<KvmVcpu>283 pub fn create_kvm_vcpu(&self, id: usize) -> Result<KvmVcpu> {
284 // SAFETY:
285 // Safe because we know that our file is a VM fd and we verify the return result.
286 let fd = unsafe { ioctl_with_val(self, KVM_CREATE_VCPU, c_ulong::try_from(id).unwrap()) };
287 if fd < 0 {
288 return errno_result();
289 }
290
291 // SAFETY:
292 // Wrap the vcpu now in case the following ? returns early. This is safe because we verified
293 // the value of the fd and we own the fd.
294 let vcpu = unsafe { File::from_raw_descriptor(fd) };
295
296 // The VCPU mapping is held by an `Arc` inside `KvmVcpu`, and it can also be cloned by
297 // `signal_handle()` for use in `KvmVcpuSignalHandle`. The mapping will not be destroyed
298 // until all references are dropped, so it is safe to reference `kvm_run` fields via the
299 // `as_ptr()` function during either type's lifetime.
300 let run_mmap = MemoryMappingBuilder::new(self.kvm.vcpu_mmap_size)
301 .from_file(&vcpu)
302 .build()
303 .map_err(|_| Error::new(ENOSPC))?;
304
305 Ok(KvmVcpu {
306 kvm: self.kvm.try_clone()?,
307 vm: self.vm.try_clone()?,
308 vcpu,
309 id,
310 cap_kvmclock_ctrl: self.cap_kvmclock_ctrl,
311 run_mmap: Arc::new(run_mmap),
312 })
313 }
314
315 /// Creates an in kernel interrupt controller.
316 ///
317 /// See the documentation on the KVM_CREATE_IRQCHIP ioctl.
create_irq_chip(&self) -> Result<()>318 pub fn create_irq_chip(&self) -> Result<()> {
319 // SAFETY:
320 // Safe because we know that our file is a VM fd and we verify the return result.
321 let ret = unsafe { ioctl(self, KVM_CREATE_IRQCHIP) };
322 if ret == 0 {
323 Ok(())
324 } else {
325 errno_result()
326 }
327 }
328
329 /// Sets the level on the given irq to 1 if `active` is true, and 0 otherwise.
set_irq_line(&self, irq: u32, active: bool) -> Result<()>330 pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> {
331 let mut irq_level = kvm_irq_level::default();
332 irq_level.__bindgen_anon_1.irq = irq;
333 irq_level.level = active.into();
334
335 // SAFETY:
336 // Safe because we know that our file is a VM fd, we know the kernel will only read the
337 // correct amount of memory from our pointer, and we verify the return result.
338 let ret = unsafe { ioctl_with_ref(self, KVM_IRQ_LINE, &irq_level) };
339 if ret == 0 {
340 Ok(())
341 } else {
342 errno_result()
343 }
344 }
345
346 /// Registers an event that will, when signalled, trigger the `gsi` irq, and `resample_evt`
347 /// ( when not None ) will be triggered when the irqchip is resampled.
register_irqfd( &self, gsi: u32, evt: &Event, resample_evt: Option<&Event>, ) -> Result<()>348 pub fn register_irqfd(
349 &self,
350 gsi: u32,
351 evt: &Event,
352 resample_evt: Option<&Event>,
353 ) -> Result<()> {
354 let mut irqfd = kvm_irqfd {
355 fd: evt.as_raw_descriptor() as u32,
356 gsi,
357 ..Default::default()
358 };
359
360 if let Some(r_evt) = resample_evt {
361 irqfd.flags = KVM_IRQFD_FLAG_RESAMPLE;
362 irqfd.resamplefd = r_evt.as_raw_descriptor() as u32;
363 }
364
365 // SAFETY:
366 // Safe because we know that our file is a VM fd, we know the kernel will only read the
367 // correct amount of memory from our pointer, and we verify the return result.
368 let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD, &irqfd) };
369 if ret == 0 {
370 Ok(())
371 } else {
372 errno_result()
373 }
374 }
375
376 /// Unregisters an event that was previously registered with
377 /// `register_irqfd`.
378 ///
379 /// The `evt` and `gsi` pair must be the same as the ones passed into
380 /// `register_irqfd`.
unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()>381 pub fn unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()> {
382 let irqfd = kvm_irqfd {
383 fd: evt.as_raw_descriptor() as u32,
384 gsi,
385 flags: KVM_IRQFD_FLAG_DEASSIGN,
386 ..Default::default()
387 };
388 // SAFETY:
389 // Safe because we know that our file is a VM fd, we know the kernel will only read the
390 // correct amount of memory from our pointer, and we verify the return result.
391 let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD, &irqfd) };
392 if ret == 0 {
393 Ok(())
394 } else {
395 errno_result()
396 }
397 }
398
399 /// Sets the GSI routing table, replacing any table set with previous calls to
400 /// `set_gsi_routing`.
set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()>401 pub fn set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()> {
402 let mut irq_routing =
403 vec_with_array_field::<kvm_irq_routing, kvm_irq_routing_entry>(routes.len());
404 irq_routing[0].nr = routes.len() as u32;
405
406 // SAFETY:
407 // Safe because we ensured there is enough space in irq_routing to hold the number of
408 // route entries.
409 let irq_routes = unsafe { irq_routing[0].entries.as_mut_slice(routes.len()) };
410 for (route, irq_route) in routes.iter().zip(irq_routes.iter_mut()) {
411 *irq_route = kvm_irq_routing_entry::from(route);
412 }
413
414 // TODO(b/315998194): Add safety comment
415 #[allow(clippy::undocumented_unsafe_blocks)]
416 let ret = unsafe { ioctl_with_ref(self, KVM_SET_GSI_ROUTING, &irq_routing[0]) };
417 if ret == 0 {
418 Ok(())
419 } else {
420 errno_result()
421 }
422 }
423
ioeventfd( &self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, deassign: bool, ) -> Result<()>424 fn ioeventfd(
425 &self,
426 evt: &Event,
427 addr: IoEventAddress,
428 datamatch: Datamatch,
429 deassign: bool,
430 ) -> Result<()> {
431 let (do_datamatch, datamatch_value, datamatch_len) = match datamatch {
432 Datamatch::AnyLength => (false, 0, 0),
433 Datamatch::U8(v) => match v {
434 Some(u) => (true, u as u64, 1),
435 None => (false, 0, 1),
436 },
437 Datamatch::U16(v) => match v {
438 Some(u) => (true, u as u64, 2),
439 None => (false, 0, 2),
440 },
441 Datamatch::U32(v) => match v {
442 Some(u) => (true, u as u64, 4),
443 None => (false, 0, 4),
444 },
445 Datamatch::U64(v) => match v {
446 Some(u) => (true, u, 8),
447 None => (false, 0, 8),
448 },
449 };
450 let mut flags = 0;
451 if deassign {
452 flags |= 1 << kvm_ioeventfd_flag_nr_deassign;
453 }
454 if do_datamatch {
455 flags |= 1 << kvm_ioeventfd_flag_nr_datamatch
456 }
457 if let IoEventAddress::Pio(_) = addr {
458 flags |= 1 << kvm_ioeventfd_flag_nr_pio;
459 }
460 let ioeventfd = kvm_ioeventfd {
461 datamatch: datamatch_value,
462 len: datamatch_len,
463 addr: match addr {
464 IoEventAddress::Pio(p) => p,
465 IoEventAddress::Mmio(m) => m,
466 },
467 fd: evt.as_raw_descriptor(),
468 flags,
469 ..Default::default()
470 };
471 // SAFETY:
472 // Safe because we know that our file is a VM fd, we know the kernel will only read the
473 // correct amount of memory from our pointer, and we verify the return result.
474 let ret = unsafe { ioctl_with_ref(self, KVM_IOEVENTFD, &ioeventfd) };
475 if ret == 0 {
476 Ok(())
477 } else {
478 errno_result()
479 }
480 }
481
482 /// Checks whether a particular KVM-specific capability is available for this VM.
check_raw_capability(&self, capability: KvmCap) -> bool483 pub fn check_raw_capability(&self, capability: KvmCap) -> bool {
484 // SAFETY:
485 // Safe because we know that our file is a KVM fd, and if the cap is invalid KVM assumes
486 // it's an unavailable extension and returns 0.
487 let ret = unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION, capability as c_ulong) };
488 match capability {
489 #[cfg(target_arch = "x86_64")]
490 KvmCap::BusLockDetect => {
491 if ret > 0 {
492 ret as u32 & KVM_BUS_LOCK_DETECTION_EXIT == KVM_BUS_LOCK_DETECTION_EXIT
493 } else {
494 false
495 }
496 }
497 _ => ret == 1,
498 }
499 }
500
501 // Currently only used on aarch64, but works on any architecture.
502 #[allow(dead_code)]
503 /// Enables a KVM-specific capability for this VM, with the given arguments.
504 ///
505 /// # Safety
506 /// This function is marked as unsafe because `args` may be interpreted as pointers for some
507 /// capabilities. The caller must ensure that any pointers passed in the `args` array are
508 /// allocated as the kernel expects, and that mutable pointers are owned.
enable_raw_capability( &self, capability: KvmCap, flags: u32, args: &[u64; 4], ) -> Result<()>509 unsafe fn enable_raw_capability(
510 &self,
511 capability: KvmCap,
512 flags: u32,
513 args: &[u64; 4],
514 ) -> Result<()> {
515 let kvm_cap = kvm_enable_cap {
516 cap: capability as u32,
517 args: *args,
518 flags,
519 ..Default::default()
520 };
521 // SAFETY:
522 // Safe because we allocated the struct and we know the kernel will read exactly the size of
523 // the struct, and because we assume the caller has allocated the args appropriately.
524 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
525 if ret == 0 {
526 Ok(())
527 } else {
528 errno_result()
529 }
530 }
531
handle_inflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()>532 fn handle_inflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()> {
533 match self.guest_mem.remove_range(guest_address, size) {
534 Ok(_) => Ok(()),
535 Err(vm_memory::Error::MemoryAccess(_, MmapError::SystemCallFailed(e))) => Err(e),
536 Err(_) => Err(Error::new(EIO)),
537 }
538 }
539
handle_deflate(&mut self, _guest_address: GuestAddress, _size: u64) -> Result<()>540 fn handle_deflate(&mut self, _guest_address: GuestAddress, _size: u64) -> Result<()> {
541 // No-op, when the guest attempts to access the pages again, Linux/KVM will provide them.
542 Ok(())
543 }
544 }
545
546 impl Vm for KvmVm {
try_clone(&self) -> Result<Self>547 fn try_clone(&self) -> Result<Self> {
548 Ok(KvmVm {
549 kvm: self.kvm.try_clone()?,
550 vm: self.vm.try_clone()?,
551 guest_mem: self.guest_mem.clone(),
552 mem_regions: self.mem_regions.clone(),
553 mem_slot_gaps: self.mem_slot_gaps.clone(),
554 cap_kvmclock_ctrl: self.cap_kvmclock_ctrl,
555 })
556 }
557
check_capability(&self, c: VmCap) -> bool558 fn check_capability(&self, c: VmCap) -> bool {
559 if let Some(val) = self.check_capability_arch(c) {
560 return val;
561 }
562 match c {
563 VmCap::DirtyLog => true,
564 VmCap::PvClock => false,
565 VmCap::Protected => self.check_raw_capability(KvmCap::ArmProtectedVm),
566 VmCap::EarlyInitCpuid => false,
567 #[cfg(target_arch = "x86_64")]
568 VmCap::BusLockDetect => self.check_raw_capability(KvmCap::BusLockDetect),
569 // When pKVM is the hypervisor, read-only memslots aren't supported, even for
570 // non-protected VMs.
571 VmCap::ReadOnlyMemoryRegion => !self.is_pkvm(),
572 VmCap::MemNoncoherentDma => {
573 cfg!(feature = "noncoherent-dma")
574 && self.check_raw_capability(KvmCap::MemNoncoherentDma)
575 }
576 }
577 }
578
enable_capability(&self, c: VmCap, _flags: u32) -> Result<bool>579 fn enable_capability(&self, c: VmCap, _flags: u32) -> Result<bool> {
580 match c {
581 #[cfg(target_arch = "x86_64")]
582 VmCap::BusLockDetect => {
583 let args = [KVM_BUS_LOCK_DETECTION_EXIT as u64, 0, 0, 0];
584 Ok(
585 // TODO(b/315998194): Add safety comment
586 #[allow(clippy::undocumented_unsafe_blocks)]
587 unsafe {
588 self.enable_raw_capability(KvmCap::BusLockDetect, _flags, &args) == Ok(())
589 },
590 )
591 }
592 _ => Ok(false),
593 }
594 }
595
get_guest_phys_addr_bits(&self) -> u8596 fn get_guest_phys_addr_bits(&self) -> u8 {
597 self.kvm.get_guest_phys_addr_bits()
598 }
599
get_memory(&self) -> &GuestMemory600 fn get_memory(&self) -> &GuestMemory {
601 &self.guest_mem
602 }
603
add_memory_region( &mut self, guest_addr: GuestAddress, mem: Box<dyn MappedRegion>, read_only: bool, log_dirty_pages: bool, cache: MemCacheType, ) -> Result<MemSlot>604 fn add_memory_region(
605 &mut self,
606 guest_addr: GuestAddress,
607 mem: Box<dyn MappedRegion>,
608 read_only: bool,
609 log_dirty_pages: bool,
610 cache: MemCacheType,
611 ) -> Result<MemSlot> {
612 let pgsz = pagesize() as u64;
613 // KVM require to set the user memory region with page size aligned size. Safe to extend
614 // the mem.size() to be page size aligned because the mmap will round up the size to be
615 // page size aligned if it is not.
616 let size = (mem.size() as u64 + pgsz - 1) / pgsz * pgsz;
617 let end_addr = guest_addr
618 .checked_add(size)
619 .ok_or_else(|| Error::new(EOVERFLOW))?;
620 if self.guest_mem.range_overlap(guest_addr, end_addr) {
621 return Err(Error::new(ENOSPC));
622 }
623 let mut regions = self.mem_regions.lock();
624 let mut gaps = self.mem_slot_gaps.lock();
625 let slot = match gaps.pop() {
626 Some(gap) => gap.0,
627 None => (regions.len() + self.guest_mem.num_regions() as usize) as MemSlot,
628 };
629
630 let cache_type = if self.check_capability(VmCap::MemNoncoherentDma) {
631 cache
632 } else {
633 MemCacheType::CacheCoherent
634 };
635
636 // SAFETY:
637 // Safe because we check that the given guest address is valid and has no overlaps. We also
638 // know that the pointer and size are correct because the MemoryMapping interface ensures
639 // this. We take ownership of the memory mapping so that it won't be unmapped until the slot
640 // is removed.
641 let res = unsafe {
642 set_user_memory_region(
643 &self.vm,
644 slot,
645 read_only,
646 log_dirty_pages,
647 cache_type,
648 guest_addr.offset(),
649 size,
650 mem.as_ptr(),
651 )
652 };
653
654 if let Err(e) = res {
655 gaps.push(Reverse(slot));
656 return Err(e);
657 }
658 regions.insert(slot, mem);
659 Ok(slot)
660 }
661
msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()>662 fn msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()> {
663 let mut regions = self.mem_regions.lock();
664 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
665
666 mem.msync(offset, size).map_err(|err| match err {
667 MmapError::InvalidAddress => Error::new(EFAULT),
668 MmapError::NotPageAligned => Error::new(EINVAL),
669 MmapError::SystemCallFailed(e) => e,
670 _ => Error::new(EIO),
671 })
672 }
673
madvise_pageout_memory_region( &mut self, slot: MemSlot, offset: usize, size: usize, ) -> Result<()>674 fn madvise_pageout_memory_region(
675 &mut self,
676 slot: MemSlot,
677 offset: usize,
678 size: usize,
679 ) -> Result<()> {
680 let mut regions = self.mem_regions.lock();
681 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
682
683 mem.madvise(offset, size, libc::MADV_PAGEOUT)
684 .map_err(|err| match err {
685 MmapError::InvalidAddress => Error::new(EFAULT),
686 MmapError::NotPageAligned => Error::new(EINVAL),
687 MmapError::SystemCallFailed(e) => e,
688 _ => Error::new(EIO),
689 })
690 }
691
madvise_remove_memory_region( &mut self, slot: MemSlot, offset: usize, size: usize, ) -> Result<()>692 fn madvise_remove_memory_region(
693 &mut self,
694 slot: MemSlot,
695 offset: usize,
696 size: usize,
697 ) -> Result<()> {
698 let mut regions = self.mem_regions.lock();
699 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
700
701 mem.madvise(offset, size, libc::MADV_REMOVE)
702 .map_err(|err| match err {
703 MmapError::InvalidAddress => Error::new(EFAULT),
704 MmapError::NotPageAligned => Error::new(EINVAL),
705 MmapError::SystemCallFailed(e) => e,
706 _ => Error::new(EIO),
707 })
708 }
709
remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>>710 fn remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>> {
711 let mut regions = self.mem_regions.lock();
712 if !regions.contains_key(&slot) {
713 return Err(Error::new(ENOENT));
714 }
715 // SAFETY:
716 // Safe because the slot is checked against the list of memory slots.
717 unsafe {
718 set_user_memory_region(
719 &self.vm,
720 slot,
721 false,
722 false,
723 MemCacheType::CacheCoherent,
724 0,
725 0,
726 std::ptr::null_mut(),
727 )?;
728 }
729 self.mem_slot_gaps.lock().push(Reverse(slot));
730 // This remove will always succeed because of the contains_key check above.
731 Ok(regions.remove(&slot).unwrap())
732 }
733
create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor>734 fn create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor> {
735 let mut device = if let Some(dev) = self.get_device_params_arch(kind) {
736 dev
737 } else {
738 match kind {
739 DeviceKind::Vfio => kvm_create_device {
740 type_: kvm_device_type_KVM_DEV_TYPE_VFIO,
741 fd: 0,
742 flags: 0,
743 },
744
745 // ARM and risc-v have additional DeviceKinds, so it needs the catch-all pattern
746 #[cfg(any(target_arch = "arm", target_arch = "aarch64", target_arch = "riscv64"))]
747 _ => return Err(Error::new(libc::ENXIO)),
748 }
749 };
750
751 // SAFETY:
752 // Safe because we know that our file is a VM fd, we know the kernel will only write correct
753 // amount of memory to our pointer, and we verify the return result.
754 let ret = unsafe { base::ioctl_with_mut_ref(self, KVM_CREATE_DEVICE, &mut device) };
755 if ret == 0 {
756 Ok(
757 // SAFETY:
758 // Safe because we verify that ret is valid and we own the fd.
759 unsafe { SafeDescriptor::from_raw_descriptor(device.fd as i32) },
760 )
761 } else {
762 errno_result()
763 }
764 }
765
get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()>766 fn get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()> {
767 let regions = self.mem_regions.lock();
768 let mmap = regions.get(&slot).ok_or_else(|| Error::new(ENOENT))?;
769 // Ensures that there are as many bytes in dirty_log as there are pages in the mmap.
770 if dirty_log_bitmap_size(mmap.size()) > dirty_log.len() {
771 return Err(Error::new(EINVAL));
772 }
773
774 let mut dirty_log_kvm = kvm_dirty_log {
775 slot,
776 ..Default::default()
777 };
778 dirty_log_kvm.__bindgen_anon_1.dirty_bitmap = dirty_log.as_ptr() as *mut c_void;
779 // SAFETY:
780 // Safe because the `dirty_bitmap` pointer assigned above is guaranteed to be valid (because
781 // it's from a slice) and we checked that it will be large enough to hold the entire log.
782 let ret = unsafe { ioctl_with_ref(self, KVM_GET_DIRTY_LOG, &dirty_log_kvm) };
783 if ret == 0 {
784 Ok(())
785 } else {
786 errno_result()
787 }
788 }
789
register_ioevent( &mut self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, ) -> Result<()>790 fn register_ioevent(
791 &mut self,
792 evt: &Event,
793 addr: IoEventAddress,
794 datamatch: Datamatch,
795 ) -> Result<()> {
796 self.ioeventfd(evt, addr, datamatch, false)
797 }
798
unregister_ioevent( &mut self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, ) -> Result<()>799 fn unregister_ioevent(
800 &mut self,
801 evt: &Event,
802 addr: IoEventAddress,
803 datamatch: Datamatch,
804 ) -> Result<()> {
805 self.ioeventfd(evt, addr, datamatch, true)
806 }
807
handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()>808 fn handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()> {
809 // KVM delivers IO events in-kernel with ioeventfds, so this is a no-op
810 Ok(())
811 }
812
get_pvclock(&self) -> Result<ClockState>813 fn get_pvclock(&self) -> Result<ClockState> {
814 self.get_pvclock_arch()
815 }
816
set_pvclock(&self, state: &ClockState) -> Result<()>817 fn set_pvclock(&self, state: &ClockState) -> Result<()> {
818 self.set_pvclock_arch(state)
819 }
820
add_fd_mapping( &mut self, slot: u32, offset: usize, size: usize, fd: &dyn AsRawDescriptor, fd_offset: u64, prot: Protection, ) -> Result<()>821 fn add_fd_mapping(
822 &mut self,
823 slot: u32,
824 offset: usize,
825 size: usize,
826 fd: &dyn AsRawDescriptor,
827 fd_offset: u64,
828 prot: Protection,
829 ) -> Result<()> {
830 let mut regions = self.mem_regions.lock();
831 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
832
833 match region.add_fd_mapping(offset, size, fd, fd_offset, prot) {
834 Ok(()) => Ok(()),
835 Err(MmapError::SystemCallFailed(e)) => Err(e),
836 Err(_) => Err(Error::new(EIO)),
837 }
838 }
839
remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()>840 fn remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()> {
841 let mut regions = self.mem_regions.lock();
842 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
843
844 match region.remove_mapping(offset, size) {
845 Ok(()) => Ok(()),
846 Err(MmapError::SystemCallFailed(e)) => Err(e),
847 Err(_) => Err(Error::new(EIO)),
848 }
849 }
850
handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()>851 fn handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()> {
852 match event {
853 BalloonEvent::Inflate(m) => self.handle_inflate(m.guest_address, m.size),
854 BalloonEvent::Deflate(m) => self.handle_deflate(m.guest_address, m.size),
855 BalloonEvent::BalloonTargetReached(_) => Ok(()),
856 }
857 }
858 }
859
860 impl AsRawDescriptor for KvmVm {
as_raw_descriptor(&self) -> RawDescriptor861 fn as_raw_descriptor(&self) -> RawDescriptor {
862 self.vm.as_raw_descriptor()
863 }
864 }
865
866 struct KvmVcpuSignalHandle {
867 run_mmap: Arc<MemoryMapping>,
868 }
869
870 impl VcpuSignalHandleInner for KvmVcpuSignalHandle {
signal_immediate_exit(&self)871 fn signal_immediate_exit(&self) {
872 // SAFETY: we ensure `run_mmap` is a valid mapping of `kvm_run` at creation time, and the
873 // `Arc` ensures the mapping still exists while we hold a reference to it.
874 unsafe {
875 let run = self.run_mmap.as_ptr() as *mut kvm_run;
876 (*run).immediate_exit = 1;
877 }
878 }
879 }
880
881 /// A wrapper around using a KVM Vcpu.
882 pub struct KvmVcpu {
883 kvm: Kvm,
884 vm: SafeDescriptor,
885 vcpu: File,
886 id: usize,
887 cap_kvmclock_ctrl: bool,
888 run_mmap: Arc<MemoryMapping>,
889 }
890
891 impl Vcpu for KvmVcpu {
try_clone(&self) -> Result<Self>892 fn try_clone(&self) -> Result<Self> {
893 let vm = self.vm.try_clone()?;
894 let vcpu = self.vcpu.try_clone()?;
895
896 Ok(KvmVcpu {
897 kvm: self.kvm.try_clone()?,
898 vm,
899 vcpu,
900 cap_kvmclock_ctrl: self.cap_kvmclock_ctrl,
901 id: self.id,
902 run_mmap: self.run_mmap.clone(),
903 })
904 }
905
as_vcpu(&self) -> &dyn Vcpu906 fn as_vcpu(&self) -> &dyn Vcpu {
907 self
908 }
909
id(&self) -> usize910 fn id(&self) -> usize {
911 self.id
912 }
913
914 #[allow(clippy::cast_ptr_alignment)]
set_immediate_exit(&self, exit: bool)915 fn set_immediate_exit(&self, exit: bool) {
916 // SAFETY:
917 // Safe because we know we mapped enough memory to hold the kvm_run struct because the
918 // kernel told us how large it was. The pointer is page aligned so casting to a different
919 // type is well defined, hence the clippy allow attribute.
920 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
921 run.immediate_exit = exit.into();
922 }
923
signal_handle(&self) -> VcpuSignalHandle924 fn signal_handle(&self) -> VcpuSignalHandle {
925 VcpuSignalHandle {
926 inner: Box::new(KvmVcpuSignalHandle {
927 run_mmap: self.run_mmap.clone(),
928 }),
929 }
930 }
931
on_suspend(&self) -> Result<()>932 fn on_suspend(&self) -> Result<()> {
933 // On KVM implementations that use a paravirtualized clock (e.g. x86), a flag must be set to
934 // indicate to the guest kernel that a vCPU was suspended. The guest kernel will use this
935 // flag to prevent the soft lockup detection from triggering when this vCPU resumes, which
936 // could happen days later in realtime.
937 if self.cap_kvmclock_ctrl {
938 // SAFETY:
939 // The ioctl is safe because it does not read or write memory in this process.
940 if unsafe { ioctl(self, KVM_KVMCLOCK_CTRL) } != 0 {
941 // Even if the host kernel supports the capability, it may not be configured by
942 // the guest - for example, when the guest kernel offlines a CPU.
943 if Error::last().errno() != libc::EINVAL {
944 return errno_result();
945 }
946 }
947 }
948
949 Ok(())
950 }
951
enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()>952 unsafe fn enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()> {
953 let kvm_cap = kvm_enable_cap {
954 cap,
955 args: *args,
956 ..Default::default()
957 };
958 // SAFETY:
959 // Safe because we allocated the struct and we know the kernel will read exactly the size of
960 // the struct, and because we assume the caller has allocated the args appropriately.
961 let ret = ioctl_with_ref(self, KVM_ENABLE_CAP, &kvm_cap);
962 if ret == 0 {
963 Ok(())
964 } else {
965 errno_result()
966 }
967 }
968
969 #[allow(clippy::cast_ptr_alignment)]
970 // The pointer is page aligned so casting to a different type is well defined, hence the clippy
971 // allow attribute.
run(&mut self) -> Result<VcpuExit>972 fn run(&mut self) -> Result<VcpuExit> {
973 // SAFETY:
974 // Safe because we know that our file is a VCPU fd and we verify the return result.
975 let ret = unsafe { ioctl(self, KVM_RUN) };
976 if ret != 0 {
977 return errno_result();
978 }
979
980 // SAFETY:
981 // Safe because we know we mapped enough memory to hold the kvm_run struct because the
982 // kernel told us how large it was.
983 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
984
985 // Check for architecture-specific VM exit reasons first in case the architecture wants to
986 // override the default handling.
987 if let Some(vcpu_exit) = self.handle_vm_exit_arch(run) {
988 return Ok(vcpu_exit);
989 }
990
991 match run.exit_reason {
992 KVM_EXIT_MMIO => Ok(VcpuExit::Mmio),
993 KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception),
994 KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall),
995 KVM_EXIT_DEBUG => Ok(VcpuExit::Debug),
996 KVM_EXIT_IRQ_WINDOW_OPEN => Ok(VcpuExit::IrqWindowOpen),
997 KVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown(Ok(()))),
998 KVM_EXIT_FAIL_ENTRY => {
999 // SAFETY:
1000 // Safe because the exit_reason (which comes from the kernel) told us which
1001 // union field to use.
1002 let hardware_entry_failure_reason = unsafe {
1003 run.__bindgen_anon_1
1004 .fail_entry
1005 .hardware_entry_failure_reason
1006 };
1007 Ok(VcpuExit::FailEntry {
1008 hardware_entry_failure_reason,
1009 })
1010 }
1011 KVM_EXIT_INTR => Ok(VcpuExit::Intr),
1012 KVM_EXIT_INTERNAL_ERROR => Ok(VcpuExit::InternalError),
1013 KVM_EXIT_SYSTEM_EVENT => {
1014 // SAFETY:
1015 // Safe because we know the exit reason told us this union
1016 // field is valid
1017 let event_type = unsafe { run.__bindgen_anon_1.system_event.type_ };
1018 let event_flags =
1019 // SAFETY:
1020 // Safe because we know the exit reason told us this union
1021 // field is valid
1022 unsafe { run.__bindgen_anon_1.system_event.__bindgen_anon_1.flags };
1023 match event_type {
1024 KVM_SYSTEM_EVENT_SHUTDOWN => Ok(VcpuExit::SystemEventShutdown),
1025 KVM_SYSTEM_EVENT_RESET => self.system_event_reset(event_flags),
1026 KVM_SYSTEM_EVENT_CRASH => Ok(VcpuExit::SystemEventCrash),
1027 _ => {
1028 error!(
1029 "Unknown KVM system event {} with flags {}",
1030 event_type, event_flags
1031 );
1032 Err(Error::new(EINVAL))
1033 }
1034 }
1035 }
1036 r => panic!("unknown kvm exit reason: {}", r),
1037 }
1038 }
1039
handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()>1040 fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> {
1041 // SAFETY:
1042 // Safe because we know we mapped enough memory to hold the kvm_run struct because the
1043 // kernel told us how large it was.
1044 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1045 // Verify that the handler is called in the right context.
1046 assert!(run.exit_reason == KVM_EXIT_MMIO);
1047 // SAFETY:
1048 // Safe because the exit_reason (which comes from the kernel) told us which
1049 // union field to use.
1050 let mmio = unsafe { &mut run.__bindgen_anon_1.mmio };
1051 let address = mmio.phys_addr;
1052 let data = &mut mmio.data[..mmio.len as usize];
1053 if mmio.is_write != 0 {
1054 handle_fn(IoParams {
1055 address,
1056 operation: IoOperation::Write(data),
1057 })
1058 } else {
1059 handle_fn(IoParams {
1060 address,
1061 operation: IoOperation::Read(data),
1062 })
1063 }
1064 }
1065
handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()>1066 fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> {
1067 // SAFETY:
1068 // Safe because we know we mapped enough memory to hold the kvm_run struct because the
1069 // kernel told us how large it was.
1070 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
1071 // Verify that the handler is called in the right context.
1072 assert!(run.exit_reason == KVM_EXIT_IO);
1073 // SAFETY:
1074 // Safe because the exit_reason (which comes from the kernel) told us which
1075 // union field to use.
1076 let io = unsafe { run.__bindgen_anon_1.io };
1077 let address = u64::from(io.port);
1078 let size = usize::from(io.size);
1079 let count = io.count as usize;
1080 let data_len = count * size;
1081 let data_offset = io.data_offset as usize;
1082 assert!(data_offset + data_len <= self.run_mmap.size());
1083
1084 // SAFETY:
1085 // The data_offset is defined by the kernel to be some number of bytes into the kvm_run
1086 // structure, which we have fully mmap'd.
1087 let buffer: &mut [u8] = unsafe {
1088 std::slice::from_raw_parts_mut(
1089 (run as *mut kvm_run as *mut u8).add(data_offset),
1090 data_len,
1091 )
1092 };
1093 let data_chunks = buffer.chunks_mut(size);
1094
1095 if io.direction == KVM_EXIT_IO_IN as u8 {
1096 for data in data_chunks {
1097 handle_fn(IoParams {
1098 address,
1099 operation: IoOperation::Read(data),
1100 });
1101 }
1102 } else {
1103 debug_assert_eq!(io.direction, KVM_EXIT_IO_OUT as u8);
1104 for data in data_chunks {
1105 handle_fn(IoParams {
1106 address,
1107 operation: IoOperation::Write(data),
1108 });
1109 }
1110 }
1111
1112 Ok(())
1113 }
1114 }
1115
1116 impl KvmVcpu {
1117 /// Gets the vcpu's current "multiprocessing state".
1118 ///
1119 /// See the documentation for KVM_GET_MP_STATE. This call can only succeed after
1120 /// a call to `Vm::create_irq_chip`.
1121 ///
1122 /// Note that KVM defines the call for both x86 and s390 but we do not expect anyone
1123 /// to run crosvm on s390.
get_mp_state(&self) -> Result<kvm_mp_state>1124 pub fn get_mp_state(&self) -> Result<kvm_mp_state> {
1125 // SAFETY: trivially safe
1126 let mut state: kvm_mp_state = unsafe { std::mem::zeroed() };
1127 let ret = {
1128 // SAFETY:
1129 // Safe because we know that our file is a VCPU fd, we know the kernel will only write
1130 // the correct amount of memory to our pointer, and we verify the return
1131 // result.
1132 unsafe { ioctl_with_mut_ref(self, KVM_GET_MP_STATE, &mut state) }
1133 };
1134 if ret < 0 {
1135 return errno_result();
1136 }
1137 Ok(state)
1138 }
1139
1140 /// Sets the vcpu's current "multiprocessing state".
1141 ///
1142 /// See the documentation for KVM_SET_MP_STATE. This call can only succeed after
1143 /// a call to `Vm::create_irq_chip`.
1144 ///
1145 /// Note that KVM defines the call for both x86 and s390 but we do not expect anyone
1146 /// to run crosvm on s390.
set_mp_state(&self, state: &kvm_mp_state) -> Result<()>1147 pub fn set_mp_state(&self, state: &kvm_mp_state) -> Result<()> {
1148 let ret = {
1149 // SAFETY:
1150 // The ioctl is safe because the kernel will only read from the kvm_mp_state struct.
1151 unsafe { ioctl_with_ref(self, KVM_SET_MP_STATE, state) }
1152 };
1153 if ret < 0 {
1154 return errno_result();
1155 }
1156 Ok(())
1157 }
1158 }
1159
1160 impl AsRawDescriptor for KvmVcpu {
as_raw_descriptor(&self) -> RawDescriptor1161 fn as_raw_descriptor(&self) -> RawDescriptor {
1162 self.vcpu.as_raw_descriptor()
1163 }
1164 }
1165
1166 impl TryFrom<HypervisorCap> for KvmCap {
1167 type Error = Error;
1168
try_from(cap: HypervisorCap) -> Result<KvmCap>1169 fn try_from(cap: HypervisorCap) -> Result<KvmCap> {
1170 match cap {
1171 HypervisorCap::ArmPmuV3 => Ok(KvmCap::ArmPmuV3),
1172 HypervisorCap::ImmediateExit => Ok(KvmCap::ImmediateExit),
1173 HypervisorCap::S390UserSigp => Ok(KvmCap::S390UserSigp),
1174 HypervisorCap::TscDeadlineTimer => Ok(KvmCap::TscDeadlineTimer),
1175 HypervisorCap::UserMemory => Ok(KvmCap::UserMemory),
1176 #[cfg(target_arch = "x86_64")]
1177 HypervisorCap::Xcrs => Ok(KvmCap::Xcrs),
1178 #[cfg(target_arch = "x86_64")]
1179 HypervisorCap::CalibratedTscLeafRequired => Err(Error::new(libc::EINVAL)),
1180 HypervisorCap::StaticSwiotlbAllocationRequired => Err(Error::new(libc::EINVAL)),
1181 HypervisorCap::HypervisorInitializedBootContext => Err(Error::new(libc::EINVAL)),
1182 }
1183 }
1184 }
1185
1186 impl From<&IrqRoute> for kvm_irq_routing_entry {
from(item: &IrqRoute) -> Self1187 fn from(item: &IrqRoute) -> Self {
1188 match &item.source {
1189 IrqSource::Irqchip { chip, pin } => kvm_irq_routing_entry {
1190 gsi: item.gsi,
1191 type_: KVM_IRQ_ROUTING_IRQCHIP,
1192 u: kvm_irq_routing_entry__bindgen_ty_1 {
1193 irqchip: kvm_irq_routing_irqchip {
1194 irqchip: chip_to_kvm_chip(*chip),
1195 pin: *pin,
1196 },
1197 },
1198 ..Default::default()
1199 },
1200 IrqSource::Msi { address, data } => kvm_irq_routing_entry {
1201 gsi: item.gsi,
1202 type_: KVM_IRQ_ROUTING_MSI,
1203 u: kvm_irq_routing_entry__bindgen_ty_1 {
1204 msi: kvm_irq_routing_msi {
1205 address_lo: *address as u32,
1206 address_hi: (*address >> 32) as u32,
1207 data: *data,
1208 ..Default::default()
1209 },
1210 },
1211 ..Default::default()
1212 },
1213 }
1214 }
1215 }
1216
1217 impl From<&kvm_mp_state> for MPState {
from(item: &kvm_mp_state) -> Self1218 fn from(item: &kvm_mp_state) -> Self {
1219 match item.mp_state {
1220 KVM_MP_STATE_RUNNABLE => MPState::Runnable,
1221 KVM_MP_STATE_UNINITIALIZED => MPState::Uninitialized,
1222 KVM_MP_STATE_INIT_RECEIVED => MPState::InitReceived,
1223 KVM_MP_STATE_HALTED => MPState::Halted,
1224 KVM_MP_STATE_SIPI_RECEIVED => MPState::SipiReceived,
1225 KVM_MP_STATE_STOPPED => MPState::Stopped,
1226 state => {
1227 error!(
1228 "unrecognized kvm_mp_state {}, setting to KVM_MP_STATE_RUNNABLE",
1229 state
1230 );
1231 MPState::Runnable
1232 }
1233 }
1234 }
1235 }
1236
1237 impl From<&MPState> for kvm_mp_state {
from(item: &MPState) -> Self1238 fn from(item: &MPState) -> Self {
1239 kvm_mp_state {
1240 mp_state: match item {
1241 MPState::Runnable => KVM_MP_STATE_RUNNABLE,
1242 MPState::Uninitialized => KVM_MP_STATE_UNINITIALIZED,
1243 MPState::InitReceived => KVM_MP_STATE_INIT_RECEIVED,
1244 MPState::Halted => KVM_MP_STATE_HALTED,
1245 MPState::SipiReceived => KVM_MP_STATE_SIPI_RECEIVED,
1246 MPState::Stopped => KVM_MP_STATE_STOPPED,
1247 },
1248 }
1249 }
1250 }
1251