summary refs log tree commit diff
diff options
context:
space:
mode:
authorLepton Wu <lepton@chromium.org>2018-11-21 11:06:18 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-03-14 20:53:53 -0700
commit608938818be555b51695972a78fc3bbe9c64c850 (patch)
tree557a028cc1fa98052b516a41751e6ca4f223bb0a
parent1bc4a06801a312e4fb770d323c35d34065a4d618 (diff)
downloadcrosvm-608938818be555b51695972a78fc3bbe9c64c850.tar
crosvm-608938818be555b51695972a78fc3bbe9c64c850.tar.gz
crosvm-608938818be555b51695972a78fc3bbe9c64c850.tar.bz2
crosvm-608938818be555b51695972a78fc3bbe9c64c850.tar.lz
crosvm-608938818be555b51695972a78fc3bbe9c64c850.tar.xz
crosvm-608938818be555b51695972a78fc3bbe9c64c850.tar.zst
crosvm-608938818be555b51695972a78fc3bbe9c64c850.zip
Start render node host service in crosvm
BUG=b:118408510
TEST=manual - build crosvm with/without crosvm-gpu-forward USE flag and run arcvm.

Change-Id: Ibb85d52dc679aa8524b29d86148ca28d82d8fe98
Reviewed-on: https://chromium-review.googlesource.com/1347330
Commit-Ready: Lepton Wu <lepton@chromium.org>
Tested-by: Lepton Wu <lepton@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Lepton Wu <lepton@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml2
-rw-r--r--render_node_forward/Cargo.toml10
-rw-r--r--render_node_forward/lib.rs62
-rw-r--r--src/linux.rs54
5 files changed, 136 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 62cc52f..b905dcd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -104,6 +104,7 @@ dependencies = [
  "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "qcow 0.1.0",
  "rand_ish 0.1.0",
+ "render_node_forward 0.1.0",
  "resources 0.1.0",
  "sync 0.1.0",
  "sys_util 0.1.0",
@@ -406,6 +407,13 @@ name = "rand_ish"
 version = "0.1.0"
 
 [[package]]
+name = "render_node_forward"
+version = "0.1.0"
+dependencies = [
+ "sys_util 0.1.0",
+]
+
+[[package]]
 name = "resources"
 version = "0.1.0"
 dependencies = [
diff --git a/Cargo.toml b/Cargo.toml
index cc39e5b..253604d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,6 +27,7 @@ gpu = ["devices/gpu"]
 usb-emulation = ["usb_util"]
 sandboxed-libusb = ["usb_util/sandboxed-libusb"]
 tpm = ["devices/tpm"]
+gpu-forward = ["render_node_forward"]
 
 [dependencies]
 arch = { path = "arch" }
@@ -58,6 +59,7 @@ resources = { path = "resources" }
 p9 = { path = "p9" }
 sync = { path = "sync" }
 rand_ish = { path = "rand_ish" }
+render_node_forward = { path = "render_node_forward", optional = true }
 
 [target.'cfg(target_arch = "x86_64")'.dependencies]
 x86_64 = { path = "x86_64" }
diff --git a/render_node_forward/Cargo.toml b/render_node_forward/Cargo.toml
new file mode 100644
index 0000000..accd36d
--- /dev/null
+++ b/render_node_forward/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "render_node_forward"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+sys_util = { path = "../sys_util" }
diff --git a/render_node_forward/lib.rs b/render_node_forward/lib.rs
new file mode 100644
index 0000000..8c04eb9
--- /dev/null
+++ b/render_node_forward/lib.rs
@@ -0,0 +1,62 @@
+// Copyright 2019 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.
+
+extern crate sys_util;
+
+use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+
+#[link(name = "rendernodehost")]
+extern "C" {
+    fn start_render_node_host(
+        gpu_host_mem: *mut u8,
+        gpu_guest_mem_start: u64,
+        gpu_guest_mem_size: u64,
+        host_start: *const u8,
+        host_4g_start: *const u8,
+    );
+}
+
+/// The number of bytes in 4 GiB.
+pub const FOUR_GB: u64 = (1 << 32);
+/// The size required for the render node host in host and guest address space.
+pub const RENDER_NODE_HOST_SIZE: u64 = FOUR_GB;
+
+/// A render node host device that interfaces with the guest render node forwarder.
+pub struct RenderNodeHost {
+    #[allow(dead_code)]
+    guest_mem: GuestMemory,
+}
+
+impl RenderNodeHost {
+    /// Starts the render node host forwarding service over the given guest and host address ranges.
+    pub fn start(
+        mmap: &MemoryMapping,
+        gpu_guest_address: u64,
+        guest_mem: GuestMemory,
+    ) -> RenderNodeHost {
+        // Render node forward library need to do address translation between host user space
+        // address and guest physical address. We could call Rust function from C library. But
+        // since it's actually a linear mapping now, we just pass the host start address to
+        // render node forward library. We need two start address here since there would be a
+        // hole below 4G if guest memory size is bigger than 4G.
+
+        let host_start_addr = guest_mem.get_host_address(GuestAddress(0)).unwrap();
+        let host_4g_addr = if guest_mem.memory_size() > FOUR_GB {
+            guest_mem.get_host_address(GuestAddress(FOUR_GB)).unwrap()
+        } else {
+            host_start_addr
+        };
+        // Safe because only valid addresses are given.
+        unsafe {
+            start_render_node_host(
+                mmap.as_ptr(),
+                gpu_guest_address,
+                mmap.size() as u64,
+                host_start_addr,
+                host_4g_addr,
+            )
+        }
+        RenderNodeHost { guest_mem }
+    }
+}
diff --git a/src/linux.rs b/src/linux.rs
index ee659cb..e7583a4 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -41,6 +41,8 @@ use sys_util::{
     FlockOperation, GuestMemory, Killable, PollContext, PollToken, SignalFd, Terminal, TimerFd,
     SIGRTMIN,
 };
+#[cfg(feature = "gpu-forward")]
+use sys_util::{GuestAddress, MemoryMapping, Protection};
 use vhost;
 use vm_control::{VmRequest, VmResponse, VmRunMode};
 
@@ -53,8 +55,17 @@ use aarch64::AArch64 as Arch;
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 use x86_64::X8664arch as Arch;
 
+#[cfg(feature = "gpu-forward")]
+extern crate render_node_forward;
+#[cfg(feature = "gpu-forward")]
+use self::render_node_forward::*;
+#[cfg(not(feature = "gpu-forward"))]
+type RenderNodeHost = ();
+
 #[derive(Debug)]
 pub enum Error {
+    AddGpuDeviceMemory(sys_util::Error),
+    AllocateGpuDeviceAddress,
     BalloonDeviceNew(virtio::BalloonError),
     BlockDeviceNew(sys_util::Error),
     BlockSignal(sys_util::signal::Error),
@@ -101,6 +112,8 @@ pub enum Error {
     RegisterRng(arch::DeviceRegistrationError),
     RegisterSignalHandler(sys_util::Error),
     RegisterWayland(arch::DeviceRegistrationError),
+    ReserveGpuMemory(sys_util::MmapError),
+    ReserveMemory(sys_util::Error),
     ResetTimerFd(sys_util::Error),
     RngDeviceNew(virtio::RngError),
     SettingGidMap(io_jail::Error),
@@ -120,6 +133,8 @@ impl Display for Error {
         use self::Error::*;
 
         match self {
+            AddGpuDeviceMemory(e) => write!(f, "failed to add gpu device memory: {}", e),
+            AllocateGpuDeviceAddress => write!(f, "failed to allocate gpu device guest address"),
             BalloonDeviceNew(e) => write!(f, "failed to create balloon: {}", e),
             BlockDeviceNew(e) => write!(f, "failed to create block device: {}", e),
             BlockSignal(e) => write!(f, "failed to block signal: {}", e),
@@ -181,6 +196,8 @@ impl Display for Error {
             RegisterRng(e) => write!(f, "error registering rng device: {}", e),
             RegisterSignalHandler(e) => write!(f, "error registering signal handler: {}", e),
             RegisterWayland(e) => write!(f, "error registering wayland device: {}", e),
+            ReserveGpuMemory(e) => write!(f, "failed to reserve gpu memory: {}", e),
+            ReserveMemory(e) => write!(f, "failed to reserve memory: {}", e),
             ResetTimerFd(e) => write!(f, "failed to reset timerfd: {}", e),
             RngDeviceNew(e) => write!(f, "failed to set up rng: {}", e),
             SettingGidMap(e) => write!(f, "error setting GID map: {}", e),
@@ -1115,6 +1132,41 @@ pub fn run_config(cfg: Config) -> Result<()> {
         )
     })
     .map_err(Error::BuildVm)?;
+
+    let _render_node_host = ();
+    #[cfg(feature = "gpu-forward")]
+    let (_render_node_host, linux) = {
+        // Rebinds linux as mutable.
+        let mut linux = linux;
+
+        // Reserve memory range for GPU buffer allocation in advance to bypass region count
+        // limitation. We use mremap/MAP_FIXED later to make sure GPU buffers fall into this range.
+        let gpu_mmap =
+            MemoryMapping::new_protection(RENDER_NODE_HOST_SIZE as usize, Protection::none())
+                .map_err(Error::ReserveGpuMemory)?;
+
+        // Put the non-accessible memory map into device memory so that no other devices use that
+        // guest address space.
+        let gpu_addr = linux
+            .resources
+            .allocate_device_addresses(RENDER_NODE_HOST_SIZE)
+            .ok_or(Error::AllocateGpuDeviceAddress)?;
+
+        let host = RenderNodeHost::start(&gpu_mmap, gpu_addr, linux.vm.get_memory().clone());
+
+        // Makes the gpu memory accessible at allocated address.
+        linux
+            .vm
+            .add_device_memory(
+                GuestAddress(gpu_addr),
+                gpu_mmap,
+                /* read_only = */ false,
+                /* log_dirty_pages = */ false,
+            )
+            .map_err(Error::AddGpuDeviceMemory)?;
+        (host, linux)
+    };
+
     run_control(
         linux,
         control_server_socket,
@@ -1122,6 +1174,7 @@ pub fn run_config(cfg: Config) -> Result<()> {
         balloon_host_socket,
         &disk_host_sockets,
         sigchld_fd,
+        _render_node_host,
     )
 }
 
@@ -1132,6 +1185,7 @@ fn run_control(
     balloon_host_socket: UnixSeqpacket,
     disk_host_sockets: &[MsgSocket<VmRequest, VmResponse>],
     sigchld_fd: SignalFd,
+    _render_node_host: RenderNodeHost,
 ) -> Result<()> {
     // Paths to get the currently available memory and the low memory threshold.
     const LOWMEM_MARGIN: &str = "/sys/kernel/mm/chromeos-low_mem/margin";