kvm_ioctls/ioctls/system.rs
1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3//
4// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5// Use of this source code is governed by a BSD-style license that can be
6// found in the THIRD-PARTY file.
7use libc::{O_CLOEXEC, O_RDWR, open};
8use std::ffi::CStr;
9use std::fs::File;
10use std::os::raw::{c_char, c_ulong};
11use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
12
13use crate::cap::Cap;
14use crate::ioctls::Result;
15use crate::ioctls::vm::{VmFd, new_vmfd};
16use crate::kvm_ioctls::*;
17#[cfg(target_arch = "aarch64")]
18use kvm_bindings::KVM_VM_TYPE_ARM_IPA_SIZE_MASK;
19#[cfg(target_arch = "x86_64")]
20use kvm_bindings::{CpuId, KVM_MAX_CPUID_ENTRIES, KVM_MAX_MSR_ENTRIES, MsrList, Msrs};
21use vmm_sys_util::errno;
22#[cfg(target_arch = "x86_64")]
23use vmm_sys_util::ioctl::ioctl_with_mut_ptr;
24use vmm_sys_util::ioctl::{ioctl, ioctl_with_val};
25
26/// Wrapper over KVM system ioctls.
27#[derive(Debug)]
28pub struct Kvm {
29 kvm: File,
30}
31
32impl Kvm {
33 /// Opens `/dev/kvm` and returns a `Kvm` object on success.
34 ///
35 /// # Example
36 ///
37 /// ```
38 /// use kvm_ioctls::Kvm;
39 /// let kvm = Kvm::new().unwrap();
40 /// ```
41 #[allow(clippy::new_ret_no_self)]
42 pub fn new() -> Result<Self> {
43 // Open `/dev/kvm` using `O_CLOEXEC` flag.
44 let fd = Self::open_with_cloexec(true)?;
45 // SAFETY: Safe because we verify that the fd is valid in `open_with_cloexec` and we own
46 // the fd.
47 Ok(unsafe { Self::from_raw_fd(fd) })
48 }
49
50 /// Opens the KVM device at `kvm_path` and returns a `Kvm` object on success.
51 ///
52 /// # Arguments
53 ///
54 /// * `kvm_path`: path to the KVM device. Usually it is `/dev/kvm`.
55 ///
56 /// # Example
57 ///
58 /// ```
59 /// use kvm_ioctls::Kvm;
60 /// use std::ffi::CString;
61 /// let kvm_path = CString::new("/dev/kvm").unwrap();
62 /// let kvm = Kvm::new_with_path(&kvm_path).unwrap();
63 /// ```
64 #[allow(clippy::new_ret_no_self)]
65 pub fn new_with_path<P>(kvm_path: P) -> Result<Self>
66 where
67 P: AsRef<CStr>,
68 {
69 // Open `kvm_path` using `O_CLOEXEC` flag.
70 let fd = Self::open_with_cloexec_at(kvm_path, true)?;
71 // SAFETY: Safe because we verify that the fd is valid in `open_with_cloexec_at`
72 // and we own the fd.
73 Ok(unsafe { Self::from_raw_fd(fd) })
74 }
75
76 /// Opens `/dev/kvm` and returns the fd number on success.
77 ///
78 /// One usecase for this method is opening `/dev/kvm` before exec-ing into a
79 /// process with seccomp filters enabled that blacklist the `sys_open` syscall.
80 /// For this usecase `open_with_cloexec` must be called with the `close_on_exec`
81 /// parameter set to false.
82 ///
83 /// # Arguments
84 ///
85 /// * `close_on_exec`: If true opens `/dev/kvm` using the `O_CLOEXEC` flag.
86 ///
87 /// # Example
88 ///
89 /// ```
90 /// # use kvm_ioctls::Kvm;
91 /// # use std::os::unix::io::FromRawFd;
92 /// let kvm_fd = Kvm::open_with_cloexec(false).unwrap();
93 /// // The `kvm_fd` can now be passed to another process where we can use
94 /// // `from_raw_fd` for creating a `Kvm` object:
95 /// let kvm = unsafe { Kvm::from_raw_fd(kvm_fd) };
96 /// ```
97 pub fn open_with_cloexec(close_on_exec: bool) -> Result<RawFd> {
98 // SAFETY: Safe because we give a constant nul-terminated string.
99 let kvm_path = c"/dev/kvm";
100 Self::open_with_cloexec_at(kvm_path, close_on_exec)
101 }
102
103 /// Opens the KVM device at `kvm_path` and returns the fd number on success.
104 /// Same as [open_with_cloexec()](struct.Kvm.html#method.open_with_cloexec)
105 /// except this method opens `kvm_path` instead of `/dev/kvm`.
106 ///
107 /// # Arguments
108 ///
109 /// * `kvm_path`: path to the KVM device. Usually it is `/dev/kvm`.
110 /// * `close_on_exec`: If true opens `kvm_path` using the `O_CLOEXEC` flag.
111 ///
112 /// # Example
113 ///
114 /// ```
115 /// # use kvm_ioctls::Kvm;
116 /// # use std::ffi::CString;
117 /// # use std::os::unix::io::FromRawFd;
118 /// let kvm_path = CString::new("/dev/kvm").unwrap();
119 /// let kvm_fd = Kvm::open_with_cloexec_at(kvm_path, false).unwrap();
120 /// // The `kvm_fd` can now be passed to another process where we can use
121 /// // `from_raw_fd` for creating a `Kvm` object:
122 /// let kvm = unsafe { Kvm::from_raw_fd(kvm_fd) };
123 /// ```
124 pub fn open_with_cloexec_at<P>(path: P, close_on_exec: bool) -> Result<RawFd>
125 where
126 P: AsRef<CStr>,
127 {
128 let open_flags = O_RDWR | if close_on_exec { O_CLOEXEC } else { 0 };
129 // SAFETY: Safe because we verify the result.
130 let ret = unsafe { open(path.as_ref().as_ptr() as *const c_char, open_flags) };
131 if ret < 0 {
132 Err(errno::Error::last())
133 } else {
134 Ok(ret)
135 }
136 }
137
138 /// Returns the KVM API version.
139 ///
140 /// See the documentation for `KVM_GET_API_VERSION`.
141 ///
142 /// # Example
143 ///
144 /// ```
145 /// # use kvm_ioctls::Kvm;
146 /// let kvm = Kvm::new().unwrap();
147 /// assert_eq!(kvm.get_api_version(), 12);
148 /// ```
149 pub fn get_api_version(&self) -> i32 {
150 // SAFETY: Safe because we know that our file is a KVM fd and that the request is one of
151 // the ones defined by kernel.
152 unsafe { ioctl(self, KVM_GET_API_VERSION()) }
153 }
154
155 /// AArch64 specific call to get the host Intermediate Physical Address space limit.
156 ///
157 /// Returns 0 if the capability is not available and an integer >= 32 otherwise.
158 #[cfg(target_arch = "aarch64")]
159 pub fn get_host_ipa_limit(&self) -> i32 {
160 self.check_extension_int(Cap::ArmVmIPASize)
161 }
162
163 /// AArch64 specific call to get the number of supported hardware breakpoints.
164 ///
165 /// Returns 0 if the capability is not available and a positive integer otherwise.
166 #[cfg(target_arch = "aarch64")]
167 pub fn get_guest_debug_hw_bps(&self) -> i32 {
168 self.check_extension_int(Cap::DebugHwBps)
169 }
170
171 /// AArch64 specific call to get the number of supported hardware watchpoints.
172 ///
173 /// Returns 0 if the capability is not available and a positive integer otherwise.
174 #[cfg(target_arch = "aarch64")]
175 pub fn get_guest_debug_hw_wps(&self) -> i32 {
176 self.check_extension_int(Cap::DebugHwWps)
177 }
178
179 /// Wrapper over `KVM_CHECK_EXTENSION`.
180 ///
181 /// Returns 0 if the capability is not available and a positive integer otherwise.
182 /// See the documentation for `KVM_CHECK_EXTENSION`.
183 ///
184 /// # Arguments
185 ///
186 /// * `c` - KVM capability to check in a form of a raw integer.
187 ///
188 /// # Example
189 ///
190 /// ```
191 /// # use kvm_ioctls::Kvm;
192 /// # use std::os::raw::c_ulong;
193 /// use kvm_ioctls::Cap;
194 ///
195 /// let kvm = Kvm::new().unwrap();
196 /// assert!(kvm.check_extension_raw(Cap::MaxVcpus as c_ulong) > 0);
197 /// ```
198 pub fn check_extension_raw(&self, c: c_ulong) -> i32 {
199 // SAFETY: Safe because we know that our file is a KVM fd.
200 // If `c` is not a known kernel extension, kernel will return 0.
201 unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION(), c) }
202 }
203
204 /// Wrapper over `KVM_CHECK_EXTENSION`.
205 ///
206 /// Returns 0 if the capability is not available and a positive integer otherwise.
207 /// See the documentation for `KVM_CHECK_EXTENSION`.
208 ///
209 /// # Arguments
210 ///
211 /// * `c` - KVM capability to check.
212 ///
213 /// # Example
214 ///
215 /// ```
216 /// # use kvm_ioctls::Kvm;
217 /// use kvm_ioctls::Cap;
218 ///
219 /// let kvm = Kvm::new().unwrap();
220 /// assert!(kvm.check_extension_int(Cap::MaxVcpus) > 0);
221 /// ```
222 pub fn check_extension_int(&self, c: Cap) -> i32 {
223 self.check_extension_raw(c as c_ulong)
224 }
225
226 /// Checks if a particular `Cap` is available.
227 ///
228 /// Returns true if the capability is supported and false otherwise.
229 /// See the documentation for `KVM_CHECK_EXTENSION`.
230 ///
231 /// # Arguments
232 ///
233 /// * `c` - KVM capability to check.
234 ///
235 /// # Example
236 ///
237 /// ```
238 /// # use kvm_ioctls::Kvm;
239 /// use kvm_ioctls::Cap;
240 ///
241 /// let kvm = Kvm::new().unwrap();
242 /// // Check if `KVM_CAP_USER_MEMORY` is supported.
243 /// assert!(kvm.check_extension(Cap::UserMemory));
244 /// ```
245 pub fn check_extension(&self, c: Cap) -> bool {
246 self.check_extension_int(c) > 0
247 }
248
249 /// Returns the size of the memory mapping required to use the vcpu's `kvm_run` structure.
250 ///
251 /// See the documentation for `KVM_GET_VCPU_MMAP_SIZE`.
252 ///
253 /// # Example
254 ///
255 /// ```
256 /// # use kvm_ioctls::Kvm;
257 /// let kvm = Kvm::new().unwrap();
258 /// assert!(kvm.get_vcpu_mmap_size().unwrap() > 0);
259 /// ```
260 pub fn get_vcpu_mmap_size(&self) -> Result<usize> {
261 // SAFETY: Safe because we know that our file is a KVM fd and we verify the return result.
262 let res = unsafe { ioctl(self, KVM_GET_VCPU_MMAP_SIZE()) };
263 if res > 0 {
264 Ok(res as usize)
265 } else {
266 Err(errno::Error::last())
267 }
268 }
269
270 /// Gets the recommended number of VCPUs per VM.
271 ///
272 /// See the documentation for `KVM_CAP_NR_VCPUS`.
273 /// Default to 4 when `KVM_CAP_NR_VCPUS` is not implemented.
274 ///
275 /// # Example
276 ///
277 /// ```
278 /// # use kvm_ioctls::Kvm;
279 /// let kvm = Kvm::new().unwrap();
280 /// // We expect the number of vCPUs to be > 0 as per KVM API documentation.
281 /// assert!(kvm.get_nr_vcpus() > 0);
282 /// ```
283 pub fn get_nr_vcpus(&self) -> usize {
284 let x = self.check_extension_int(Cap::NrVcpus);
285 if x > 0 { x as usize } else { 4 }
286 }
287
288 /// Returns the maximum allowed memory slots per VM.
289 ///
290 /// KVM reports the number of available memory slots (`KVM_CAP_NR_MEMSLOTS`)
291 /// using the extension interface. Both x86 and s390 implement this, ARM
292 /// and powerpc do not yet enable it.
293 /// Default to 32 when `KVM_CAP_NR_MEMSLOTS` is not implemented.
294 ///
295 /// # Example
296 ///
297 /// ```
298 /// # use kvm_ioctls::Kvm;
299 /// let kvm = Kvm::new().unwrap();
300 /// assert!(kvm.get_nr_memslots() > 0);
301 /// ```
302 pub fn get_nr_memslots(&self) -> usize {
303 let x = self.check_extension_int(Cap::NrMemslots);
304 if x > 0 { x as usize } else { 32 }
305 }
306
307 /// Gets the recommended maximum number of VCPUs per VM.
308 ///
309 /// See the documentation for `KVM_CAP_MAX_VCPUS`.
310 /// Returns [get_nr_vcpus()](struct.Kvm.html#method.get_nr_vcpus) when
311 /// `KVM_CAP_MAX_VCPUS` is not implemented.
312 ///
313 /// # Example
314 ///
315 /// ```
316 /// # use kvm_ioctls::Kvm;
317 /// let kvm = Kvm::new().unwrap();
318 /// assert!(kvm.get_max_vcpus() > 0);
319 /// ```
320 pub fn get_max_vcpus(&self) -> usize {
321 match self.check_extension_int(Cap::MaxVcpus) {
322 0 => self.get_nr_vcpus(),
323 x => x as usize,
324 }
325 }
326
327 /// Gets the Maximum VCPU ID per VM.
328 ///
329 /// See the documentation for `KVM_CAP_MAX_VCPU_ID`
330 /// Returns [get_max_vcpus()](struct.Kvm.html#method.get_max_vcpus) when
331 /// `KVM_CAP_MAX_VCPU_ID` is not implemented
332 ///
333 /// # Example
334 ///
335 /// ```
336 /// # use kvm_ioctls::Kvm;
337 /// let kvm = Kvm::new().unwrap();
338 /// assert!(kvm.get_max_vcpu_id() > 0);
339 /// ```
340 pub fn get_max_vcpu_id(&self) -> usize {
341 match self.check_extension_int(Cap::MaxVcpuId) {
342 0 => self.get_max_vcpus(),
343 x => x as usize,
344 }
345 }
346
347 #[cfg(target_arch = "x86_64")]
348 fn get_cpuid(&self, kind: u64, num_entries: usize) -> Result<CpuId> {
349 if num_entries > KVM_MAX_CPUID_ENTRIES {
350 // Returns the same error the underlying `ioctl` would have sent.
351 return Err(errno::Error::new(libc::ENOMEM));
352 }
353
354 let mut cpuid = CpuId::new(num_entries).map_err(|_| errno::Error::new(libc::ENOMEM))?;
355 // SAFETY: The kernel is trusted not to write beyond the bounds of the memory
356 // allocated for the struct. The limit is read from nent, which is set to the allocated
357 // size(num_entries) above.
358 let ret = unsafe { ioctl_with_mut_ptr(self, kind, cpuid.as_mut_fam_struct_ptr()) };
359 if ret < 0 {
360 return Err(errno::Error::last());
361 }
362
363 Ok(cpuid)
364 }
365
366 /// X86 specific call to get the system emulated CPUID values.
367 ///
368 /// See the documentation for `KVM_GET_EMULATED_CPUID`.
369 ///
370 /// # Arguments
371 ///
372 /// * `num_entries` - Maximum number of CPUID entries. This function can return less than
373 /// this when the hardware does not support so many CPUID entries.
374 ///
375 /// Returns Error `errno::Error(libc::ENOMEM)` when the input `num_entries` is greater than
376 /// `KVM_MAX_CPUID_ENTRIES`.
377 ///
378 /// # Example
379 ///
380 /// ```
381 /// extern crate kvm_bindings;
382 /// use kvm_bindings::KVM_MAX_CPUID_ENTRIES;
383 /// use kvm_ioctls::Kvm;
384 ///
385 /// let kvm = Kvm::new().unwrap();
386 /// let mut cpuid = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap();
387 /// let cpuid_entries = cpuid.as_mut_slice();
388 /// assert!(cpuid_entries.len() <= KVM_MAX_CPUID_ENTRIES);
389 /// ```
390 #[cfg(target_arch = "x86_64")]
391 pub fn get_emulated_cpuid(&self, num_entries: usize) -> Result<CpuId> {
392 self.get_cpuid(KVM_GET_EMULATED_CPUID(), num_entries)
393 }
394
395 /// X86 specific call to get the system supported CPUID values.
396 ///
397 /// See the documentation for `KVM_GET_SUPPORTED_CPUID`.
398 ///
399 /// # Arguments
400 ///
401 /// * `num_entries` - Maximum number of CPUID entries. This function can return less than
402 /// this when the hardware does not support so many CPUID entries.
403 ///
404 /// Returns Error `errno::Error(libc::ENOMEM)` when the input `num_entries` is greater than
405 /// `KVM_MAX_CPUID_ENTRIES`.
406 ///
407 /// # Example
408 ///
409 /// ```
410 /// extern crate kvm_bindings;
411 /// use kvm_bindings::KVM_MAX_CPUID_ENTRIES;
412 /// use kvm_ioctls::Kvm;
413 ///
414 /// let kvm = Kvm::new().unwrap();
415 /// let mut cpuid = kvm.get_supported_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap();
416 /// let cpuid_entries = cpuid.as_mut_slice();
417 /// assert!(cpuid_entries.len() <= KVM_MAX_CPUID_ENTRIES);
418 /// ```
419 #[cfg(target_arch = "x86_64")]
420 pub fn get_supported_cpuid(&self, num_entries: usize) -> Result<CpuId> {
421 self.get_cpuid(KVM_GET_SUPPORTED_CPUID(), num_entries)
422 }
423
424 /// X86 specific call to get list of supported MSRS
425 ///
426 /// See the documentation for `KVM_GET_MSR_INDEX_LIST`.
427 ///
428 /// # Example
429 ///
430 /// ```
431 /// use kvm_ioctls::Kvm;
432 ///
433 /// let kvm = Kvm::new().unwrap();
434 /// let msr_index_list = kvm.get_msr_index_list().unwrap();
435 /// ```
436 #[cfg(target_arch = "x86_64")]
437 pub fn get_msr_index_list(&self) -> Result<MsrList> {
438 let mut msr_list =
439 MsrList::new(KVM_MAX_MSR_ENTRIES).map_err(|_| errno::Error::new(libc::ENOMEM))?;
440
441 // SAFETY: The kernel is trusted not to write beyond the bounds of the memory
442 // allocated for the struct. The limit is read from nmsrs, which is set to the allocated
443 // size (KVM_MAX_MSR_ENTRIES) above.
444 let ret = unsafe {
445 ioctl_with_mut_ptr(
446 self,
447 KVM_GET_MSR_INDEX_LIST(),
448 msr_list.as_mut_fam_struct_ptr(),
449 )
450 };
451 if ret < 0 {
452 return Err(errno::Error::last());
453 }
454
455 // The ioctl will also update the internal `nmsrs` with the actual count.
456 Ok(msr_list)
457 }
458
459 /// X86 specific call to get a list of MSRs that can be passed to the KVM_GET_MSRS system ioctl.
460 ///
461 /// See the documentation for `KVM_GET_MSR_FEATURE_INDEX_LIST`.
462 ///
463 /// # Example
464 ///
465 /// ```
466 /// use kvm_bindings::{Msrs, kvm_msr_entry};
467 /// use kvm_ioctls::Kvm;
468 ///
469 /// let kvm = Kvm::new().unwrap();
470 /// let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap();
471 /// ```
472 #[cfg(target_arch = "x86_64")]
473 pub fn get_msr_feature_index_list(&self) -> Result<MsrList> {
474 let mut msr_list =
475 MsrList::new(KVM_MAX_MSR_ENTRIES).map_err(|_| errno::Error::new(libc::ENOMEM))?;
476
477 // SAFETY: The kernel is trusted not to write beyond the bounds of the memory
478 // allocated for the struct. The limit is read from nmsrs, which is set to the allocated
479 // size (KVM_MAX_MSR_ENTRIES) above.
480 let ret = unsafe {
481 ioctl_with_mut_ptr(
482 self,
483 KVM_GET_MSR_FEATURE_INDEX_LIST(),
484 msr_list.as_mut_fam_struct_ptr(),
485 )
486 };
487 if ret < 0 {
488 return Err(errno::Error::last());
489 }
490
491 Ok(msr_list)
492 }
493
494 /// X86 specific call to read the values of MSR-based features that are available for the VM.
495 /// As opposed to `VcpuFd::get_msrs()`, this call returns all the MSRs supported by the
496 /// system, similar to `get_supported_cpuid()` for CPUID.
497 ///
498 /// See the documentation for `KVM_GET_MSRS`.
499 ///
500 /// # Arguments
501 ///
502 /// * `msrs` - MSRs (input/output). For details check the `kvm_msrs` structure in the
503 /// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt).
504 ///
505 /// # Example
506 ///
507 /// ```
508 /// use kvm_bindings::{Msrs, kvm_msr_entry};
509 /// use kvm_ioctls::Kvm;
510 ///
511 /// let kvm = Kvm::new().unwrap();
512 /// let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap();
513 /// let mut msrs = Msrs::from_entries(
514 /// &msr_feature_index_list
515 /// .as_slice()
516 /// .iter()
517 /// .map(|&idx| kvm_msr_entry {
518 /// index: idx,
519 /// ..Default::default()
520 /// })
521 /// .collect::<Vec<_>>(),
522 /// )
523 /// .unwrap();
524 /// let ret = kvm.get_msrs(&mut msrs).unwrap();
525 /// ```
526 #[cfg(target_arch = "x86_64")]
527 pub fn get_msrs(&self, msrs: &mut Msrs) -> Result<usize> {
528 // SAFETY: Here we trust the kernel not to read past the end of the kvm_msrs struct.
529 let ret = unsafe { ioctl_with_mut_ptr(self, KVM_GET_MSRS(), msrs.as_mut_fam_struct_ptr()) };
530 if ret < 0 {
531 return Err(errno::Error::last());
532 }
533 Ok(ret as usize)
534 }
535
536 /// Creates a VM fd using the KVM fd.
537 ///
538 /// See the documentation for `KVM_CREATE_VM`.
539 /// A call to this function will also initialize the size of the vcpu mmap area using the
540 /// `KVM_GET_VCPU_MMAP_SIZE` ioctl.
541 ///
542 /// # Example
543 ///
544 /// ```
545 /// # use kvm_ioctls::Kvm;
546 /// let kvm = Kvm::new().unwrap();
547 /// let vm = kvm.create_vm().unwrap();
548 /// // Check that the VM mmap size is the same reported by `KVM_GET_VCPU_MMAP_SIZE`.
549 /// assert!(vm.run_size() == kvm.get_vcpu_mmap_size().unwrap());
550 /// ```
551 #[cfg(not(target_arch = "aarch64"))]
552 pub fn create_vm(&self) -> Result<VmFd> {
553 self.create_vm_with_type(0) // Create using default VM type
554 }
555
556 /// AArch64 specific create_vm to create a VM fd using the KVM fd using the host's maximum IPA size.
557 ///
558 /// See the arm64 section of KVM documentation for `KVM_CREATE_VM`.
559 /// A call to this function will also initialize the size of the vcpu mmap area using the
560 /// `KVM_GET_VCPU_MMAP_SIZE` ioctl.
561 ///
562 /// # Example
563 ///
564 /// ```
565 /// # use kvm_ioctls::Kvm;
566 /// let kvm = Kvm::new().unwrap();
567 /// let vm = kvm.create_vm().unwrap();
568 /// // Check that the VM mmap size is the same reported by `KVM_GET_VCPU_MMAP_SIZE`.
569 /// assert_eq!(vm.run_size(), kvm.get_vcpu_mmap_size().unwrap());
570 /// ```
571 #[cfg(target_arch = "aarch64")]
572 pub fn create_vm(&self) -> Result<VmFd> {
573 let mut ipa_size = 0; // Create using default VM type
574 if self.check_extension(Cap::ArmVmIPASize) {
575 ipa_size = self.get_host_ipa_limit();
576 }
577 self.create_vm_with_type(ipa_size as u64)
578 }
579
580 /// AArch64 specific function to create a VM fd using the KVM fd with flexible IPA size.
581 ///
582 /// See the arm64 section of KVM documentation for `KVM_CREATE_VM`.
583 /// A call to this function will also initialize the size of the vcpu mmap area using the
584 /// `KVM_GET_VCPU_MMAP_SIZE` ioctl.
585 ///
586 /// Note: `Cap::ArmVmIPASize` should be checked using `check_extension` before calling
587 /// this function to determine if the host machine supports the IPA size capability.
588 ///
589 /// # Arguments
590 ///
591 /// * `ipa_size` - Guest VM IPA size, 32 <= ipa_size <= Host_IPA_Limit.
592 /// The value of `Host_IPA_Limit` may be different between hardware
593 /// implementations and can be extracted by calling `get_host_ipa_limit`.
594 /// Possible values can be found in documentation of registers `TCR_EL2`
595 /// and `VTCR_EL2`.
596 ///
597 /// # Example
598 ///
599 /// ```
600 /// # use kvm_ioctls::{Kvm, Cap};
601 /// let kvm = Kvm::new().unwrap();
602 /// // Check if the ArmVmIPASize cap is supported.
603 /// if kvm.check_extension(Cap::ArmVmIPASize) {
604 /// let host_ipa_limit = kvm.get_host_ipa_limit();
605 /// let vm = kvm.create_vm_with_ipa_size(host_ipa_limit as u32).unwrap();
606 /// // Check that the VM mmap size is the same reported by `KVM_GET_VCPU_MMAP_SIZE`.
607 /// assert_eq!(vm.run_size(), kvm.get_vcpu_mmap_size().unwrap());
608 /// }
609 /// ```
610 #[cfg(target_arch = "aarch64")]
611 pub fn create_vm_with_ipa_size(&self, ipa_size: u32) -> Result<VmFd> {
612 self.create_vm_with_type((ipa_size & KVM_VM_TYPE_ARM_IPA_SIZE_MASK).into())
613 }
614
615 /// Creates a VM fd using the KVM fd of a specific type.
616 ///
617 /// See the documentation for `KVM_CREATE_VM`.
618 /// A call to this function will also initialize the size of the vcpu mmap area using the
619 /// `KVM_GET_VCPU_MMAP_SIZE` ioctl.
620 ///
621 /// * `vm_type` - Platform and architecture specific platform VM type. A value of 0 is the equivalent
622 /// to using the default VM type.
623 /// # Example
624 ///
625 /// ```
626 /// # use kvm_ioctls::Kvm;
627 /// let kvm = Kvm::new().unwrap();
628 /// let vm = kvm.create_vm_with_type(0).unwrap();
629 /// // Check that the VM mmap size is the same reported by `KVM_GET_VCPU_MMAP_SIZE`.
630 /// assert_eq!(vm.run_size(), kvm.get_vcpu_mmap_size().unwrap());
631 /// ```
632 pub fn create_vm_with_type(&self, vm_type: u64) -> Result<VmFd> {
633 // SAFETY: Safe because we know `self.kvm` is a real KVM fd as this module is the only one
634 // that create Kvm objects.
635 let ret = unsafe { ioctl_with_val(&self.kvm, KVM_CREATE_VM(), vm_type) };
636 if ret >= 0 {
637 // SAFETY: Safe because we verify the value of ret and we are the owners of the fd.
638 let vm_file = unsafe { File::from_raw_fd(ret) };
639 let run_mmap_size = self.get_vcpu_mmap_size()?;
640 Ok(new_vmfd(vm_file, run_mmap_size))
641 } else {
642 Err(errno::Error::last())
643 }
644 }
645
646 /// Creates a VmFd object from a VM RawFd.
647 ///
648 /// # Arguments
649 ///
650 /// * `fd` - the RawFd used for creating the VmFd object.
651 ///
652 /// # Safety
653 ///
654 /// This function is unsafe as the primitives currently returned have the contract that
655 /// they are the sole owner of the file descriptor they are wrapping. Usage of this function
656 /// could accidentally allow violating this contract which can cause memory unsafety in code
657 /// that relies on it being true.
658 ///
659 /// The caller of this method must make sure the fd is valid and nothing else uses it.
660 ///
661 /// # Example
662 ///
663 /// ```rust
664 /// # extern crate kvm_ioctls;
665 /// # use std::os::unix::io::AsRawFd;
666 /// # use kvm_ioctls::Kvm;
667 /// let kvm = Kvm::new().unwrap();
668 /// let vm = kvm.create_vm().unwrap();
669 /// let rawfd = unsafe { libc::dup(vm.as_raw_fd()) };
670 /// assert!(rawfd >= 0);
671 /// let vm = unsafe { kvm.create_vmfd_from_rawfd(rawfd).unwrap() };
672 /// ```
673 pub unsafe fn create_vmfd_from_rawfd(&self, fd: RawFd) -> Result<VmFd> {
674 let run_mmap_size = self.get_vcpu_mmap_size()?;
675 // SAFETY: we trust the kernel and verified parameters
676 Ok(new_vmfd(unsafe { File::from_raw_fd(fd) }, run_mmap_size))
677 }
678}
679
680impl AsRawFd for Kvm {
681 fn as_raw_fd(&self) -> RawFd {
682 self.kvm.as_raw_fd()
683 }
684}
685
686impl FromRawFd for Kvm {
687 /// Creates a new Kvm object assuming `fd` represents an existing open file descriptor
688 /// associated with `/dev/kvm`.
689 ///
690 /// For usage examples check [open_with_cloexec()](struct.Kvm.html#method.open_with_cloexec).
691 ///
692 /// # Arguments
693 ///
694 /// * `fd` - File descriptor for `/dev/kvm`.
695 ///
696 /// # Safety
697 ///
698 /// This function is unsafe as the primitives currently returned have the contract that
699 /// they are the sole owner of the file descriptor they are wrapping. Usage of this function
700 /// could accidentally allow violating this contract which can cause memory unsafety in code
701 /// that relies on it being true.
702 ///
703 /// The caller of this method must make sure the fd is valid and nothing else uses it.
704 ///
705 /// # Example
706 ///
707 /// ```
708 /// # use kvm_ioctls::Kvm;
709 /// # use std::os::unix::io::FromRawFd;
710 /// let kvm_fd = Kvm::open_with_cloexec(true).unwrap();
711 /// // Safe because we verify that the fd is valid in `open_with_cloexec` and we own the fd.
712 /// let kvm = unsafe { Kvm::from_raw_fd(kvm_fd) };
713 /// ```
714 unsafe fn from_raw_fd(fd: RawFd) -> Self {
715 Kvm {
716 // SAFETY: we trust the kernel and verified parameters
717 kvm: unsafe { File::from_raw_fd(fd) },
718 }
719 }
720}
721
722#[cfg(test)]
723mod tests {
724 #![allow(clippy::undocumented_unsafe_blocks)]
725 use super::*;
726 use libc::{F_GETFD, FD_CLOEXEC, fcntl};
727 use std::os::fd::IntoRawFd;
728 #[cfg(target_arch = "x86_64")]
729 use vmm_sys_util::fam::FamStruct;
730
731 #[test]
732 fn test_kvm_new() {
733 Kvm::new().unwrap();
734 }
735
736 #[test]
737 fn test_kvm_new_with_path() {
738 let kvm_path = c"/dev/kvm";
739 Kvm::new_with_path(kvm_path).unwrap();
740 }
741
742 #[test]
743 fn test_open_with_cloexec() {
744 let fd = Kvm::open_with_cloexec(false).unwrap();
745 let flags = unsafe { fcntl(fd, F_GETFD, 0) };
746 assert_eq!(flags & FD_CLOEXEC, 0);
747 let fd = Kvm::open_with_cloexec(true).unwrap();
748 let flags = unsafe { fcntl(fd, F_GETFD, 0) };
749 assert_eq!(flags & FD_CLOEXEC, FD_CLOEXEC);
750 }
751
752 #[test]
753 fn test_open_with_cloexec_at() {
754 let kvm_path = std::ffi::CString::new("/dev/kvm").unwrap();
755 let fd = Kvm::open_with_cloexec_at(&kvm_path, false).unwrap();
756 let flags = unsafe { fcntl(fd, F_GETFD, 0) };
757 assert_eq!(flags & FD_CLOEXEC, 0);
758 let fd = Kvm::open_with_cloexec_at(&kvm_path, true).unwrap();
759 let flags = unsafe { fcntl(fd, F_GETFD, 0) };
760 assert_eq!(flags & FD_CLOEXEC, FD_CLOEXEC);
761 }
762
763 #[test]
764 fn test_kvm_api_version() {
765 let kvm = Kvm::new().unwrap();
766 assert_eq!(kvm.get_api_version(), 12);
767 assert!(kvm.check_extension(Cap::UserMemory));
768 }
769
770 #[test]
771 fn test_kvm_check_extension() {
772 let kvm = Kvm::new().unwrap();
773 // unsupported extension will return 0
774 assert_eq!(kvm.check_extension_raw(696969), 0);
775 }
776
777 #[test]
778 #[cfg(target_arch = "aarch64")]
779 fn test_get_host_ipa_limit() {
780 let kvm = Kvm::new().unwrap();
781 let host_ipa_limit = kvm.get_host_ipa_limit();
782
783 if host_ipa_limit > 0 {
784 assert!(host_ipa_limit >= 32);
785 } else {
786 // if unsupported, the return value should be 0.
787 assert_eq!(host_ipa_limit, 0);
788 }
789 }
790
791 #[test]
792 #[cfg(target_arch = "aarch64")]
793 fn test_guest_debug_hw_capacity() {
794 let kvm = Kvm::new().unwrap();
795 // The number of supported breakpoints and watchpoints may vary on
796 // different platforms.
797 // It could be 0 if no supported, or any positive integer otherwise.
798 assert!(kvm.get_guest_debug_hw_bps() >= 0);
799 assert!(kvm.get_guest_debug_hw_wps() >= 0);
800 }
801
802 #[test]
803 fn test_kvm_getters() {
804 let kvm = Kvm::new().unwrap();
805
806 // vCPU related getters
807 let nr_vcpus = kvm.get_nr_vcpus();
808 assert!(nr_vcpus >= 4);
809
810 assert!(kvm.get_max_vcpus() >= nr_vcpus);
811
812 // Memory related getters
813 assert!(kvm.get_vcpu_mmap_size().unwrap() > 0);
814 assert!(kvm.get_nr_memslots() >= 32);
815 }
816
817 #[test]
818 fn test_create_vm() {
819 let kvm = Kvm::new().unwrap();
820 let vm = kvm.create_vm().unwrap();
821
822 // Test create_vmfd_from_rawfd()
823 let rawfd = unsafe { libc::dup(vm.as_raw_fd()) };
824 assert!(rawfd >= 0);
825 let vm = unsafe { kvm.create_vmfd_from_rawfd(rawfd).unwrap() };
826
827 assert_eq!(vm.run_size(), kvm.get_vcpu_mmap_size().unwrap());
828 }
829
830 #[test]
831 fn test_create_vm_with_type() {
832 let kvm = Kvm::new().unwrap();
833 let vm = kvm.create_vm_with_type(0).unwrap();
834
835 // Test create_vmfd_from_rawfd()
836 let rawfd = unsafe { libc::dup(vm.as_raw_fd()) };
837 assert!(rawfd >= 0);
838 let vm = unsafe { kvm.create_vmfd_from_rawfd(rawfd).unwrap() };
839
840 assert_eq!(vm.run_size(), kvm.get_vcpu_mmap_size().unwrap());
841 }
842
843 #[test]
844 #[cfg(target_arch = "aarch64")]
845 fn test_create_vm_with_ipa_size() {
846 let kvm = Kvm::new().unwrap();
847 if kvm.check_extension(Cap::ArmVmIPASize) {
848 let host_ipa_limit = kvm.get_host_ipa_limit();
849 // Here we test with the maximum value that the host supports to both test the
850 // discoverability of supported IPA sizes and likely some other values than 40.
851 kvm.create_vm_with_ipa_size(host_ipa_limit as u32).unwrap();
852 // Test invalid input values
853 // Case 1: IPA size is smaller than 32.
854 kvm.create_vm_with_ipa_size(31).unwrap_err();
855 // Case 2: IPA size is bigger than Host_IPA_Limit.
856 kvm.create_vm_with_ipa_size((host_ipa_limit + 1) as u32)
857 .unwrap_err();
858 } else {
859 // Unsupported, we can't provide an IPA size. Only KVM type=0 works.
860 kvm.create_vm_with_type(0).unwrap_err();
861 }
862 }
863
864 #[cfg(target_arch = "x86_64")]
865 #[test]
866 fn test_get_supported_cpuid() {
867 let kvm = Kvm::new().unwrap();
868 let mut cpuid = kvm.get_supported_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap();
869 let cpuid_entries = cpuid.as_mut_slice();
870 assert!(!cpuid_entries.is_empty());
871 assert!(cpuid_entries.len() <= KVM_MAX_CPUID_ENTRIES);
872
873 // Test case for more than MAX entries
874 let cpuid_err = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES + 1_usize);
875 cpuid_err.unwrap_err();
876 }
877
878 #[test]
879 #[cfg(target_arch = "x86_64")]
880 fn test_get_emulated_cpuid() {
881 let kvm = Kvm::new().unwrap();
882 let mut cpuid = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap();
883 let cpuid_entries = cpuid.as_mut_slice();
884 assert!(!cpuid_entries.is_empty());
885 assert!(cpuid_entries.len() <= KVM_MAX_CPUID_ENTRIES);
886
887 // Test case for more than MAX entries
888 let cpuid_err = kvm.get_emulated_cpuid(KVM_MAX_CPUID_ENTRIES + 1_usize);
889 cpuid_err.unwrap_err();
890 }
891
892 #[cfg(target_arch = "x86_64")]
893 #[test]
894 fn test_cpuid_clone() {
895 let kvm = Kvm::new().unwrap();
896
897 // Test from_raw_fd()
898 let rawfd = unsafe { libc::dup(kvm.as_raw_fd()) };
899 assert!(rawfd >= 0);
900 let kvm = unsafe { Kvm::from_raw_fd(rawfd) };
901
902 let cpuid_1 = kvm.get_supported_cpuid(KVM_MAX_CPUID_ENTRIES).unwrap();
903 let _ = CpuId::new(cpuid_1.as_fam_struct_ref().len()).unwrap();
904 }
905
906 #[test]
907 #[cfg(target_arch = "x86_64")]
908 fn get_msr_index_list() {
909 let kvm = Kvm::new().unwrap();
910 let msr_list = kvm.get_msr_index_list().unwrap();
911 assert!(msr_list.as_slice().len() >= 2);
912 }
913
914 #[test]
915 #[cfg(target_arch = "x86_64")]
916 fn get_msr_feature_index_list() {
917 let kvm = Kvm::new().unwrap();
918 let msr_feature_index_list = kvm.get_msr_feature_index_list().unwrap();
919 assert!(!msr_feature_index_list.as_slice().is_empty());
920 }
921
922 #[test]
923 #[cfg(target_arch = "x86_64")]
924 fn get_msrs() {
925 use kvm_bindings::kvm_msr_entry;
926
927 let kvm = Kvm::new().unwrap();
928 let mut msrs = Msrs::from_entries(&[
929 kvm_msr_entry {
930 index: 0x0000010a, // MSR_IA32_ARCH_CAPABILITIES
931 ..Default::default()
932 },
933 kvm_msr_entry {
934 index: 0x00000345, // MSR_IA32_PERF_CAPABILITIES
935 ..Default::default()
936 },
937 ])
938 .unwrap();
939 let nmsrs = kvm.get_msrs(&mut msrs).unwrap();
940
941 assert_eq!(nmsrs, 2);
942 }
943
944 #[test]
945 fn test_bad_kvm_fd() {
946 let badf_errno = libc::EBADF;
947
948 let faulty_kvm = Kvm {
949 kvm: unsafe { File::from_raw_fd(-2) },
950 };
951
952 assert_eq!(
953 faulty_kvm.get_vcpu_mmap_size().unwrap_err().errno(),
954 badf_errno
955 );
956 assert_eq!(faulty_kvm.get_nr_vcpus(), 4);
957 assert_eq!(faulty_kvm.get_nr_memslots(), 32);
958 #[cfg(target_arch = "x86_64")]
959 {
960 assert_eq!(
961 faulty_kvm.get_emulated_cpuid(4).err().unwrap().errno(),
962 badf_errno
963 );
964 assert_eq!(
965 faulty_kvm.get_supported_cpuid(4).err().unwrap().errno(),
966 badf_errno
967 );
968
969 assert_eq!(
970 faulty_kvm.get_msr_index_list().err().unwrap().errno(),
971 badf_errno
972 );
973 }
974 assert_eq!(faulty_kvm.create_vm().err().unwrap().errno(), badf_errno);
975
976 // Don't drop the File object, or it'll notice the file it's trying to close is
977 // invalid and abort the process.
978 let _ = faulty_kvm.kvm.into_raw_fd();
979 }
980}