summary refs log tree commit diff
path: root/sys_util/src/struct_util.rs
diff options
context:
space:
mode:
authorXiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>2019-04-23 17:15:00 +0800
committerCommit Bot <commit-bot@chromium.org>2019-10-17 00:17:07 +0000
commitbed8b0017d2cb283c20dc50241adb4f5b2668489 (patch)
tree7a76e936a9e1aede56c08c112ca7d436ab8d9e98 /sys_util/src/struct_util.rs
parent04a82c7be173b2068c4254ed4a129e24e9e3a2e4 (diff)
downloadcrosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.tar
crosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.tar.gz
crosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.tar.bz2
crosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.tar.lz
crosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.tar.xz
crosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.tar.zst
crosvm-bed8b0017d2cb283c20dc50241adb4f5b2668489.zip
vfio: Add msi support
crosvm doesn't support MSI/MSI-x, but kvmgt vgpu support MSI only
through cfg msi capability. This is a simple msi implementation, it
detects msi capability and track msi control, data and address info, then
call vfio kernel to enable / disable msi interrupt.

Currently it supports one vetor per MSI. It could extend to multi vetors and
MSI-x.

BUG=chromium:992270
TEST=none

Change-Id: I04fc95f23a07f9698237c014d9f909d011f447ef
Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1581142
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'sys_util/src/struct_util.rs')
-rw-r--r--sys_util/src/struct_util.rs41
1 files changed, 35 insertions, 6 deletions
diff --git a/sys_util/src/struct_util.rs b/sys_util/src/struct_util.rs
index 3d8def2..22411a1 100644
--- a/sys_util/src/struct_util.rs
+++ b/sys_util/src/struct_util.rs
@@ -4,7 +4,38 @@
 
 use std;
 use std::io::Read;
-use std::mem;
+use std::mem::size_of;
+
+// Returns a `Vec<T>` with a size in ytes at least as large as `size_in_bytes`.
+fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
+    let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
+    let mut v = Vec::with_capacity(rounded_size);
+    for _ in 0..rounded_size {
+        v.push(T::default())
+    }
+    v
+}
+
+/// The kvm API has many structs that resemble the following `Foo` structure:
+///
+/// ```
+/// #[repr(C)]
+/// struct Foo {
+///    some_data: u32
+///    entries: __IncompleteArrayField<__u32>,
+/// }
+/// ```
+///
+/// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not
+/// include any space for `entries`. To make the allocation large enough while still being aligned
+/// for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used
+/// as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous
+/// with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries.
+pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
+    let element_space = count * size_of::<F>();
+    let vec_size_bytes = size_of::<T>() + element_space;
+    vec_with_size_in_bytes(vec_size_bytes)
+}
 
 #[derive(Debug)]
 pub enum Error {
@@ -21,7 +52,7 @@ pub type Result<T> = std::result::Result<T, Error>;
 /// * `f` - The input to read from.  Often this is a file.
 /// * `out` - The struct to fill with data read from `f`.
 pub unsafe fn read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()> {
-    let out_slice = std::slice::from_raw_parts_mut(out as *mut T as *mut u8, mem::size_of::<T>());
+    let out_slice = std::slice::from_raw_parts_mut(out as *mut T as *mut u8, size_of::<T>());
     f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
     Ok(())
 }
@@ -38,10 +69,8 @@ pub unsafe fn read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()
 pub unsafe fn read_struct_slice<T: Copy, F: Read>(f: &mut F, len: usize) -> Result<Vec<T>> {
     let mut out: Vec<T> = Vec::with_capacity(len);
     out.set_len(len);
-    let out_slice = std::slice::from_raw_parts_mut(
-        out.as_ptr() as *mut T as *mut u8,
-        mem::size_of::<T>() * len,
-    );
+    let out_slice =
+        std::slice::from_raw_parts_mut(out.as_ptr() as *mut T as *mut u8, size_of::<T>() * len);
     f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
     Ok(out)
 }