use std::mem::{MaybeUninit, size_of_val};
use std::os::fd::{AsFd, BorrowedFd, FromRawFd, OwnedFd};
use snafu::ResultExt;
use crate::hv::kvm::kvm_error;
use crate::hv::kvm::vm::KvmVm;
use crate::hv::{KvmError, Result};
use crate::sys::kvm::{
KvmCreateDevice, KvmDevType, KvmDeviceAttr, kvm_create_device, kvm_get_device_attr,
kvm_set_device_attr,
};
#[derive(Debug)]
pub(super) struct KvmDevice(pub OwnedFd);
impl KvmDevice {
pub fn new(vm: &KvmVm, type_: KvmDevType) -> Result<KvmDevice, KvmError> {
let mut create_device = KvmCreateDevice {
type_,
fd: 0,
flags: 0,
};
unsafe { kvm_create_device(&vm.vm.fd, &mut create_device) }
.context(kvm_error::CreateDevice { type_ })?;
Ok(KvmDevice(unsafe { OwnedFd::from_raw_fd(create_device.fd) }))
}
}
impl AsFd for KvmDevice {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl KvmDevice {
pub fn set_attr<T>(&self, group: u32, attr: u64, val: &T) -> Result<(), KvmError> {
let attr = KvmDeviceAttr {
group,
attr,
addr: if size_of_val(val) == 0 {
0
} else {
val as *const _ as _
},
_flags: 0,
};
unsafe { kvm_set_device_attr(self, &attr) }.context(kvm_error::DeviceAttr)?;
Ok(())
}
pub fn get_attr<T>(&self, group: u32, attr: u64) -> Result<T, KvmError> {
let mut val = MaybeUninit::uninit();
let attr = KvmDeviceAttr {
group,
attr,
addr: val.as_mut_ptr() as _,
_flags: 0,
};
unsafe { kvm_get_device_attr(self, &attr) }.context(kvm_error::DeviceAttr)?;
Ok(unsafe { val.assume_init() })
}
}