Skip to content

Commit 6eaa36c

Browse files
MrXinWangalxiord
authored andcommitted
Add support to flexibly configure AArch64 IPA size of the guest
As `KVM_CREATE_VM` ioctl supports configuration of AArch64 IPA size of the guest after kernel v4.20, this commit adds support to flexibly configure AArch64 IPA size of the guest in rust-vmm. Signed-off-by: Henry Wang <[email protected]>
1 parent 1072239 commit 6eaa36c

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

coverage_config_aarch64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 76.9,
2+
"coverage_score": 77.1,
33
"exclude_path": "",
44
"crate_features": ""
55
}

src/ioctls/system.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
1212
use cap::Cap;
1313
use ioctls::vm::{new_vmfd, VmFd};
1414
use ioctls::Result;
15+
#[cfg(any(target_arch = "aarch64"))]
16+
use kvm_bindings::KVM_VM_TYPE_ARM_IPA_SIZE_MASK;
1517
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1618
use kvm_bindings::{CpuId, MsrList, KVM_MAX_MSR_ENTRIES};
1719
use kvm_ioctls::*;
@@ -374,6 +376,58 @@ impl Kvm {
374376
}
375377
}
376378

379+
/// AArch64 specific function to create a VM fd using the KVM fd with flexible IPA size.
380+
///
381+
/// See the arm64 section of KVM documentation for `KVM_CREATE_VM`.
382+
/// A call to this function will also initialize the size of the vcpu mmap area using the
383+
/// `KVM_GET_VCPU_MMAP_SIZE` ioctl.
384+
///
385+
/// Note: `Cap::ArmVmIPASize` should be checked using `check_extension` before calling
386+
/// this function to determine if the host machine supports the IPA size capability.
387+
///
388+
/// # Arguments
389+
///
390+
/// * `ipa_size` - Guest VM IPA size, 32 <= ipa_size <= Host_IPA_Limit.
391+
/// The value of `Host_IPA_Limit` may be different between hardware
392+
/// implementations and can be extracted by calling `get_host_ipa_limit`.
393+
/// Possible values can be found in documentation of registers `TCR_EL2`
394+
/// and `VTCR_EL2`.
395+
///
396+
/// # Example
397+
///
398+
/// ```
399+
/// # use kvm_ioctls::{Kvm, Cap};
400+
/// let kvm = Kvm::new().unwrap();
401+
/// // Check if the ArmVmIPASize cap is supported.
402+
/// if kvm.check_extension(Cap::ArmVmIPASize) {
403+
/// let host_ipa_limit = kvm.get_host_ipa_limit();
404+
/// let vm = kvm.create_vm_with_ipa_size(host_ipa_limit as u32).unwrap();
405+
/// // Check that the VM mmap size is the same reported by `KVM_GET_VCPU_MMAP_SIZE`.
406+
/// assert!(vm.run_size() == kvm.get_vcpu_mmap_size().unwrap());
407+
/// }
408+
/// ```
409+
///
410+
#[cfg(any(target_arch = "aarch64"))]
411+
pub fn create_vm_with_ipa_size(&self, ipa_size: u32) -> Result<VmFd> {
412+
// Safe because we know `self.kvm` is a real KVM fd as this module is the only one that
413+
// create Kvm objects.
414+
let ret = unsafe {
415+
ioctl_with_val(
416+
&self.kvm,
417+
KVM_CREATE_VM(),
418+
(ipa_size & KVM_VM_TYPE_ARM_IPA_SIZE_MASK).into(),
419+
)
420+
};
421+
if ret >= 0 {
422+
// Safe because we verify the value of ret and we are the owners of the fd.
423+
let vm_file = unsafe { File::from_raw_fd(ret) };
424+
let run_mmap_size = self.get_vcpu_mmap_size()?;
425+
Ok(new_vmfd(vm_file, run_mmap_size))
426+
} else {
427+
Err(errno::Error::last())
428+
}
429+
}
430+
377431
/// Creates a VmFd object from a VM RawFd.
378432
///
379433
/// This function is unsafe as the primitives currently returned have the contract that
@@ -462,6 +516,28 @@ mod tests {
462516
assert_eq!(vm.run_size(), kvm.get_vcpu_mmap_size().unwrap());
463517
}
464518

519+
#[test]
520+
#[cfg(any(target_arch = "aarch64"))]
521+
fn test_create_vm_with_ipa_size() {
522+
let kvm = Kvm::new().unwrap();
523+
if kvm.check_extension(Cap::ArmVmIPASize) {
524+
let host_ipa_limit = kvm.get_host_ipa_limit();
525+
// Here we test with the maximum value that the host supports to both test the
526+
// discoverability of supported IPA sizes and likely some other values than 40.
527+
kvm.create_vm_with_ipa_size(host_ipa_limit as u32).unwrap();
528+
// Test invalid input values
529+
// Case 1: IPA size is smaller than 32.
530+
assert!(kvm.create_vm_with_ipa_size(31).is_err());
531+
// Case 2: IPA size is bigger than Host_IPA_Limit.
532+
assert!(kvm
533+
.create_vm_with_ipa_size((host_ipa_limit + 1) as u32)
534+
.is_err());
535+
} else {
536+
// Unsupported, here we can test with the default value 40.
537+
assert!(kvm.create_vm_with_ipa_size(40).is_err());
538+
}
539+
}
540+
465541
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
466542
#[test]
467543
fn test_get_supported_cpuid() {

0 commit comments

Comments
 (0)