From eb90518961ca5f00bd832429be840600ce305fb4 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 10 Apr 2020 13:19:04 +0000 Subject: three parts --- src/ext/wl_main.rs | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/guest/wl.rs | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/linux.rs | 17 ++--- src/wl.rs | 171 ------------------------------------------------ 4 files changed, 379 insertions(+), 179 deletions(-) create mode 100644 src/ext/wl_main.rs create mode 100644 src/guest/wl.rs delete mode 100644 src/wl.rs (limited to 'src') diff --git a/src/ext/wl_main.rs b/src/ext/wl_main.rs new file mode 100644 index 0000000..0b8d6a3 --- /dev/null +++ b/src/ext/wl_main.rs @@ -0,0 +1,187 @@ +// Copyright 2017 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::env::args_os; +use std::fs::remove_file; +use std::io::{stdout, IoSlice, Write}; +use std::os::unix::prelude::*; +use std::process; + +use devices::virtio::{remote, virtualized}; +use sys_util::net::{UnixSeqpacket, UnixSeqpacketListener}; +use sys_util::{PollContext, PollToken, ScmSocket}; + +fn main() { + // Create and display the incoming socket. + let mut path = std::env::var_os("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing"); + path.push("/crosvm_wl-"); + path.push(process::id().to_string()); + path.push(".sock"); + let _ = remove_file(&path); + let server = UnixSeqpacketListener::bind(&path).expect("failed to create socket"); + match stdout().write_all(path.as_bytes()) { + Ok(()) => println!(), + Err(e) => eprintln!("{}", e), + } + + // Receive connection from crosvm. + let conn = server.accept().expect("accept failed"); + let client_virtio_device_msg_socket: msg_socket2::Socket = + msg_socket2::Socket::new(conn); + + let (memory_params, client_vm_control_socket) = match client_virtio_device_msg_socket.recv() { + Ok(remote::Request::Create { + memory_params, + vm_control_socket, + }) => (memory_params, vm_control_socket.owned()), + + Ok(msg) => panic!("unexpected message: {:?}", msg), + Err(e) => panic!("recv error: {}", e), + }; + + let server_virtio_device_socket_path = args_os().nth(1).expect("missing server socket path"); + let server_virtio_device_socket = + UnixSeqpacket::connect(server_virtio_device_socket_path).expect("connect failed"); + let server_virtio_device_msg_socket: msg_socket2::Socket< + virtualized::Request, + virtualized::Response, + > = msg_socket2::Socket::new(server_virtio_device_socket); + + let (server_vm_control_socket, ext_vm_control_socket) = + UnixSeqpacket::pair().expect("pair failed"); + + server_virtio_device_msg_socket + .send(virtualized::Request::Create { + memory_params, + ext_socket: ext_vm_control_socket, // TODO: proxy rather than passing through + }) + .expect("send failed"); + + #[derive(Debug, PollToken)] + enum Token { + ClientVirtioDevice, + ClientVmControl, + ServerVirtioDevice, + ServerVmControl, + } + + let poll_ctx = match PollContext::build_with(&[ + (&client_virtio_device_msg_socket, Token::ClientVirtioDevice), + (&client_vm_control_socket, Token::ClientVmControl), + (&server_virtio_device_msg_socket, Token::ServerVirtioDevice), + (&server_vm_control_socket, Token::ServerVmControl), + ]) { + Ok(pc) => pc, + Err(e) => panic!("failed creating PollContext: {}", e), + }; + + loop { + let events = match poll_ctx.wait() { + Ok(v) => v, + Err(e) => panic!("failed polling for events: {}", e), + }; + + for event in &events { + match event.token() { + Token::ClientVirtioDevice => { + let msg = match dbg!(client_virtio_device_msg_socket.recv()) { + Ok(remote::Request::DebugLabel) => virtualized::Request::DebugLabel, + Ok(remote::Request::DeviceType) => virtualized::Request::DeviceType, + Ok(remote::Request::QueueMaxSizes) => virtualized::Request::QueueMaxSizes, + Ok(remote::Request::Features) => virtualized::Request::Features, + Ok(remote::Request::AckFeatures(value)) => { + virtualized::Request::AckFeatures(value) + } + Ok(remote::Request::ReadConfig { offset, len }) => { + virtualized::Request::ReadConfig { offset, len } + } + Ok(remote::Request::WriteConfig { offset, data }) => { + virtualized::Request::WriteConfig { offset, data } + } + Ok(remote::Request::Activate { + shm, + interrupt, + interrupt_resample_evt, + queues, + queue_evts, + }) => virtualized::Request::Activate { + shm, + interrupt, + interrupt_resample_evt, + queues, + queue_evts, + }, + Ok(remote::Request::Reset) => virtualized::Request::Reset, + Ok(remote::Request::GetDeviceBars(address)) => { + virtualized::Request::GetDeviceBars(address) + } + Ok(remote::Request::GetDeviceCaps) => virtualized::Request::GetDeviceCaps, + Ok(remote::Request::Kill) => virtualized::Request::Kill, + + Ok(req @ remote::Request::Create { .. }) => { + panic!("unexpected message: {:?}", req) + } + + Err(e) => panic!("recv failed: {}", e), + }; + + if let Err(e) = server_virtio_device_msg_socket.send(msg) { + panic!("send failed: {}", e); + } + } + + Token::ClientVmControl => { + let (buf, fds) = client_vm_control_socket + .recv_as_vec_with_fds() + .expect("recv failed"); + server_vm_control_socket + .send_with_fds(&[IoSlice::new(&buf)], &fds[..]) + .expect("send failed"); + } + + Token::ServerVirtioDevice => { + let msg = match server_virtio_device_msg_socket.recv() { + Ok(virtualized::Response::DebugLabel(label)) => { + remote::Response::DebugLabel(label) + } + Ok(virtualized::Response::DeviceType(typ)) => { + remote::Response::DeviceType(typ) + } + Ok(virtualized::Response::Features(value)) => { + remote::Response::Features(value) + } + Ok(virtualized::Response::GetDeviceBars(bars)) => { + remote::Response::GetDeviceBars(bars) + } + Ok(virtualized::Response::GetDeviceCaps(caps)) => { + remote::Response::GetDeviceCaps(caps) + } + Ok(virtualized::Response::Kill) => remote::Response::Kill, + Ok(virtualized::Response::QueueMaxSizes(sizes)) => { + remote::Response::QueueMaxSizes(sizes) + } + Ok(virtualized::Response::ReadConfig(config)) => { + remote::Response::ReadConfig(config) + } + Ok(virtualized::Response::Reset(result)) => remote::Response::Reset(result), + Err(e) => panic!("recv failed: {}", e), + }; + + if let Err(e) = client_virtio_device_msg_socket.send(dbg!(msg)) { + panic!("send failed: {}", e); + } + } + + Token::ServerVmControl => { + let (buf, fds) = server_vm_control_socket + .recv_as_vec_with_fds() + .expect("recv failed"); + client_vm_control_socket + .send_with_fds(&[IoSlice::new(&buf)], &fds[..]) + .expect("send failed"); + } + } + } + } +} diff --git a/src/guest/wl.rs b/src/guest/wl.rs new file mode 100644 index 0000000..e273246 --- /dev/null +++ b/src/guest/wl.rs @@ -0,0 +1,183 @@ +// Copyright 2017 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 devices::virtio::remote::RemotePciCapability; +use devices::virtio::virtualized::{Request, Response}; +use devices::virtio::{ + InterruptProxy, InterruptProxyEvent, Params, VirtioDevice, VirtioDeviceNew, Wl, +}; +use msg_socket::MsgSocket; +use std::collections::BTreeMap; +use std::fs::remove_file; +use std::io::prelude::*; +use std::io::stdout; +use std::os::unix::prelude::*; +use std::process; +use sys_util::{error, net::UnixSeqpacketListener, GuestMemory}; +use vm_control::MaybeOwnedFd; + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +pub use aarch64::arch_memory_regions; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub use x86_64::arch_memory_regions; + +type Socket = msg_socket2::Socket; + +fn main() { + eprintln!("hello world"); + + // Create and display the socket. + let mut path = std::env::var_os("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing"); + path.push("/crosvm_wl-"); + path.push(process::id().to_string()); + path.push(".sock"); + let _ = remove_file(&path); + let server = UnixSeqpacketListener::bind(&path).expect("failed to create control socket"); + match stdout().write_all(path.as_bytes()) { + Ok(()) => println!(), + Err(e) => eprintln!("{}", e), + } + + // Receive connection from crosvm. + let conn = server.accept().expect("accept failed"); + let msg_socket: Socket = msg_socket2::Socket::new(conn); + + let (memory_params, ext_socket) = match msg_socket.recv() { + Ok(Request::Create { + memory_params, + ext_socket, + }) => (memory_params, ext_socket), + + Ok(msg) => { + panic!("received unexpected message: {:?}", msg); + } + + Err(e) => { + panic!("recv error: {}", e); + } + }; + + let mut wayland_paths = BTreeMap::new(); + wayland_paths.insert("".into(), "/run/user/1000/wayland-0".into()); + + let mut wl = Wl::new(Params { + wayland_paths, + vm_socket: MsgSocket::new(ext_socket), + resource_bridge: None, + }) + .unwrap(); + + loop { + match dbg!(msg_socket.recv()) { + Ok(Request::DebugLabel) => { + let result = wl.debug_label(); + if let Err(e) = msg_socket.send(Response::DebugLabel(result)) { + panic!("responding to DebugLabel failed: {}", e); + } + } + + Ok(Request::DeviceType) => { + let result = wl.device_type(); + if let Err(e) = msg_socket.send(Response::DeviceType(result)) { + panic!("responding to DeviceType failed: {}", e); + } + } + + Ok(Request::QueueMaxSizes) => { + let result = wl.queue_max_sizes(); + if let Err(e) = msg_socket.send(dbg!(Response::QueueMaxSizes(result))) { + panic!("responding to QueueMaxSizes failed: {}", e); + } + } + + Ok(Request::Features) => { + let result = wl.features(); + if let Err(e) = msg_socket.send(Response::Features(result)) { + panic!("responding to Features failed: {}", e); + } + } + + Ok(Request::AckFeatures(value)) => wl.ack_features(value), + + Ok(Request::ReadConfig { offset, len }) => { + let mut data = vec![0; len]; + wl.read_config(offset, &mut data); + if let Err(e) = msg_socket.send(Response::ReadConfig(data)) { + panic!("responding to ReadConfig failed: {}", e); + } + } + + Ok(Request::WriteConfig { offset, ref data }) => wl.write_config(offset, data), + + Ok(Request::Activate { + shm, + interrupt, + interrupt_resample_evt, + queues, + queue_evts, + }) => { + let shm = shm.owned(); + + let regions = arch_memory_regions(memory_params); + let mem = + GuestMemory::with_memfd(®ions, shm).expect("GuestMemory::with_memfd failed"); + + let interrupt: MsgSocket = + MsgSocket::new(interrupt.owned()); + + wl.activate( + mem, + Box::new(InterruptProxy::new( + interrupt, + interrupt_resample_evt.owned(), + )), + queues, + queue_evts.into_iter().map(MaybeOwnedFd::owned).collect(), + ); + + println!("activated Wl"); + } + + Ok(Request::Reset) => { + let result = wl.reset(); + if let Err(e) = msg_socket.send(dbg!(Response::Reset(result))) { + panic!("responding to Reset failed: {}", e); + } + } + + Ok(Request::GetDeviceBars(address)) => { + let result = wl.get_device_bars(address); + if let Err(e) = msg_socket.send(Response::GetDeviceBars(result)) { + panic!("responding to GetDeviceBars failed: {}", e); + } + } + + Ok(Request::GetDeviceCaps) => { + let result = wl + .get_device_caps() + .into_iter() + .map(|c| RemotePciCapability::from(&*c)) + .collect(); + if let Err(e) = msg_socket.send(Response::GetDeviceCaps(result)) { + panic!("responding to GetDeviceCaps failed: {}", e); + } + } + + Ok(Request::Kill) => { + // Will block until worker shuts down. + drop(wl); + + if let Err(e) = msg_socket.send(Response::Kill) { + error!("responding to Kill failed: {}", e); + } + + break; + } + + Ok(msg @ Request::Create { .. }) => panic!("unexpected message {:?}", msg), + + Err(e) => panic!("recv failed: {}", e), + } + } +} diff --git a/src/linux.rs b/src/linux.rs index ce177e0..ee248a4 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -767,22 +767,23 @@ fn create_wayland_device( .collect::>>() .ok_or(Error::InvalidWaylandPath)?; - let params = Params { - wayland_paths: cfg.wayland_socket_paths.clone(), - vm_socket, - resource_bridge, - }; - let dev: Box = match cfg.remote_wayland_device_socket_path { Some(ref socket_path) => { let socket = UnixSeqpacket::connect(socket_path).map_err(Error::ConnectRemoteDevice)?; let msg_socket = msg_socket2::Socket::new(socket); - let controller = virtio::Controller::create(params, memory_params, msg_socket) + let controller = virtio::Controller::create(memory_params, vm_socket, msg_socket) .map_err(Error::CreateController)?; Box::new(controller) } - None => Box::new(virtio::Wl::new(params).unwrap()), + None => Box::new( + virtio::Wl::new(Params { + wayland_paths: cfg.wayland_socket_paths.clone(), + vm_socket, + resource_bridge, + }) + .unwrap(), + ), }; let jail = match simple_jail(&cfg, "wl_device")? { diff --git a/src/wl.rs b/src/wl.rs deleted file mode 100644 index 1581b2c..0000000 --- a/src/wl.rs +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -use devices::virtio::{ - InterruptProxy, InterruptProxyEvent, RemotePciCapability, Request, Response, VirtioDevice, - VirtioDeviceNew, Wl, -}; -use msg_socket::MsgSocket; -use std::fs::remove_file; -use std::io::prelude::*; -use std::io::stdout; -use std::os::unix::prelude::*; -use std::process; -use sys_util::{error, net::UnixSeqpacketListener, GuestMemory}; -use vm_control::MaybeOwnedFd; - -#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] -pub use aarch64::arch_memory_regions; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub use x86_64::arch_memory_regions; - -type Socket = msg_socket2::Socket; - -fn main() { - eprintln!("hello world"); - - // Create and display the socket. - let mut path = std::env::var_os("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing"); - path.push("/crosvm_wl-"); - path.push(process::id().to_string()); - path.push(".sock"); - let _ = remove_file(&path); - let server = UnixSeqpacketListener::bind(&path).expect("failed to create control socket"); - match stdout().write_all(path.as_bytes()) { - Ok(()) => println!(), - Err(e) => eprintln!("{}", e), - } - - // Receive connection from crosvm. - let conn = server.accept().expect("accept failed"); - let msg_socket: Socket = msg_socket2::Socket::new(conn); - - let (device_params, memory_params) = match msg_socket.recv() { - Ok(Request::Create { - device_params, - memory_params, - }) => (device_params, memory_params), - - Ok(msg) => { - panic!("received unexpected message: {:?}", msg); - } - - Err(e) => { - panic!("recv error: {}", e); - } - }; - - let mut wl = Wl::new(device_params).unwrap(); - - loop { - match msg_socket.recv() { - Ok(Request::DebugLabel) => { - let result = wl.debug_label(); - if let Err(e) = msg_socket.send(Response::DebugLabel(result)) { - panic!("responding to DebugLabel failed: {}", e); - } - } - - Ok(Request::DeviceType) => { - let result = wl.device_type(); - if let Err(e) = msg_socket.send(Response::DeviceType(result)) { - panic!("responding to DeviceType failed: {}", e); - } - } - - Ok(Request::QueueMaxSizes) => { - let result = wl.queue_max_sizes(); - if let Err(e) = msg_socket.send(Response::QueueMaxSizes(result)) { - panic!("responding to QueueMaxSizes failed: {}", e); - } - } - - Ok(Request::Features) => { - let result = wl.features(); - if let Err(e) = msg_socket.send(Response::Features(result)) { - panic!("responding to Features failed: {}", e); - } - } - - Ok(Request::AckFeatures(value)) => wl.ack_features(value), - - Ok(Request::ReadConfig { offset, len }) => { - let mut data = vec![0; len]; - wl.read_config(offset, &mut data); - if let Err(e) = msg_socket.send(Response::ReadConfig(data)) { - panic!("responding to ReadConfig failed: {}", e); - } - } - - Ok(Request::WriteConfig { offset, ref data }) => wl.write_config(offset, data), - - Ok(Request::Activate { - shm, - interrupt, - interrupt_resample_evt, - queues, - queue_evts, - }) => { - let shm = shm.owned(); - - let regions = arch_memory_regions(memory_params); - let mem = - GuestMemory::with_memfd(®ions, shm).expect("GuestMemory::with_memfd failed"); - - let interrupt: MsgSocket = - MsgSocket::new(interrupt.owned()); - - wl.activate( - mem, - Box::new(InterruptProxy::new( - interrupt, - interrupt_resample_evt.owned(), - )), - queues, - queue_evts.into_iter().map(MaybeOwnedFd::owned).collect(), - ); - - println!("activated Wl"); - } - - Ok(Request::Reset) => { - let result = wl.reset(); - if let Err(e) = msg_socket.send(Response::Reset(result)) { - panic!("responding to Reset failed: {}", e); - } - } - - Ok(Request::GetDeviceBars(address)) => { - let result = wl.get_device_bars(address); - if let Err(e) = msg_socket.send(Response::GetDeviceBars(result)) { - panic!("responding to GetDeviceBars failed: {}", e); - } - } - - Ok(Request::GetDeviceCaps) => { - let result = wl - .get_device_caps() - .into_iter() - .map(|c| RemotePciCapability::from(&*c)) - .collect(); - if let Err(e) = msg_socket.send(Response::GetDeviceCaps(result)) { - panic!("responding to GetDeviceCaps failed: {}", e); - } - } - - Ok(Request::Kill) => { - // Will block until worker shuts down. - drop(wl); - - if let Err(e) = msg_socket.send(Response::Kill) { - error!("responding to Kill failed: {}", e); - } - - break; - } - - Ok(msg @ Request::Create { .. }) => panic!("unexpected message {:?}", msg), - - Err(e) => panic!("recv failed: {}", e), - } - } -} -- cgit 1.4.1