summary refs log tree commit diff
diff options
context:
space:
mode:
authorXiong Zhang <xiong.y.zhang@intel.com>2019-09-19 10:29:02 +0800
committerCommit Bot <commit-bot@chromium.org>2019-10-15 11:41:38 +0000
commit2515b756302235e69fbc1b07ae70270be204a91d (patch)
treeae378fd1b5382e74f39769355a41fd0b7bee3b1d
parent8eb944b480c0b1e07ba24e02bb7e1955f3daf584 (diff)
downloadcrosvm-2515b756302235e69fbc1b07ae70270be204a91d.tar
crosvm-2515b756302235e69fbc1b07ae70270be204a91d.tar.gz
crosvm-2515b756302235e69fbc1b07ae70270be204a91d.tar.bz2
crosvm-2515b756302235e69fbc1b07ae70270be204a91d.tar.lz
crosvm-2515b756302235e69fbc1b07ae70270be204a91d.tar.xz
crosvm-2515b756302235e69fbc1b07ae70270be204a91d.tar.zst
crosvm-2515b756302235e69fbc1b07ae70270be204a91d.zip
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 <xiong.y.zhang@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1846603
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Xiong  Zhang <xiong.y.zhang@intel.corp-partner.google.com>
-rw-r--r--src/linux.rs21
-rw-r--r--vm_control/src/lib.rs71
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<T> = std::result::Result<T, Error>;
 enum TaggedControlSocket {
     Vm(VmControlResponseSocket),
     VmMemory(VmMemoryControlResponseSocket),
+    #[allow(dead_code)]
+    VmIrq(VmIrqResponseSocket),
 }
 
 impl AsRef<UnixSeqpacket> for TaggedControlSocket {
@@ -265,6 +267,7 @@ impl AsRef<UnixSeqpacket> 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<BalloonControlCommand, ()>;
 pub type BalloonControlResponseSocket = MsgSocket<(), BalloonControlCommand>;
 
@@ -295,6 +359,9 @@ pub type UsbControlSocket = MsgSocket<UsbControlCommand, UsbControlResult>;
 pub type VmMemoryControlRequestSocket = MsgSocket<VmMemoryRequest, VmMemoryResponse>;
 pub type VmMemoryControlResponseSocket = MsgSocket<VmMemoryResponse, VmMemoryRequest>;
 
+pub type VmIrqRequestSocket = MsgSocket<VmIrqRequest, VmIrqResponse>;
+pub type VmIrqResponseSocket = MsgSocket<VmIrqResponse, VmIrqRequest>;
+
 pub type VmControlRequestSocket = MsgSocket<VmRequest, VmResponse>;
 pub type VmControlResponseSocket = MsgSocket<VmResponse, VmRequest>;