From 2515b756302235e69fbc1b07ae70270be204a91d Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Thu, 19 Sep 2019 10:29:02 +0800 Subject: vm_control: Add VmIrqRequest Socket When vfio device's msi/msi-x or virtio device's msi-x is enabled, its irq routing info should be notified to kvm. But this is a runtime vm service call, so vm_control is used to call vm service. VmIrqRequest->AllocateOneMsi() is used to allocate one gsi for a msi and a msi-x vector, and link gsi with irqfd through vm->register_irqfd. The orignal interrupt_evt and interrupt_resample_interrupt is used for INTX only. VmIrqRequest->AddMsiRoute is used to add msi routing info into kvm route table. BUG=chromium:992270 TEST=none Change-Id: I4f1beeb791943e09d957573dd2a58d55bf895d16 Signed-off-by: Xiong Zhang Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1846603 Reviewed-by: Daniel Verkamp Reviewed-by: Zach Reizner Tested-by: kokoro Commit-Queue: Xiong Zhang --- src/linux.rs | 21 ++++++++++++++- vm_control/src/lib.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/linux.rs b/src/linux.rs index bf78eb2..c761240 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -53,7 +53,7 @@ use vhost; use vm_control::{ BalloonControlCommand, BalloonControlRequestSocket, BalloonControlResponseSocket, DiskControlCommand, DiskControlRequestSocket, DiskControlResponseSocket, DiskControlResult, - UsbControlSocket, VmControlResponseSocket, VmMemoryControlRequestSocket, + UsbControlSocket, VmControlResponseSocket, VmIrqResponseSocket, VmMemoryControlRequestSocket, VmMemoryControlResponseSocket, VmMemoryRequest, VmMemoryResponse, VmRunMode, }; @@ -257,6 +257,8 @@ type Result = std::result::Result; enum TaggedControlSocket { Vm(VmControlResponseSocket), VmMemory(VmMemoryControlResponseSocket), + #[allow(dead_code)] + VmIrq(VmIrqResponseSocket), } impl AsRef for TaggedControlSocket { @@ -265,6 +267,7 @@ impl AsRef for TaggedControlSocket { match &self { Vm(ref socket) => socket, VmMemory(ref socket) => socket, + VmIrq(ref socket) => socket, } } } @@ -1755,6 +1758,22 @@ fn run_control( } } }, + TaggedControlSocket::VmIrq(socket) => match socket.recv() { + Ok(request) => { + let response = + request.execute(&mut linux.vm, &mut linux.resources); + if let Err(e) = socket.send(&response) { + error!("failed to send VmIrqResponse: {}", e); + } + } + Err(e) => { + if let MsgError::BadRecvSize { actual: 0, .. } = e { + vm_control_indices_to_remove.push(index); + } else { + error!("failed to recv VmIrqRequest: {}", e); + } + } + }, } } } diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index e5d18e3..f25ab20 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs @@ -17,10 +17,10 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use libc::{EINVAL, EIO, ENODEV}; -use kvm::Vm; +use kvm::{IrqRoute, IrqSource, Vm}; use msg_socket::{MsgOnSocket, MsgReceiver, MsgResult, MsgSender, MsgSocket}; use resources::{Alloc, GpuMemoryDesc, SystemAllocator}; -use sys_util::{error, Error as SysError, GuestAddress, MemoryMapping, MmapError, Result}; +use sys_util::{error, Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result}; /// A file descriptor either borrowed or owned by this. #[derive(Debug)] @@ -284,6 +284,70 @@ pub enum VmMemoryResponse { Err(SysError), } +#[derive(MsgOnSocket, Debug)] +pub enum VmIrqRequest { + /// Allocate one gsi, and associate gsi to irqfd with register_irqfd() + AllocateOneMsi { irqfd: MaybeOwnedFd }, + /// Add one msi route entry into kvm + AddMsiRoute { + gsi: u32, + msi_address: u64, + msi_data: u32, + }, +} + +impl VmIrqRequest { + /// Executes this request on the given Vm. + /// + /// # Arguments + /// * `vm` - The `Vm` to perform the request on. + /// + /// This does not return a result, instead encapsulating the success or failure in a + /// `VmIrqResponse` with the intended purpose of sending the response back over the socket + /// that received this `VmIrqResponse`. + pub fn execute(&self, vm: &mut Vm, sys_allocator: &mut SystemAllocator) -> VmIrqResponse { + use self::VmIrqRequest::*; + match *self { + AllocateOneMsi { ref irqfd } => { + if let Some(irq_num) = sys_allocator.allocate_irq() { + let evt = unsafe { EventFd::from_raw_fd(irqfd.as_raw_fd()) }; + match vm.register_irqfd(&evt, irq_num) { + Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num }, + Err(e) => VmIrqResponse::Err(e), + } + } else { + VmIrqResponse::Err(SysError::new(EINVAL)) + } + } + AddMsiRoute { + gsi, + msi_address, + msi_data, + } => { + let route = IrqRoute { + gsi, + source: IrqSource::Msi { + address: msi_address, + data: msi_data, + }, + }; + + match vm.add_irq_route_entry(route) { + Ok(_) => VmIrqResponse::Ok, + Err(e) => VmIrqResponse::Err(e), + } + } + } + } +} + +#[derive(MsgOnSocket, Debug)] +pub enum VmIrqResponse { + AllocateOneMsi { gsi: u32 }, + Ok, + Err(SysError), +} + pub type BalloonControlRequestSocket = MsgSocket; pub type BalloonControlResponseSocket = MsgSocket<(), BalloonControlCommand>; @@ -295,6 +359,9 @@ pub type UsbControlSocket = MsgSocket; pub type VmMemoryControlRequestSocket = MsgSocket; pub type VmMemoryControlResponseSocket = MsgSocket; +pub type VmIrqRequestSocket = MsgSocket; +pub type VmIrqResponseSocket = MsgSocket; + pub type VmControlRequestSocket = MsgSocket; pub type VmControlResponseSocket = MsgSocket; -- cgit 1.4.1