diff options
author | Zach Reizner <zachr@google.com> | 2018-01-08 11:12:23 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-01-18 17:40:14 -0800 |
commit | 0335dad57e6ccf06f132a890df36f3d3ef7f3e14 (patch) | |
tree | b09d4978a7f62127440a291d5bc5509c303ec402 /kvm/src/lib.rs | |
parent | 61046bfe82c0ccf713638edfef2659d576a21f3f (diff) | |
download | crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.tar crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.tar.gz crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.tar.bz2 crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.tar.lz crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.tar.xz crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.tar.zst crosvm-0335dad57e6ccf06f132a890df36f3d3ef7f3e14.zip |
kvm: add ioeventfd and irqfd unregister support
This is needed to support the plugin API, which might unregister such eventfds. BUG=chromium:800626 TEST=./build_test Change-Id: Ic4e74ffd4b2374868644d1f6598509aba741ce00 Reviewed-on: https://chromium-review.googlesource.com/857908 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'kvm/src/lib.rs')
-rw-r--r-- | kvm/src/lib.rs | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs index cb194f8..69ad3a7 100644 --- a/kvm/src/lib.rs +++ b/kvm/src/lib.rs @@ -375,17 +375,32 @@ impl Vm { } } - /// Registers an event to be signalled whenever a certain address is written to. + /// Registers an event to be signaled whenever a certain address is written to. /// - /// The `datamatch` parameter can be used to limit singalling `evt` to only the cases where the + /// The `datamatch` parameter can be used to limit signaling `evt` to only the cases where the /// value being written is equal to `datamatch`. Note that the size of `datamatch` is important /// and must match the expected size of the guest's write. /// - /// In all cases where `evt` is signalled, the ordinary vmexit to userspace that would be + /// In all cases where `evt` is signaled, the ordinary vmexit to userspace that would be /// triggered is prevented. pub fn register_ioevent<T: Into<u64>>(&self, evt: &EventFd, addr: IoeventAddress, datamatch: T) -> Result<()> { + self.ioeventfd(evt, addr, datamatch.into(), std::mem::size_of::<T>() as u32, false) + } + + /// Unregisters an event previously registered with `register_ioevent`. + /// + /// The `evt`, `addr`, and `datamatch` set must be the same as the ones passed into + /// `register_ioevent`. + pub fn unregister_ioevent<T: Into<u64>>(&self, evt: &EventFd, addr: IoeventAddress, datamatch: T) -> Result<()> { + self.ioeventfd(evt, addr, datamatch.into(), std::mem::size_of::<T>() as u32, true) + } + + fn ioeventfd(&self, evt: &EventFd, addr: IoeventAddress, datamatch: u64, datamatch_len: u32, deassign: bool) -> Result<()> { let mut flags = 0; - if std::mem::size_of::<T>() > 0 { + if deassign { + flags |= 1 << kvm_ioeventfd_flag_nr_deassign; + } + if datamatch_len > 0 { flags |= 1 << kvm_ioeventfd_flag_nr_datamatch } match addr { @@ -393,8 +408,8 @@ impl Vm { _ => {} }; let ioeventfd = kvm_ioeventfd { - datamatch: datamatch.into(), - len: std::mem::size_of::<T>() as u32, + datamatch: datamatch, + len: datamatch_len, addr: match addr { IoeventAddress::Pio(p) => p as u64, IoeventAddress::Mmio(m) => m }, fd: evt.as_raw_fd(), flags: flags, @@ -427,6 +442,27 @@ impl Vm { errno_result() } } + + /// Unregisters an event that was previously registered with `register_irqfd`. + /// + /// The `evt` and `gsi` pair must be the same as the ones passed into `register_irqfd`. + #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm", target_arch = "aarch64"))] + pub fn unregister_irqfd(&self, evt: &EventFd, gsi: u32) -> Result<()> { + let irqfd = kvm_irqfd { + fd: evt.as_raw_fd() as u32, + gsi: gsi, + flags: KVM_IRQFD_FLAG_DEASSIGN, + ..Default::default() + }; + // Safe because we know that our file is a VM fd, we know the kernel will only read the + // correct amount of memory from our pointer, and we verify the return result. + let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD(), &irqfd) }; + if ret == 0 { + Ok(()) + } else { + errno_result() + } + } } impl AsRawFd for Vm { @@ -882,6 +918,20 @@ mod tests { } #[test] + fn unregister_ioevent() { + let kvm = Kvm::new().unwrap(); + let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); + let vm = Vm::new(&kvm, gm).unwrap(); + let evtfd = EventFd::new().unwrap(); + vm.register_ioevent(&evtfd, IoeventAddress::Pio(0xf4), NoDatamatch).unwrap(); + vm.register_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), NoDatamatch).unwrap(); + vm.register_ioevent(&evtfd, IoeventAddress::Mmio(0x1004), 0x7fu8).unwrap(); + vm.unregister_ioevent(&evtfd, IoeventAddress::Pio(0xf4), NoDatamatch).unwrap(); + vm.unregister_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), NoDatamatch).unwrap(); + vm.unregister_ioevent(&evtfd, IoeventAddress::Mmio(0x1004), 0x7fu8).unwrap(); + } + + #[test] fn register_irqfd() { let kvm = Kvm::new().unwrap(); let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); @@ -896,6 +946,22 @@ mod tests { } #[test] + fn unregister_irqfd() { + let kvm = Kvm::new().unwrap(); + let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); + let vm = Vm::new(&kvm, gm).unwrap(); + let evtfd1 = EventFd::new().unwrap(); + let evtfd2 = EventFd::new().unwrap(); + let evtfd3 = EventFd::new().unwrap(); + vm.register_irqfd(&evtfd1, 4).unwrap(); + vm.register_irqfd(&evtfd2, 8).unwrap(); + vm.register_irqfd(&evtfd3, 4).unwrap(); + vm.unregister_irqfd(&evtfd1, 4).unwrap(); + vm.unregister_irqfd(&evtfd2, 8).unwrap(); + vm.unregister_irqfd(&evtfd3, 4).unwrap(); + } + + #[test] fn create_vcpu() { let kvm = Kvm::new().unwrap(); let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); |