summary refs log tree commit diff
path: root/gpu_buffer/src
diff options
context:
space:
mode:
authorDavid Reveman <reveman@chromium.org>2018-04-22 21:42:09 -0400
committerchrome-bot <chrome-bot@chromium.org>2018-05-16 08:34:40 -0700
commit52ba4e5c6492d69a8ff57e87a0134c148a74a1f2 (patch)
treee7afc45010d50be4cb42db47314222af8d6b121d /gpu_buffer/src
parent0f1770d3ef9469b23edbaaa5f977dc0bb59602c6 (diff)
downloadcrosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.tar
crosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.tar.gz
crosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.tar.bz2
crosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.tar.lz
crosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.tar.xz
crosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.tar.zst
crosvm-52ba4e5c6492d69a8ff57e87a0134c148a74a1f2.zip
virtwl: Add DMABuf allocation support.
This implements DMABuf allocation type in the virtio wayland
device.

We attempt to locate a supported DRM device prior to engaging
the device jail. If found, the DRM device is passed to the
wayland device code and used to serve DMABuf allocations.

DMABuf support can be disabled by not providing crosvm with
access to any DRM device nodes.

The guest is expected to handle the case when DMABuf allocation
fails and fall-back to standard shared memory.

This initial change uses DRM directly but is structured in a
way that would allow the allocator to be replaced by minigbm
with minimal effort.

BUG=chromium:837209
TEST=crosvm finds drm device and returns valid dmabufs to guest

Change-Id: Ic1fd776dfdfefae2d7b321d449273ef269e9cc62
Reviewed-on: https://chromium-review.googlesource.com/1034088
Commit-Ready: David Reveman <reveman@chromium.org>
Tested-by: David Reveman <reveman@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'gpu_buffer/src')
-rw-r--r--gpu_buffer/src/lib.rs3
-rw-r--r--gpu_buffer/src/rendernode.rs106
2 files changed, 109 insertions, 0 deletions
diff --git a/gpu_buffer/src/lib.rs b/gpu_buffer/src/lib.rs
index 6d0cfa9..fb69eeb 100644
--- a/gpu_buffer/src/lib.rs
+++ b/gpu_buffer/src/lib.rs
@@ -31,7 +31,10 @@
 //! ```
 
 extern crate data_model;
+#[macro_use]
+extern crate sys_util;
 
+pub mod rendernode;
 mod raw;
 
 use std::os::raw::c_void;
diff --git a/gpu_buffer/src/rendernode.rs b/gpu_buffer/src/rendernode.rs
new file mode 100644
index 0000000..ce89a15
--- /dev/null
+++ b/gpu_buffer/src/rendernode.rs
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CString;
+use std::fs::{File, OpenOptions};
+use std::os::raw::{c_char, c_int, c_uint, c_ulonglong};
+use std::path::Path;
+use std::ptr::null_mut;
+
+use sys_util::ioctl_with_mut_ref;
+
+const DRM_IOCTL_BASE: c_uint = 0x64;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct drm_version {
+    version_major: c_int,
+    version_minor: c_int,
+    version_patchlevel: c_int,
+    name_len: c_ulonglong,
+    name: *mut c_char,
+    date_len: c_ulonglong,
+    date: *mut c_char,
+    desc_len: c_ulonglong,
+    desc: *mut c_char,
+}
+
+ioctl_iowr_nr!(DRM_IOCTL_VERSION, DRM_IOCTL_BASE, 0x0, drm_version);
+
+fn get_drm_device_name(fd: &File) -> Result<String, ()> {
+    let mut version = drm_version {
+        version_major: 0,
+        version_minor: 0,
+        version_patchlevel: 0,
+        name_len: 0,
+        name: null_mut(),
+        date_len: 0,
+        date: null_mut(),
+        desc_len: 0,
+        desc: null_mut(),
+    };
+
+    // Get the length of the device name.
+    if unsafe { ioctl_with_mut_ref(fd, DRM_IOCTL_VERSION(), &mut version) } < 0 {
+        return Err(());
+    }
+
+    // Enough bytes to hold the device name and terminating null character.
+    let mut name_bytes: Vec<u8> = vec![0; (version.name_len + 1) as usize];
+    let mut version = drm_version {
+        version_major: 0,
+        version_minor: 0,
+        version_patchlevel: 0,
+        name_len: name_bytes.len() as c_ulonglong,
+        name: name_bytes.as_mut_ptr() as *mut c_char,
+        date_len: 0,
+        date: null_mut(),
+        desc_len: 0,
+        desc: null_mut(),
+    };
+
+    // Safe as no more than name_len + 1 bytes will be written to name.
+    if unsafe { ioctl_with_mut_ref(fd, DRM_IOCTL_VERSION(), &mut version) } < 0 {
+        return Err(());
+    }
+
+    Ok(CString::new(&name_bytes[..(version.name_len as usize)])
+       .map_err(|_| ())?
+       .into_string().map_err(|_| ())?)
+}
+
+
+/// Returns a `fd` for an opened rendernode device, while filtering out specified
+/// undesired drivers.
+pub fn open_device(undesired: &[&str]) -> Result<File, ()> {
+    const DRM_DIR_NAME: &str = "/dev/dri";
+    const DRM_MAX_MINOR: u32 = 15;
+    const RENDER_NODE_START: u32 = 128;
+
+    for n in RENDER_NODE_START..(RENDER_NODE_START + DRM_MAX_MINOR + 1) {
+        let path = Path::new(DRM_DIR_NAME).join(format!("renderD{}", n));
+
+        if let Ok(fd) = OpenOptions::new().read(true).write(true).open(path) {
+            if let Ok(name) = get_drm_device_name(&fd) {
+                if !undesired.iter().any(|item| *item == name) {
+                    return Ok(fd);
+                }
+            }
+        }
+    }
+
+    Err(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    #[ignore] // no access to /dev/dri
+    fn open_rendernode_device() {
+        let undesired: &[&str] = &["bad_driver", "another_bad_driver"];
+        open_device(undesired).expect("failed to open rendernode");
+    }
+}