summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2020-04-10 13:19:04 +0000
committerAlyssa Ross <hi@alyssa.is>2020-06-15 09:37:29 +0000
commiteb90518961ca5f00bd832429be840600ce305fb4 (patch)
tree8415abc6314ac439b47d90305194cc88eca76146
parentaa9ee49fdf908aef32d4363704099a0584834d4c (diff)
downloadcrosvm-eb90518961ca5f00bd832429be840600ce305fb4.tar
crosvm-eb90518961ca5f00bd832429be840600ce305fb4.tar.gz
crosvm-eb90518961ca5f00bd832429be840600ce305fb4.tar.bz2
crosvm-eb90518961ca5f00bd832429be840600ce305fb4.tar.lz
crosvm-eb90518961ca5f00bd832429be840600ce305fb4.tar.xz
crosvm-eb90518961ca5f00bd832429be840600ce305fb4.tar.zst
crosvm-eb90518961ca5f00bd832429be840600ce305fb4.zip
three parts
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml16
-rw-r--r--devices/src/virtio/controller.rs534
-rw-r--r--devices/src/virtio/mod.rs2
-rw-r--r--devices/src/virtio/remote.rs536
-rw-r--r--devices/src/virtio/virtualized.rs505
-rw-r--r--src/ext/wl_main.rs187
-rw-r--r--src/guest/wl.rs (renamed from src/wl.rs)32
-rw-r--r--src/linux.rs17
-rw-r--r--vm_control/src/lib.rs1
10 files changed, 1280 insertions, 551 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ba5218a..a72324e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -154,6 +154,7 @@ dependencies = [
  "rand_ish 0.1.0",
  "remain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "resources 0.1.0",
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
  "sync 0.1.0",
  "sys_util 0.1.0",
  "vhost 0.1.0",
diff --git a/Cargo.toml b/Cargo.toml
index baf401b..2615178 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,20 +12,19 @@ name = "crosvm"
 path = "src/main.rs"
 
 [[bin]]
-name = "crosvm_wl"
-path = "src/wl.rs"
+name = "crosvm_ext_wl"
+path = "src/ext/wl_main.rs"
+
+[[bin]]
+name = "crosvm_guest_wl"
+path = "src/guest/wl.rs"
 
 [profile.release]
 panic = 'abort'
 overflow-checks = true
 
 [workspace]
-members = ["qcow_utils",
-
-# TEMP
-# "data_socket",
-
-]
+members = ["qcow_utils"]
 exclude = [
     "assertions",
     "async_core",
@@ -81,6 +80,7 @@ protos = { path = "protos", optional = true }
 rand_ish = { path = "rand_ish" }
 remain = "*"
 resources = { path = "resources" }
+serde = "*"
 sync = { path = "sync" }
 sys_util = "*"
 vhost = { path = "vhost" }
diff --git a/devices/src/virtio/controller.rs b/devices/src/virtio/controller.rs
index 7500164..dbb14e6 100644
--- a/devices/src/virtio/controller.rs
+++ b/devices/src/virtio/controller.rs
@@ -28,539 +28,23 @@
 //! the virtio queue, and routing messages in and out of `WlState`. Possible events include the kill
 //! event, available descriptors on the `in` or `out` queue, and incoming data on any vfd's socket.
 
-use std::fmt::{self, Formatter};
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::sync::Arc;
 use std::thread;
 
 use msg_socket::{MsgReceiver, MsgSocket};
-use msg_socket2::de::{EnumAccessWithFds, SeqAccessWithFds, VariantAccessWithFds, VisitorWithFds};
-use msg_socket2::ser::{SerializeAdapter, SerializeStructVariantFds, SerializeTupleVariantFds};
-use msg_socket2::{DeserializeWithFds, DeserializerWithFds, FdSerializer, SerializeWithFds};
-use serde::ser::{SerializeStructVariant, SerializeTupleVariant, Serializer};
-use serde::{Deserialize, Serialize};
 use sys_util::net::UnixSeqpacket;
-use sys_util::{error, EventFd, GuestMemory, PollContext, PollToken, SharedMemory};
+use sys_util::{error, EventFd, GuestMemory, PollContext, PollToken};
+use vm_control::{MaybeOwnedFd, VmMemoryControlRequestSocket};
 
-use super::{Interrupt, InterruptProxyEvent, Params, Queue, VirtioDevice};
+use super::{
+    remote::{Request, Response},
+    Interrupt, InterruptProxyEvent, Queue, VirtioDevice,
+};
 use crate::{
-    pci::{PciAddress, PciBarConfiguration, PciCapability, PciCapabilityID},
+    pci::{PciAddress, PciBarConfiguration, PciCapability},
     MemoryParams,
 };
-use vm_control::MaybeOwnedFd;
-
-// As far as I can tell, these never change on the other side, so it's
-// fine to just copy them over.
-#[derive(Clone, Debug, Deserialize, Serialize)]
-pub struct RemotePciCapability {
-    bytes: Vec<u8>,
-    id: PciCapabilityID,
-}
-
-impl RemotePciCapability {
-    pub fn from(capability: &dyn PciCapability) -> Self {
-        Self {
-            bytes: capability.bytes().to_vec(),
-            id: capability.id(),
-        }
-    }
-}
-
-impl PciCapability for RemotePciCapability {
-    fn bytes(&self) -> &[u8] {
-        &self.bytes
-    }
-
-    fn id(&self) -> PciCapabilityID {
-        self.id
-    }
-}
-
-#[derive(Debug)]
-pub enum Request {
-    Create {
-        device_params: Params,
-        memory_params: MemoryParams,
-    },
-
-    DebugLabel,
-
-    DeviceType,
-
-    QueueMaxSizes,
-
-    Features,
-    AckFeatures(u64),
-
-    ReadConfig {
-        offset: u64,
-        len: usize,
-    },
-    WriteConfig {
-        offset: u64,
-        data: Vec<u8>,
-    },
-
-    Activate {
-        shm: MaybeOwnedFd<SharedMemory>,
-        interrupt: MaybeOwnedFd<UnixSeqpacket>,
-        interrupt_resample_evt: MaybeOwnedFd<EventFd>,
-        queues: Vec<Queue>,
-        queue_evts: Vec<MaybeOwnedFd<EventFd>>,
-    },
-
-    Reset,
-
-    GetDeviceBars(PciAddress),
-    GetDeviceCaps,
-
-    Kill,
-}
-
-impl SerializeWithFds for Request {
-    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
-        use Request::*;
-
-        match self {
-            Create {
-                device_params,
-                memory_params,
-            } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?;
-                sv.serialize_field("device_params", &SerializeAdapter::new(device_params))?;
-                sv.serialize_field("memory_params", memory_params)?;
-                sv.end()
-            }
-
-            DebugLabel => serializer.serialize_unit_variant("Request", 1, "DebugLabel"),
-
-            DeviceType => serializer.serialize_unit_variant("Request", 2, "DeviceType"),
-            QueueMaxSizes => serializer.serialize_unit_variant("Request", 3, "QueueMaxSizes"),
-
-            Features => serializer.serialize_unit_variant("Request", 4, "Features"),
-
-            AckFeatures(features) => {
-                let mut tv = serializer.serialize_tuple_variant("Request", 5, "AckFeatures", 1)?;
-                tv.serialize_field(features)?;
-                tv.end()
-            }
-
-            ReadConfig { offset, len } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 6, "ReadConfig", 2)?;
-                sv.serialize_field("offset", offset)?;
-                sv.serialize_field("len", len)?;
-                sv.end()
-            }
-
-            WriteConfig { offset, data } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 7, "WriteConfig", 2)?;
-                sv.serialize_field("offset", offset)?;
-                sv.serialize_field("data", data)?;
-                sv.end()
-            }
-
-            Activate {
-                shm,
-                interrupt,
-                interrupt_resample_evt,
-                queues,
-                queue_evts,
-            } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 7)?;
-                sv.serialize_field("shm", &SerializeAdapter::new(shm))?;
-                sv.serialize_field("interrupt", &SerializeAdapter::new(interrupt))?;
-                sv.serialize_field(
-                    "interrupt_resample_evt",
-                    &SerializeAdapter::new(interrupt_resample_evt),
-                )?;
-                sv.serialize_field("queues", queues)?;
-                sv.serialize_field("queue_evts", &SerializeAdapter::new(queue_evts))?;
-                sv.end()
-            }
-
-            Reset => serializer.serialize_unit_variant("Request", 9, "Reset"),
-
-            GetDeviceBars(address) => {
-                let mut sv =
-                    serializer.serialize_struct_variant("Request", 10, "GetDeviceBars", 1)?;
-                sv.serialize_field("address", address)?;
-                sv.end()
-            }
-
-            GetDeviceCaps => serializer.serialize_unit_variant("Request", 11, "GetDeviceCaps"),
-
-            Kill => serializer.serialize_unit_variant("Request", 12, "Kill"),
-        }
-    }
-
-    fn serialize_fds<'fds, S>(&'fds self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: FdSerializer<'fds>,
-    {
-        use Request::*;
-
-        match self {
-            Create {
-                device_params,
-                memory_params,
-            } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?;
-                sv.serialize_field("device_params", device_params)?;
-                sv.serialize_field("memory_params", memory_params)?;
-                sv.end()
-            }
-
-            DebugLabel => serializer.serialize_unit_variant("Request", 1, "DebugLabel"),
-            DeviceType => serializer.serialize_unit_variant("Request", 2, "DeviceType"),
-            QueueMaxSizes => serializer.serialize_unit_variant("Request", 3, "QueueMaxSizes"),
-            Features => serializer.serialize_unit_variant("Request", 4, "Features"),
-
-            AckFeatures(features) => {
-                let mut tv = serializer.serialize_tuple_variant("Request", 5, "AckFeatures", 1)?;
-                tv.serialize_field(features)?;
-                tv.end()
-            }
-
-            ReadConfig { offset, len } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 6, "ReadConfig", 2)?;
-                sv.serialize_field("offset", offset)?;
-                sv.serialize_field("len", len)?;
-                sv.end()
-            }
-
-            WriteConfig { offset, data } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 7, "WriteConfig", 2)?;
-                sv.serialize_field("offset", offset)?;
-                sv.serialize_field("data", data)?;
-                sv.end()
-            }
-
-            Activate {
-                shm,
-                interrupt,
-                interrupt_resample_evt,
-                queues,
-                queue_evts,
-            } => {
-                let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 2)?;
-                sv.serialize_field("shm", shm)?;
-                sv.serialize_field("interrupt", interrupt)?;
-                sv.serialize_field("interrupt_resample_evt", interrupt_resample_evt)?;
-                sv.serialize_field("queues", queues)?;
-                sv.serialize_field("queue_evts", queue_evts)?;
-                sv.end()
-            }
-
-            Reset => serializer.serialize_unit_variant("Request", 9, "Reset"),
-
-            GetDeviceBars(address) => {
-                let mut tv =
-                    serializer.serialize_tuple_variant("Request", 10, "GetDeviceBars", 1)?;
-                tv.serialize_field(address)?;
-                tv.end()
-            }
-
-            GetDeviceCaps => serializer.serialize_unit_variant("Request", 11, "GetDeviceCaps"),
-
-            Kill => serializer.serialize_unit_variant("Request", 12, "Kill"),
-        }
-    }
-}
-
-impl<'de> DeserializeWithFds<'de> for Request {
-    fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> {
-        struct Visitor;
-
-        impl<'de> VisitorWithFds<'de> for Visitor {
-            type Value = Request;
-
-            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
-                write!(f, "enum Request")
-            }
-
-            fn visit_enum<A: EnumAccessWithFds<'de>>(
-                self,
-                data: A,
-            ) -> Result<Self::Value, A::Error> {
-                #[derive(Debug, Deserialize)]
-                enum Variant {
-                    Create,
-                    DebugLabel,
-                    DeviceType,
-                    QueueMaxSizes,
-                    Features,
-                    AckFeatures,
-                    ReadConfig,
-                    WriteConfig,
-                    Activate,
-                    Reset,
-                    GetDeviceBars,
-                    GetDeviceCaps,
-                    Kill,
-                }
-
-                match data.variant()? {
-                    (Variant::Create, variant) => {
-                        struct Visitor;
-
-                        impl<'de> VisitorWithFds<'de> for Visitor {
-                            type Value = Request;
-
-                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
-                                write!(f, "struct variant Request::Create")
-                            }
-
-                            fn visit_seq<A: SeqAccessWithFds<'de>>(
-                                self,
-                                mut seq: A,
-                            ) -> Result<Request, A::Error> {
-                                use serde::de::Error;
-
-                                fn too_short<E: Error>(len: usize) -> E {
-                                    E::invalid_length(
-                                        len,
-                                        &"struct variant Request::Create with 2 elements",
-                                    )
-                                }
-
-                                Ok(Request::Create {
-                                    device_params: seq
-                                        .next_element()?
-                                        .ok_or_else(|| too_short(0))?,
-                                    memory_params: seq
-                                        .next_element()?
-                                        .ok_or_else(|| too_short(1))?,
-                                })
-                            }
-                        }
-
-                        variant.struct_variant(&["vm_socket", "memory_params"], Visitor)
-                    }
-
-                    (Variant::DebugLabel, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::DebugLabel)
-                    }
-
-                    (Variant::DeviceType, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::DeviceType)
-                    }
-
-                    (Variant::QueueMaxSizes, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::QueueMaxSizes)
-                    }
-
-                    (Variant::Features, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::Features)
-                    }
-
-                    (Variant::AckFeatures, variant) => {
-                        Ok(Request::AckFeatures(variant.newtype_variant()?))
-                    }
-
-                    (Variant::ReadConfig, variant) => {
-                        struct Visitor;
-
-                        impl<'de> VisitorWithFds<'de> for Visitor {
-                            type Value = Request;
-
-                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
-                                write!(f, "struct variant Request::ReadConfig")
-                            }
-
-                            fn visit_seq<A: SeqAccessWithFds<'de>>(
-                                self,
-                                mut seq: A,
-                            ) -> Result<Request, A::Error> {
-                                use serde::de::Error;
-
-                                fn too_short<E: Error>(len: usize) -> E {
-                                    E::invalid_length(
-                                        len,
-                                        &"struct variant Request::ReadConfig with 2 elements",
-                                    )
-                                }
-
-                                Ok(Request::ReadConfig {
-                                    offset: seq.next_element()?.ok_or_else(|| too_short(0))?,
-                                    len: seq.next_element()?.ok_or_else(|| too_short(1))?,
-                                })
-                            }
-                        }
-
-                        variant.struct_variant(&["offset", "len"], Visitor)
-                    }
-
-                    (Variant::WriteConfig, variant) => {
-                        struct Visitor;
-
-                        impl<'de> VisitorWithFds<'de> for Visitor {
-                            type Value = Request;
-
-                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
-                                write!(f, "struct variant Request::WriteConfig")
-                            }
-
-                            fn visit_seq<A: SeqAccessWithFds<'de>>(
-                                self,
-                                mut seq: A,
-                            ) -> Result<Request, A::Error> {
-                                use serde::de::Error;
-
-                                fn too_short<E: Error>(len: usize) -> E {
-                                    E::invalid_length(
-                                        len,
-                                        &"struct variant Request::WriteConfig with 2 elements",
-                                    )
-                                }
-
-                                Ok(Request::WriteConfig {
-                                    offset: seq.next_element()?.ok_or_else(|| too_short(0))?,
-                                    data: seq.next_element()?.ok_or_else(|| too_short(1))?,
-                                })
-                            }
-                        }
-
-                        variant.struct_variant(&["offset", "data"], Visitor)
-                    }
-
-                    (Variant::Activate, variant) => {
-                        struct Visitor;
-
-                        impl<'de> VisitorWithFds<'de> for Visitor {
-                            type Value = Request;
-
-                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
-                                write!(f, "struct variant Request::Activate")
-                            }
-
-                            fn visit_seq<A: SeqAccessWithFds<'de>>(
-                                self,
-                                mut seq: A,
-                            ) -> Result<Request, A::Error> {
-                                use serde::de::Error;
-
-                                fn too_short<E: Error>(len: usize) -> E {
-                                    E::invalid_length(
-                                        len,
-                                        &"struct variant Request::Activate with 7 elements",
-                                    )
-                                }
-
-                                Ok(Request::Activate {
-                                    shm: seq.next_element()?.ok_or_else(|| too_short(0))?,
-                                    interrupt: seq.next_element()?.ok_or_else(|| too_short(1))?,
-                                    interrupt_resample_evt: seq
-                                        .next_element()?
-                                        .ok_or_else(|| too_short(2))?,
-                                    queues: seq.next_element()?.ok_or_else(|| too_short(3))?,
-                                    queue_evts: seq.next_element()?.ok_or_else(|| too_short(4))?,
-                                })
-                            }
-                        }
-
-                        variant.struct_variant(
-                            &[
-                                "shm",
-                                "interrupt",
-                                "interrupt_resample_evt",
-                                "in_queue",
-                                "out_queue",
-                                "in_queue_evt",
-                                "out_queue_evt",
-                            ],
-                            Visitor,
-                        )
-                    }
-
-                    (Variant::Reset, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::Reset)
-                    }
-
-                    (Variant::GetDeviceBars, variant) => {
-                        struct Visitor;
-
-                        impl<'de> VisitorWithFds<'de> for Visitor {
-                            type Value = Request;
-
-                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
-                                write!(f, "struct variant Request::GetDeviceBars")
-                            }
-
-                            fn visit_seq<A: SeqAccessWithFds<'de>>(
-                                self,
-                                mut seq: A,
-                            ) -> Result<Request, A::Error> {
-                                use serde::de::Error;
-
-                                fn too_short<E: Error>(len: usize) -> E {
-                                    E::invalid_length(
-                                        len,
-                                        &"struct variant Request::GetDeviceBars with 2 elements",
-                                    )
-                                }
-
-                                Ok(Request::GetDeviceBars(
-                                    seq.next_element()?.ok_or_else(|| too_short(0))?,
-                                ))
-                            }
-                        }
-
-                        variant.struct_variant(&["bus", "dev"], Visitor)
-                    }
-
-                    (Variant::GetDeviceCaps, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::GetDeviceCaps)
-                    }
-
-                    (Variant::Kill, variant) => {
-                        variant.unit_variant()?;
-                        Ok(Request::Kill)
-                    }
-                }
-            }
-        }
-
-        deserializer.deserialize_enum(
-            "Request",
-            &[
-                "Create",
-                "DebugLabel",
-                "DeviceType",
-                "QueueMaxSizes",
-                "Features",
-                "AckFeatures",
-                "ReadConfig",
-                "WriteConfig",
-                "Activate",
-                "Reset",
-                "GetDeviceBars",
-                "GetDeviceCaps",
-                "Kill",
-            ],
-            Visitor,
-        )
-    }
-}
-
-#[derive(Debug, Deserialize, DeserializeWithFds, Serialize, SerializeWithFds)]
-#[msg_socket2(strategy = "serde")]
-pub enum Response {
-    DebugLabel(String),
-    DeviceType(u32),
-    QueueMaxSizes(Vec<u16>),
-    Features(u64),
-    ReadConfig(Vec<u8>),
-    Reset(bool),
-    GetDeviceBars(Vec<PciBarConfiguration>),
-    GetDeviceCaps(Vec<RemotePciCapability>),
-    Kill,
-}
 
 type Socket = msg_socket2::Socket<Request, Response>;
 
@@ -671,13 +155,13 @@ impl Controller {
     /// Construct a controller, and initialize (but don't activate)
     /// the remote device.
     pub fn create(
-        device_params: Params,
         memory_params: MemoryParams,
+        vm_control_socket: VmMemoryControlRequestSocket,
         socket: Socket,
     ) -> Result<Controller, msg_socket2::Error> {
         socket.send(Request::Create {
-            device_params,
             memory_params,
+            vm_control_socket: MaybeOwnedFd::Borrowed(vm_control_socket.as_raw_fd()),
         })?;
 
         Ok(Controller {
diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs
index acae318..9bc222e 100644
--- a/devices/src/virtio/mod.rs
+++ b/devices/src/virtio/mod.rs
@@ -32,8 +32,10 @@ use std::fmt::Debug;
 pub mod fs;
 #[cfg(feature = "gpu")]
 pub mod gpu;
+pub mod remote;
 pub mod resource_bridge;
 pub mod vhost;
+pub mod virtualized;
 
 pub use self::balloon::*;
 pub use self::block::*;
diff --git a/devices/src/virtio/remote.rs b/devices/src/virtio/remote.rs
new file mode 100644
index 0000000..e7f7967
--- /dev/null
+++ b/devices/src/virtio/remote.rs
@@ -0,0 +1,536 @@
+// 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 msg_socket2::de::{EnumAccessWithFds, SeqAccessWithFds, VariantAccessWithFds, VisitorWithFds};
+use msg_socket2::ser::{
+    SerializeAdapter, SerializeStructVariant, SerializeStructVariantFds, SerializeTupleVariant,
+    SerializeTupleVariantFds, Serializer,
+};
+use msg_socket2::{
+    Deserialize, DeserializeWithFds, DeserializerWithFds, FdSerializer, Serialize, SerializeWithFds,
+};
+use std::fmt::{self, Formatter};
+use sys_util::net::UnixSeqpacket;
+use sys_util::{EventFd, SharedMemory};
+use vm_control::MaybeOwnedFd;
+
+use crate::pci::{PciAddress, PciBarConfiguration, PciCapability, PciCapabilityID};
+use crate::virtio::Queue;
+use crate::MemoryParams;
+
+// As far as I can tell, these never change on the other side, so it's
+// fine to just copy them over.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct RemotePciCapability {
+    bytes: Vec<u8>,
+    id: PciCapabilityID,
+}
+
+impl RemotePciCapability {
+    pub fn from(capability: &dyn PciCapability) -> Self {
+        Self {
+            bytes: capability.bytes().to_vec(),
+            id: capability.id(),
+        }
+    }
+}
+
+impl PciCapability for RemotePciCapability {
+    fn bytes(&self) -> &[u8] {
+        &self.bytes
+    }
+
+    fn id(&self) -> PciCapabilityID {
+        self.id
+    }
+}
+
+#[derive(Debug)]
+pub enum Request {
+    Create {
+        memory_params: MemoryParams,
+        vm_control_socket: MaybeOwnedFd<UnixSeqpacket>,
+    },
+
+    DebugLabel,
+
+    DeviceType,
+
+    QueueMaxSizes,
+
+    Features,
+    AckFeatures(u64),
+
+    ReadConfig {
+        offset: u64,
+        len: usize,
+    },
+    WriteConfig {
+        offset: u64,
+        data: Vec<u8>,
+    },
+
+    Activate {
+        shm: MaybeOwnedFd<SharedMemory>,
+        interrupt: MaybeOwnedFd<UnixSeqpacket>,
+        interrupt_resample_evt: MaybeOwnedFd<EventFd>,
+        queues: Vec<Queue>,
+        queue_evts: Vec<MaybeOwnedFd<EventFd>>,
+    },
+
+    Reset,
+
+    GetDeviceBars(PciAddress),
+    GetDeviceCaps,
+
+    Kill,
+}
+
+impl SerializeWithFds for Request {
+    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        use Request::*;
+
+        match self {
+            Create {
+                memory_params,
+                vm_control_socket,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?;
+                sv.serialize_field("memory_params", memory_params)?;
+                sv.serialize_field(
+                    "vm_control_socket",
+                    &SerializeAdapter::new(vm_control_socket),
+                )?;
+                sv.end()
+            }
+
+            DebugLabel => serializer.serialize_unit_variant("Request", 1, "DebugLabel"),
+
+            DeviceType => serializer.serialize_unit_variant("Request", 2, "DeviceType"),
+            QueueMaxSizes => serializer.serialize_unit_variant("Request", 3, "QueueMaxSizes"),
+
+            Features => serializer.serialize_unit_variant("Request", 4, "Features"),
+
+            AckFeatures(features) => {
+                let mut tv = serializer.serialize_tuple_variant("Request", 5, "AckFeatures", 1)?;
+                tv.serialize_field(features)?;
+                tv.end()
+            }
+
+            ReadConfig { offset, len } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 6, "ReadConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("len", len)?;
+                sv.end()
+            }
+
+            WriteConfig { offset, data } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 7, "WriteConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("data", data)?;
+                sv.end()
+            }
+
+            Activate {
+                shm,
+                interrupt,
+                interrupt_resample_evt,
+                queues,
+                queue_evts,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 7)?;
+                sv.serialize_field("shm", &SerializeAdapter::new(shm))?;
+                sv.serialize_field("interrupt", &SerializeAdapter::new(interrupt))?;
+                sv.serialize_field(
+                    "interrupt_resample_evt",
+                    &SerializeAdapter::new(interrupt_resample_evt),
+                )?;
+                sv.serialize_field("queues", queues)?;
+                sv.serialize_field("queue_evts", &SerializeAdapter::new(queue_evts))?;
+                sv.end()
+            }
+
+            Reset => serializer.serialize_unit_variant("Request", 9, "Reset"),
+
+            GetDeviceBars(address) => {
+                let mut tv =
+                    serializer.serialize_tuple_variant("Request", 10, "GetDeviceBars", 1)?;
+                tv.serialize_field(address)?;
+                tv.end()
+            }
+
+            GetDeviceCaps => serializer.serialize_unit_variant("Request", 11, "GetDeviceCaps"),
+
+            Kill => serializer.serialize_unit_variant("Request", 12, "Kill"),
+        }
+    }
+
+    fn serialize_fds<'fds, S>(&'fds self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: FdSerializer<'fds>,
+    {
+        use Request::*;
+
+        match self {
+            Create {
+                memory_params,
+                vm_control_socket,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?;
+                sv.serialize_field("memory_params", memory_params)?;
+                sv.serialize_field("vm_control_socket", vm_control_socket)?;
+                sv.end()
+            }
+
+            DebugLabel => serializer.serialize_unit_variant("Request", 1, "DebugLabel"),
+            DeviceType => serializer.serialize_unit_variant("Request", 2, "DeviceType"),
+            QueueMaxSizes => serializer.serialize_unit_variant("Request", 3, "QueueMaxSizes"),
+            Features => serializer.serialize_unit_variant("Request", 4, "Features"),
+
+            AckFeatures(features) => {
+                let mut tv = serializer.serialize_tuple_variant("Request", 5, "AckFeatures", 1)?;
+                tv.serialize_field(features)?;
+                tv.end()
+            }
+
+            ReadConfig { offset, len } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 6, "ReadConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("len", len)?;
+                sv.end()
+            }
+
+            WriteConfig { offset, data } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 7, "WriteConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("data", data)?;
+                sv.end()
+            }
+
+            Activate {
+                shm,
+                interrupt,
+                interrupt_resample_evt,
+                queues,
+                queue_evts,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 2)?;
+                sv.serialize_field("shm", shm)?;
+                sv.serialize_field("interrupt", interrupt)?;
+                sv.serialize_field("interrupt_resample_evt", interrupt_resample_evt)?;
+                sv.serialize_field("queues", queues)?;
+                sv.serialize_field("queue_evts", queue_evts)?;
+                sv.end()
+            }
+
+            Reset => serializer.serialize_unit_variant("Request", 9, "Reset"),
+
+            GetDeviceBars(address) => {
+                let mut tv =
+                    serializer.serialize_tuple_variant("Request", 10, "GetDeviceBars", 1)?;
+                tv.serialize_field(address)?;
+                tv.end()
+            }
+
+            GetDeviceCaps => serializer.serialize_unit_variant("Request", 11, "GetDeviceCaps"),
+
+            Kill => serializer.serialize_unit_variant("Request", 12, "Kill"),
+        }
+    }
+}
+
+impl<'de> DeserializeWithFds<'de> for Request {
+    fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> {
+        struct Visitor;
+
+        impl<'de> VisitorWithFds<'de> for Visitor {
+            type Value = Request;
+
+            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                write!(f, "enum Request")
+            }
+
+            fn visit_enum<A: EnumAccessWithFds<'de>>(
+                self,
+                data: A,
+            ) -> Result<Self::Value, A::Error> {
+                #[derive(Debug, Deserialize)]
+                enum Variant {
+                    Create,
+                    DebugLabel,
+                    DeviceType,
+                    QueueMaxSizes,
+                    Features,
+                    AckFeatures,
+                    ReadConfig,
+                    WriteConfig,
+                    Activate,
+                    Reset,
+                    GetDeviceBars,
+                    GetDeviceCaps,
+                    Kill,
+                }
+
+                match data.variant()? {
+                    (Variant::Create, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::Create")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::Create with 2 elements",
+                                    )
+                                }
+
+                                Ok(Request::Create {
+                                    memory_params: seq
+                                        .next_element()?
+                                        .ok_or_else(|| too_short(0))?,
+                                    vm_control_socket: seq
+                                        .next_element()?
+                                        .ok_or_else(|| too_short(1))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(&["memory_params", "vm_control_socket"], Visitor)
+                    }
+
+                    (Variant::DebugLabel, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::DebugLabel)
+                    }
+
+                    (Variant::DeviceType, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::DeviceType)
+                    }
+
+                    (Variant::QueueMaxSizes, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::QueueMaxSizes)
+                    }
+
+                    (Variant::Features, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::Features)
+                    }
+
+                    (Variant::AckFeatures, variant) => {
+                        Ok(Request::AckFeatures(variant.newtype_variant()?))
+                    }
+
+                    (Variant::ReadConfig, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::ReadConfig")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::ReadConfig with 2 elements",
+                                    )
+                                }
+
+                                Ok(Request::ReadConfig {
+                                    offset: seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                    len: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(&["offset", "len"], Visitor)
+                    }
+
+                    (Variant::WriteConfig, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::WriteConfig")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::WriteConfig with 2 elements",
+                                    )
+                                }
+
+                                Ok(Request::WriteConfig {
+                                    offset: seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                    data: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(&["offset", "data"], Visitor)
+                    }
+
+                    (Variant::Activate, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::Activate")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::Activate with 7 elements",
+                                    )
+                                }
+
+                                Ok(Request::Activate {
+                                    shm: seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                    interrupt: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                    interrupt_resample_evt: seq
+                                        .next_element()?
+                                        .ok_or_else(|| too_short(2))?,
+                                    queues: seq.next_element()?.ok_or_else(|| too_short(3))?,
+                                    queue_evts: seq.next_element()?.ok_or_else(|| too_short(4))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(
+                            &[
+                                "shm",
+                                "interrupt",
+                                "interrupt_resample_evt",
+                                "in_queue",
+                                "out_queue",
+                                "in_queue_evt",
+                                "out_queue_evt",
+                            ],
+                            Visitor,
+                        )
+                    }
+
+                    (Variant::Reset, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::Reset)
+                    }
+
+                    (Variant::GetDeviceBars, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "tuple variant Request::GetDeviceBars")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"tuple variant Request::GetDeviceBars with 1 elements",
+                                    )
+                                }
+
+                                Ok(Request::GetDeviceBars(
+                                    seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                ))
+                            }
+                        }
+
+                        variant.struct_variant(&["bus", "dev"], Visitor)
+                    }
+
+                    (Variant::GetDeviceCaps, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::GetDeviceCaps)
+                    }
+
+                    (Variant::Kill, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::Kill)
+                    }
+                }
+            }
+        }
+
+        deserializer.deserialize_enum(
+            "Request",
+            &[
+                "Create",
+                "DebugLabel",
+                "DeviceType",
+                "QueueMaxSizes",
+                "Features",
+                "AckFeatures",
+                "ReadConfig",
+                "WriteConfig",
+                "Activate",
+                "Reset",
+                "GetDeviceBars",
+                "GetDeviceCaps",
+                "Kill",
+            ],
+            Visitor,
+        )
+    }
+}
+
+#[derive(Debug, Deserialize, DeserializeWithFds, Serialize, SerializeWithFds)]
+#[msg_socket2(strategy = "serde")]
+pub enum Response {
+    DebugLabel(String),
+    DeviceType(u32),
+    QueueMaxSizes(Vec<u16>),
+    Features(u64),
+    ReadConfig(Vec<u8>),
+    Reset(bool),
+    GetDeviceBars(Vec<PciBarConfiguration>),
+    GetDeviceCaps(Vec<RemotePciCapability>),
+    Kill,
+}
diff --git a/devices/src/virtio/virtualized.rs b/devices/src/virtio/virtualized.rs
new file mode 100644
index 0000000..fd11f8a
--- /dev/null
+++ b/devices/src/virtio/virtualized.rs
@@ -0,0 +1,505 @@
+// 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 msg_socket2::de::{EnumAccessWithFds, SeqAccessWithFds, VariantAccessWithFds, VisitorWithFds};
+use msg_socket2::ser::{
+    SerializeAdapter, SerializeStructVariant, SerializeStructVariantFds, SerializeTupleVariant,
+    SerializeTupleVariantFds, Serializer,
+};
+use msg_socket2::{
+    Deserialize, DeserializeWithFds, DeserializerWithFds, FdSerializer, Serialize, SerializeWithFds,
+};
+use std::fmt::{self, Formatter};
+use sys_util::net::UnixSeqpacket;
+use sys_util::{EventFd, SharedMemory};
+use vm_control::MaybeOwnedFd;
+
+use crate::pci::{PciAddress, PciBarConfiguration};
+use crate::virtio::remote::RemotePciCapability;
+use crate::virtio::Queue;
+use crate::MemoryParams;
+
+#[derive(Debug)]
+pub enum Request {
+    Create {
+        memory_params: MemoryParams,
+        ext_socket: UnixSeqpacket,
+    },
+
+    DebugLabel,
+
+    DeviceType,
+
+    QueueMaxSizes,
+
+    Features,
+    AckFeatures(u64),
+
+    ReadConfig {
+        offset: u64,
+        len: usize,
+    },
+    WriteConfig {
+        offset: u64,
+        data: Vec<u8>,
+    },
+
+    Activate {
+        shm: MaybeOwnedFd<SharedMemory>,
+        interrupt: MaybeOwnedFd<UnixSeqpacket>,
+        interrupt_resample_evt: MaybeOwnedFd<EventFd>,
+        queues: Vec<Queue>,
+        queue_evts: Vec<MaybeOwnedFd<EventFd>>,
+    },
+
+    Reset,
+
+    GetDeviceBars(PciAddress),
+    GetDeviceCaps,
+
+    Kill,
+}
+
+impl SerializeWithFds for Request {
+    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        use Request::*;
+
+        match self {
+            Create {
+                memory_params,
+                ext_socket,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?;
+                sv.serialize_field("memory_params", memory_params)?;
+                sv.serialize_field("ext_socket", &SerializeAdapter::new(ext_socket))?;
+                sv.end()
+            }
+
+            DebugLabel => serializer.serialize_unit_variant("Request", 1, "DebugLabel"),
+
+            DeviceType => serializer.serialize_unit_variant("Request", 2, "DeviceType"),
+            QueueMaxSizes => serializer.serialize_unit_variant("Request", 3, "QueueMaxSizes"),
+
+            Features => serializer.serialize_unit_variant("Request", 4, "Features"),
+
+            AckFeatures(features) => {
+                let mut tv = serializer.serialize_tuple_variant("Request", 5, "AckFeatures", 1)?;
+                tv.serialize_field(features)?;
+                tv.end()
+            }
+
+            ReadConfig { offset, len } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 6, "ReadConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("len", len)?;
+                sv.end()
+            }
+
+            WriteConfig { offset, data } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 7, "WriteConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("data", data)?;
+                sv.end()
+            }
+
+            Activate {
+                shm,
+                interrupt,
+                interrupt_resample_evt,
+                queues,
+                queue_evts,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 7)?;
+                sv.serialize_field("shm", &SerializeAdapter::new(shm))?;
+                sv.serialize_field("interrupt", &SerializeAdapter::new(interrupt))?;
+                sv.serialize_field(
+                    "interrupt_resample_evt",
+                    &SerializeAdapter::new(interrupt_resample_evt),
+                )?;
+                sv.serialize_field("queues", queues)?;
+                sv.serialize_field("queue_evts", &SerializeAdapter::new(queue_evts))?;
+                sv.end()
+            }
+
+            Reset => serializer.serialize_unit_variant("Request", 9, "Reset"),
+
+            GetDeviceBars(address) => {
+                let mut tv =
+                    serializer.serialize_tuple_variant("Request", 10, "GetDeviceBars", 1)?;
+                tv.serialize_field(address)?;
+                tv.end()
+            }
+
+            GetDeviceCaps => serializer.serialize_unit_variant("Request", 11, "GetDeviceCaps"),
+
+            Kill => serializer.serialize_unit_variant("Request", 12, "Kill"),
+        }
+    }
+
+    fn serialize_fds<'fds, S>(&'fds self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: FdSerializer<'fds>,
+    {
+        use Request::*;
+
+        match self {
+            Create {
+                memory_params,
+                ext_socket,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?;
+                sv.serialize_field("memory_params", memory_params)?;
+                sv.serialize_field("ext_socket", ext_socket)?;
+                sv.end()
+            }
+
+            DebugLabel => serializer.serialize_unit_variant("Request", 1, "DebugLabel"),
+            DeviceType => serializer.serialize_unit_variant("Request", 2, "DeviceType"),
+            QueueMaxSizes => serializer.serialize_unit_variant("Request", 3, "QueueMaxSizes"),
+            Features => serializer.serialize_unit_variant("Request", 4, "Features"),
+
+            AckFeatures(features) => {
+                let mut tv = serializer.serialize_tuple_variant("Request", 5, "AckFeatures", 1)?;
+                tv.serialize_field(features)?;
+                tv.end()
+            }
+
+            ReadConfig { offset, len } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 6, "ReadConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("len", len)?;
+                sv.end()
+            }
+
+            WriteConfig { offset, data } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 7, "WriteConfig", 2)?;
+                sv.serialize_field("offset", offset)?;
+                sv.serialize_field("data", data)?;
+                sv.end()
+            }
+
+            Activate {
+                shm,
+                interrupt,
+                interrupt_resample_evt,
+                queues,
+                queue_evts,
+            } => {
+                let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 2)?;
+                sv.serialize_field("shm", shm)?;
+                sv.serialize_field("interrupt", interrupt)?;
+                sv.serialize_field("interrupt_resample_evt", interrupt_resample_evt)?;
+                sv.serialize_field("queues", queues)?;
+                sv.serialize_field("queue_evts", queue_evts)?;
+                sv.end()
+            }
+
+            Reset => serializer.serialize_unit_variant("Request", 9, "Reset"),
+
+            GetDeviceBars(address) => {
+                let mut tv =
+                    serializer.serialize_tuple_variant("Request", 10, "GetDeviceBars", 1)?;
+                tv.serialize_field(address)?;
+                tv.end()
+            }
+
+            GetDeviceCaps => serializer.serialize_unit_variant("Request", 11, "GetDeviceCaps"),
+
+            Kill => serializer.serialize_unit_variant("Request", 12, "Kill"),
+        }
+    }
+}
+
+impl<'de> DeserializeWithFds<'de> for Request {
+    fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> {
+        struct Visitor;
+
+        impl<'de> VisitorWithFds<'de> for Visitor {
+            type Value = Request;
+
+            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                write!(f, "enum Request")
+            }
+
+            fn visit_enum<A: EnumAccessWithFds<'de>>(
+                self,
+                data: A,
+            ) -> Result<Self::Value, A::Error> {
+                #[derive(Debug, Deserialize)]
+                enum Variant {
+                    Create,
+                    DebugLabel,
+                    DeviceType,
+                    QueueMaxSizes,
+                    Features,
+                    AckFeatures,
+                    ReadConfig,
+                    WriteConfig,
+                    Activate,
+                    Reset,
+                    GetDeviceBars,
+                    GetDeviceCaps,
+                    Kill,
+                }
+
+                match data.variant()? {
+                    (Variant::Create, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::Create")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::Create with 2 elements",
+                                    )
+                                }
+
+                                Ok(Request::Create {
+                                    memory_params: seq
+                                        .next_element()?
+                                        .ok_or_else(|| too_short(0))?,
+                                    ext_socket: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(&["memory_params", "ext_socket"], Visitor)
+                    }
+
+                    (Variant::DebugLabel, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::DebugLabel)
+                    }
+
+                    (Variant::DeviceType, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::DeviceType)
+                    }
+
+                    (Variant::QueueMaxSizes, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::QueueMaxSizes)
+                    }
+
+                    (Variant::Features, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::Features)
+                    }
+
+                    (Variant::AckFeatures, variant) => {
+                        Ok(Request::AckFeatures(variant.newtype_variant()?))
+                    }
+
+                    (Variant::ReadConfig, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::ReadConfig")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::ReadConfig with 2 elements",
+                                    )
+                                }
+
+                                Ok(Request::ReadConfig {
+                                    offset: seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                    len: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(&["offset", "len"], Visitor)
+                    }
+
+                    (Variant::WriteConfig, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::WriteConfig")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::WriteConfig with 2 elements",
+                                    )
+                                }
+
+                                Ok(Request::WriteConfig {
+                                    offset: seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                    data: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(&["offset", "data"], Visitor)
+                    }
+
+                    (Variant::Activate, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "struct variant Request::Activate")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"struct variant Request::Activate with 7 elements",
+                                    )
+                                }
+
+                                Ok(Request::Activate {
+                                    shm: seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                    interrupt: seq.next_element()?.ok_or_else(|| too_short(1))?,
+                                    interrupt_resample_evt: seq
+                                        .next_element()?
+                                        .ok_or_else(|| too_short(2))?,
+                                    queues: seq.next_element()?.ok_or_else(|| too_short(3))?,
+                                    queue_evts: seq.next_element()?.ok_or_else(|| too_short(4))?,
+                                })
+                            }
+                        }
+
+                        variant.struct_variant(
+                            &[
+                                "shm",
+                                "interrupt",
+                                "interrupt_resample_evt",
+                                "in_queue",
+                                "out_queue",
+                                "in_queue_evt",
+                                "out_queue_evt",
+                            ],
+                            Visitor,
+                        )
+                    }
+
+                    (Variant::Reset, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::Reset)
+                    }
+
+                    (Variant::GetDeviceBars, variant) => {
+                        struct Visitor;
+
+                        impl<'de> VisitorWithFds<'de> for Visitor {
+                            type Value = Request;
+
+                            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
+                                write!(f, "tuple variant Request::GetDeviceBars")
+                            }
+
+                            fn visit_seq<A: SeqAccessWithFds<'de>>(
+                                self,
+                                mut seq: A,
+                            ) -> Result<Request, A::Error> {
+                                use serde::de::Error;
+
+                                fn too_short<E: Error>(len: usize) -> E {
+                                    E::invalid_length(
+                                        len,
+                                        &"tuple variant Request::GetDeviceBars with 1 elements",
+                                    )
+                                }
+
+                                Ok(Request::GetDeviceBars(
+                                    seq.next_element()?.ok_or_else(|| too_short(0))?,
+                                ))
+                            }
+                        }
+
+                        variant.struct_variant(&["bus", "dev"], Visitor)
+                    }
+
+                    (Variant::GetDeviceCaps, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::GetDeviceCaps)
+                    }
+
+                    (Variant::Kill, variant) => {
+                        variant.unit_variant()?;
+                        Ok(Request::Kill)
+                    }
+                }
+            }
+        }
+
+        deserializer.deserialize_enum(
+            "Request",
+            &[
+                "Create",
+                "DebugLabel",
+                "DeviceType",
+                "QueueMaxSizes",
+                "Features",
+                "AckFeatures",
+                "ReadConfig",
+                "WriteConfig",
+                "Activate",
+                "Reset",
+                "GetDeviceBars",
+                "GetDeviceCaps",
+                "Kill",
+            ],
+            Visitor,
+        )
+    }
+}
+
+#[derive(Debug, Deserialize, DeserializeWithFds, Serialize, SerializeWithFds)]
+#[msg_socket2(strategy = "serde")]
+pub enum Response {
+    DebugLabel(String),
+    DeviceType(u32),
+    QueueMaxSizes(Vec<u16>),
+    Features(u64),
+    ReadConfig(Vec<u8>),
+    Reset(bool),
+    GetDeviceBars(Vec<PciBarConfiguration>),
+    GetDeviceCaps(Vec<RemotePciCapability>),
+    Kill,
+}
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<remote::Response, remote::Request> =
+        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/wl.rs b/src/guest/wl.rs
index 1581b2c..e273246 100644
--- a/src/wl.rs
+++ b/src/guest/wl.rs
@@ -1,10 +1,14 @@
-// SPDX-License-Identifier: BSD-3-Clause
+// 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, RemotePciCapability, Request, Response, VirtioDevice,
-    VirtioDeviceNew, Wl,
+    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;
@@ -39,11 +43,11 @@ fn main() {
     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() {
+    let (memory_params, ext_socket) = match msg_socket.recv() {
         Ok(Request::Create {
-            device_params,
             memory_params,
-        }) => (device_params, memory_params),
+            ext_socket,
+        }) => (memory_params, ext_socket),
 
         Ok(msg) => {
             panic!("received unexpected message: {:?}", msg);
@@ -54,10 +58,18 @@ fn main() {
         }
     };
 
-    let mut wl = Wl::new(device_params).unwrap();
+    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 msg_socket.recv() {
+        match dbg!(msg_socket.recv()) {
             Ok(Request::DebugLabel) => {
                 let result = wl.debug_label();
                 if let Err(e) = msg_socket.send(Response::DebugLabel(result)) {
@@ -74,7 +86,7 @@ fn main() {
 
             Ok(Request::QueueMaxSizes) => {
                 let result = wl.queue_max_sizes();
-                if let Err(e) = msg_socket.send(Response::QueueMaxSizes(result)) {
+                if let Err(e) = msg_socket.send(dbg!(Response::QueueMaxSizes(result))) {
                     panic!("responding to QueueMaxSizes failed: {}", e);
                 }
             }
@@ -129,7 +141,7 @@ fn main() {
 
             Ok(Request::Reset) => {
                 let result = wl.reset();
-                if let Err(e) = msg_socket.send(Response::Reset(result)) {
+                if let Err(e) = msg_socket.send(dbg!(Response::Reset(result))) {
                     panic!("responding to Reset 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::<Option<Vec<_>>>()
         .ok_or(Error::InvalidWaylandPath)?;
 
-    let params = Params {
-        wayland_paths: cfg.wayland_socket_paths.clone(),
-        vm_socket,
-        resource_bridge,
-    };
-
     let dev: Box<dyn VirtioDevice> = 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/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 99fae7e..a9784b1 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -26,6 +26,7 @@ use sys_util::net::UnixSeqpacket;
 use sys_util::{error, Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result};
 
 /// A data structure that either owns or borrows a file descriptor.
+// TODO: "Borrowed" should not be holding a raw file descriptor, it should be borrowing.
 #[derive(Debug, DeserializeWithFds, SerializeWithFds)]
 #[msg_socket2(strategy = "AsRawFd")]
 pub enum MaybeOwnedFd<Owned: AsRawFd + FromRawFd> {