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>
This commit is contained in:
Lepton Wu 2018-11-21 11:06:18 -08:00 committed by chrome-bot
parent 1bc4a06801
commit 608938818b
5 changed files with 136 additions and 0 deletions

8
Cargo.lock generated
View file

@ -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",
@ -405,6 +406,13 @@ dependencies = [
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"

View file

@ -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" }

View file

@ -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" }

View file

@ -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 }
}
}

View file

@ -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";