Skip to content

Commit bc85674

Browse files
dianpopaalxiord
authored andcommitted
Add support for KVM_GET_REG_LIST ioctl
The `KVM_GET_REG_LIST` ioctl is used to extract a list containing the id of all registers on aarch64 architecture. We need this in order to be able to save/restore them. Fixes: #104 Signed-off-by: Diana Popa <[email protected]>
1 parent d8f78a1 commit bc85674

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/ioctls/vcpu.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,46 @@ impl VcpuFd {
959959
Ok(())
960960
}
961961

962+
/// Returns the guest registers that are supported for the
963+
/// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
964+
///
965+
/// # Arguments
966+
///
967+
/// * `reg_list` - list of registers (input/output). For details check the `kvm_reg_list`
968+
/// structure in the
969+
/// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt).
970+
///
971+
/// # Example
972+
///
973+
/// ```rust
974+
/// # extern crate kvm_ioctls;
975+
/// # extern crate kvm_bindings;
976+
/// # use kvm_ioctls::Kvm;
977+
/// # use kvm_bindings::RegList;
978+
/// let kvm = Kvm::new().unwrap();
979+
/// let vm = kvm.create_vm().unwrap();
980+
/// let vcpu = vm.create_vcpu(0).unwrap();
981+
///
982+
/// // KVM_GET_REG_LIST demands that the vcpus be initalized.
983+
/// let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
984+
/// vm.get_preferred_target(&mut kvi).unwrap();
985+
/// vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu");
986+
///
987+
/// let mut reg_list = RegList::new(500);
988+
/// vcpu.get_reg_list(&mut reg_list).unwrap();
989+
/// assert!(reg_list.as_fam_struct_ref().n > 0);
990+
/// ```
991+
///
992+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
993+
pub fn get_reg_list(&self, reg_list: &mut RegList) -> Result<()> {
994+
let ret =
995+
unsafe { ioctl_with_mut_ref(self, KVM_GET_REG_LIST(), reg_list.as_mut_fam_struct()) };
996+
if ret < 0 {
997+
return Err(errno::Error::last());
998+
}
999+
Ok(())
1000+
}
1001+
9621002
/// Sets the value of one register for this vCPU.
9631003
///
9641004
/// The id of the register is encoded as specified in the kernel documentation
@@ -1838,6 +1878,35 @@ mod tests {
18381878
);
18391879
}
18401880

1881+
#[test]
1882+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
1883+
fn test_get_reg_list() {
1884+
let kvm = Kvm::new().unwrap();
1885+
let vm = kvm.create_vm().unwrap();
1886+
let vcpu = vm.create_vcpu(0).unwrap();
1887+
1888+
let mut reg_list = RegList::new(1);
1889+
// KVM_GET_REG_LIST demands that the vcpus be initalized, so we expect this to fail.
1890+
let err = vcpu.get_reg_list(&mut reg_list).unwrap_err();
1891+
assert!(err.errno() == libc::ENOEXEC);
1892+
1893+
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
1894+
vm.get_preferred_target(&mut kvi)
1895+
.expect("Cannot get preferred target");
1896+
vcpu.vcpu_init(&kvi).expect("Cannot initialize vcpu");
1897+
1898+
// KVM_GET_REG_LIST offers us a number of registers for which we have
1899+
// not allocated memory, so the first time it fails.
1900+
let err = vcpu.get_reg_list(&mut reg_list).unwrap_err();
1901+
assert!(err.errno() == libc::E2BIG);
1902+
assert!(reg_list.as_mut_fam_struct().n > 0);
1903+
1904+
// We make use of the number of registers returned to allocate memory and
1905+
// try one more time.
1906+
let mut reg_list = RegList::new(reg_list.as_mut_fam_struct().n as usize);
1907+
assert!(vcpu.get_reg_list(&mut reg_list).is_ok());
1908+
}
1909+
18411910
#[test]
18421911
fn set_kvm_immediate_exit() {
18431912
let kvm = Kvm::new().unwrap();

src/kvm_ioctls.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ ioctl_iow_nr!(KVM_SET_ONE_REG, KVMIO, 0xac, kvm_one_reg);
211211
ioctl_iow_nr!(KVM_ARM_VCPU_INIT, KVMIO, 0xae, kvm_vcpu_init);
212212
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
213213
ioctl_ior_nr!(KVM_ARM_PREFERRED_TARGET, KVMIO, 0xaf, kvm_vcpu_init);
214+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
215+
ioctl_iowr_nr!(KVM_GET_REG_LIST, KVMIO, 0xb0, kvm_reg_list);
214216

215217
// Device ioctls.
216218

0 commit comments

Comments
 (0)