summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2018-06-07 15:42:41 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-07-09 17:59:23 -0700
commit228e4a6a91ea2972b2443d3959c14d862a23c358 (patch)
tree4b7fd7bf8249b7dde2fbd8b958d836bc0a12d420
parent20d71f8928e1e95f6554c87cfca12f24f9f652cf (diff)
downloadcrosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.gz
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.bz2
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.lz
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.xz
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.zst
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.zip
Move gpu allocator to resources
Combine GPU buffer allocation with the system resource allocator making
life easier as only one allocator needs to get passed to the execute
function.

Change-Id: I199eb0fd6b99b629aaec1ae3295e8a1942da5309
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1099856
-rw-r--r--Cargo.lock3
-rw-r--r--Cargo.toml2
-rw-r--r--aarch64/src/lib.rs4
-rw-r--r--arch/src/lib.rs2
-rw-r--r--devices/Cargo.toml1
-rw-r--r--devices/src/lib.rs1
-rw-r--r--devices/src/virtio/wl.rs3
-rw-r--r--resources/Cargo.toml5
-rw-r--r--resources/src/gpu_allocator.rs106
-rw-r--r--resources/src/lib.rs5
-rw-r--r--resources/src/system_allocator.rs19
-rw-r--r--src/linux.rs88
-rw-r--r--vm_control/src/lib.rs46
-rw-r--r--x86_64/src/lib.rs4
14 files changed, 160 insertions, 129 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6085049..2717631 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -104,6 +104,7 @@ dependencies = [
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "net_sys 0.1.0",
  "net_util 0.1.0",
+ "resources 0.1.0",
  "sys_util 0.1.0",
  "vhost 0.1.0",
  "virtio_sys 0.1.0",
@@ -302,6 +303,8 @@ name = "resources"
 version = "0.1.0"
 dependencies = [
  "data_model 0.1.0",
+ "gpu_buffer 0.1.0",
+ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "sys_util 0.1.0",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index 9ec3e75..43a73bd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@ panic = 'abort'
 [features]
 plugin = ["plugin_proto", "crosvm_plugin", "protobuf"]
 default-no-sandbox = []
-wl-dmabuf = ["devices/wl-dmabuf", "gpu_buffer"]
+wl-dmabuf = ["devices/wl-dmabuf", "gpu_buffer", "resources/wl-dmabuf"]
 
 [dependencies]
 arch = { path = "arch" }
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index a030d5e..35da1fd 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -205,12 +205,12 @@ impl arch::LinuxArch for AArch64 {
     }
 
     /// Returns a system resource allocator.
-    fn get_resource_allocator(mem_size: u64) -> SystemAllocator {
+    fn get_resource_allocator(mem_size: u64, gpu_allocation: bool) -> SystemAllocator {
         let device_addr_start = Self::get_base_dev_pfn(mem_size) * sys_util::pagesize() as u64;
         AddressRanges::new()
             .add_device_addresses(device_addr_start, u64::max_value() - device_addr_start)
             .add_mmio_addresses(AARCH64_MMIO_BASE, 0x10000)
-            .create_allocator(AARCH64_IRQ_BASE).unwrap()
+            .create_allocator(AARCH64_IRQ_BASE, gpu_allocation).unwrap()
     }
 
     /// This adds any early platform devices for this architecture.
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 19ea98b..1b07c62 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -87,7 +87,7 @@ pub trait LinuxArch {
     fn get_base_linux_cmdline() -> kernel_cmdline::Cmdline;
 
     /// Returns a system resource allocator.
-    fn get_resource_allocator(mem_size: u64) -> SystemAllocator;
+    fn get_resource_allocator(mem_size: u64, gpu_allocation: bool) -> SystemAllocator;
 
     /// Sets up the IO bus for this platform
     ///
diff --git a/devices/Cargo.toml b/devices/Cargo.toml
index 4581594..8b43c4b 100644
--- a/devices/Cargo.toml
+++ b/devices/Cargo.toml
@@ -13,6 +13,7 @@ libc = "*"
 io_jail = { path = "../io_jail" }
 net_sys = { path = "../net_sys" }
 net_util = { path = "../net_util" }
+resources = { path = "../resources" }
 sys_util = { path = "../sys_util" }
 vhost = { path = "../vhost" }
 virtio_sys = { path = "../virtio_sys" }
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 7ef8af2..7e3df35 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -10,6 +10,7 @@ extern crate io_jail;
 extern crate libc;
 extern crate net_sys;
 extern crate net_util;
+extern crate resources;
 #[macro_use]
 extern crate sys_util;
 extern crate vhost;
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index 1ec6873..b946c51 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -58,13 +58,14 @@ use libc::{dup, EBADF, EINVAL};
 use data_model::*;
 use data_model::VolatileMemoryError;
 
+use resources::GpuMemoryDesc;
 use sys_util::{Error, Result, EventFd, Scm, SharedMemory, GuestAddress, GuestMemory,
                GuestMemoryError, PollContext, PollToken, FileFlags, pipe, round_up_to_page_size};
 
 #[cfg(feature = "wl-dmabuf")]
 use sys_util::ioctl_with_ref;
 
-use vm_control::{VmControlError, VmRequest, VmResponse, MaybeOwnedFd, GpuMemoryDesc};
+use vm_control::{VmControlError, VmRequest, VmResponse, MaybeOwnedFd};
 use super::{VirtioDevice, Queue, DescriptorChain, INTERRUPT_STATUS_USED_RING, TYPE_WL};
 
 const VIRTWL_SEND_MAX_ALLOCS: usize = 28;
diff --git a/resources/Cargo.toml b/resources/Cargo.toml
index 2569f9d..29fc38a 100644
--- a/resources/Cargo.toml
+++ b/resources/Cargo.toml
@@ -3,6 +3,11 @@ name = "resources"
 version = "0.1.0"
 authors = ["The Chromium OS Authors"]
 
+[features]
+wl-dmabuf = ["gpu_buffer"]
+
 [dependencies]
 data_model = { path = "../data_model" }
+gpu_buffer = { path = "../gpu_buffer", optional = true }
+libc = "*"
 sys_util = { path = "../sys_util" }
diff --git a/resources/src/gpu_allocator.rs b/resources/src/gpu_allocator.rs
new file mode 100644
index 0000000..ea38ba4
--- /dev/null
+++ b/resources/src/gpu_allocator.rs
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+
+#[cfg(feature = "wl-dmabuf")]
+use libc::EINVAL;
+
+#[cfg(feature = "wl-dmabuf")]
+use gpu_buffer;
+use sys_util;
+
+#[derive(Debug)]
+pub enum GpuAllocatorError {
+    OpenGpuBufferDevice,
+    CreateGpuBufferDevice,
+}
+
+/// Struct that describes the offset and stride of a plane located in GPU memory.
+#[derive(Clone, Copy, Debug, PartialEq, Default)]
+pub struct GpuMemoryPlaneDesc {
+    pub stride: u32,
+    pub offset: u32,
+}
+
+/// Struct that describes a GPU memory allocation that consists of up to 3 planes.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct GpuMemoryDesc {
+    pub planes: [GpuMemoryPlaneDesc; 3],
+}
+
+/// Trait that needs to be implemented in order to service GPU memory allocation
+/// requests. Implementations are expected to support some set of buffer sizes and
+/// formats but every possible combination is not required.
+pub trait GpuMemoryAllocator {
+    /// Allocates GPU memory for a buffer of a specific size and format. The memory
+    /// layout for the returned buffer must be linear. A file handle and the
+    /// description of the planes for the buffer are returned on success.
+    ///
+    /// # Arguments
+    /// * `width` - Width of buffer.
+    /// * `height` - Height of buffer.
+    /// * `format` - Fourcc format of buffer.
+    fn allocate(&self, width: u32, height: u32, format: u32)
+        -> sys_util::Result<(File, GpuMemoryDesc)>;
+}
+
+#[cfg(feature = "wl-dmabuf")]
+pub struct GpuBufferDevice {
+    device: gpu_buffer::Device,
+}
+
+#[cfg(feature = "wl-dmabuf")]
+impl GpuMemoryAllocator for GpuBufferDevice {
+    fn allocate(&self, width: u32, height: u32, format: u32) ->
+        sys_util::Result<(File, GpuMemoryDesc)>
+    {
+        let buffer = match self.device.create_buffer(
+            width,
+            height,
+            gpu_buffer::Format::from(format),
+            // Linear layout is a requirement as virtio wayland guest expects
+            // this for CPU access to the buffer. Scanout and texturing are
+            // optional as the consumer (wayland compositor) is expected to
+            // fall-back to a less efficient meachnisms for presentation if
+            // neccesary. In practice, linear buffers for commonly used formats
+            // will also support scanout and texturing.
+            gpu_buffer::Flags::empty().use_linear(true)) {
+            Ok(v) => v,
+            Err(_) => return Err(sys_util::Error::new(EINVAL)),
+        };
+        // We only support one FD. Buffers with multiple planes are supported
+        // as long as each plane is associated with the same handle.
+        let fd = match buffer.export_plane_fd(0) {
+            Ok(v) => v,
+            Err(e) => return Err(sys_util::Error::new(e)),
+        };
+
+        let mut desc = GpuMemoryDesc::default();
+        for i in 0..buffer.num_planes() {
+            // Use stride and offset for plane if handle matches first plane.
+            if buffer.plane_handle(i) == buffer.plane_handle(0) {
+                desc.planes[i] = GpuMemoryPlaneDesc { stride: buffer.plane_stride(i),
+                                                      offset: buffer.plane_offset(i) }
+            }
+        }
+
+        Ok((fd, desc))
+    }
+}
+
+#[cfg(feature = "wl-dmabuf")]
+pub fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>, GpuAllocatorError> {
+    let undesired: &[&str] = &["vgem", "pvr"];
+    let fd = gpu_buffer::rendernode::open_device(undesired)
+        .map_err(|_| GpuAllocatorError::OpenGpuBufferDevice)?;
+    let device = gpu_buffer::Device::new(fd)
+        .map_err(|_| GpuAllocatorError::CreateGpuBufferDevice)?;
+    Ok(Some(Box::new(GpuBufferDevice { device })))
+}
+
+#[cfg(not(feature = "wl-dmabuf"))]
+pub fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>, GpuAllocatorError> {
+    Ok(None)
+}
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index 11cc905..5d12cfc 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -4,10 +4,15 @@
 
 //! Manages system resources that can be allocated to VMs and their devices.
 
+#[cfg(feature = "wl-dmabuf")]
+extern crate gpu_buffer;
+extern crate libc;
 extern crate sys_util;
 
 mod address_allocator;
+mod gpu_allocator;
 mod system_allocator;
 
 pub use address_allocator::AddressAllocator;
+pub use gpu_allocator::{GpuMemoryAllocator, GpuMemoryDesc, GpuMemoryPlaneDesc};
 pub use system_allocator::{AddressRanges, SystemAllocator};
diff --git a/resources/src/system_allocator.rs b/resources/src/system_allocator.rs
index fec8b41..7c406c9 100644
--- a/resources/src/system_allocator.rs
+++ b/resources/src/system_allocator.rs
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 use address_allocator::AddressAllocator;
+use gpu_allocator::{self, GpuMemoryAllocator};
 use sys_util::pagesize;
 
 /// Manages allocating system resources such as address space and interrupt numbers.
@@ -21,11 +22,11 @@ use sys_util::pagesize;
 ///       assert_eq!(a.allocate_device_addresses(0x100), Some(0x10000000));
 ///   }
 /// ```
-#[derive(Debug, Eq, PartialEq)]
 pub struct SystemAllocator {
     io_address_space: Option<AddressAllocator>,
     device_address_space: AddressAllocator,
     mmio_address_space: AddressAllocator,
+    gpu_allocator: Option<Box<GpuMemoryAllocator>>,
     next_irq: u32,
 }
 
@@ -40,10 +41,12 @@ impl SystemAllocator {
     /// * `dev_size` - The size of device memory.
     /// * `mmio_base` - The starting address of MMIO space.
     /// * `mmio_size` - The size of MMIO space.
+    /// * `create_gpu_allocator` - If true, enable gpu memory allocation.
     /// * `first_irq` - The first irq number to give out.
     fn new(io_base: Option<u64>, io_size: Option<u64>,
            dev_base: u64, dev_size: u64,
            mmio_base: u64, mmio_size: u64,
+           create_gpu_allocator: bool,
            first_irq: u32) -> Option<Self> {
         let page_size = pagesize() as u64;
         Some(SystemAllocator {
@@ -54,6 +57,11 @@ impl SystemAllocator {
             },
             device_address_space: AddressAllocator::new(dev_base, dev_size, Some(page_size))?,
             mmio_address_space: AddressAllocator::new(mmio_base, mmio_size, Some(page_size))?,
+            gpu_allocator: if create_gpu_allocator {
+                gpu_allocator::create_gpu_memory_allocator().ok()?
+            } else {
+                None
+            },
             next_irq: first_irq,
         })
     }
@@ -82,6 +90,11 @@ impl SystemAllocator {
     pub fn allocate_mmio_addresses(&mut self, size: u64) -> Option<u64> {
         self.mmio_address_space.allocate(size)
     }
+
+    /// Gets an allocator to be used for GPU memory.
+    pub fn gpu_memory_allocator(&self) -> Option<&GpuMemoryAllocator> {
+        self.gpu_allocator.as_ref().map(|v| v.as_ref())
+    }
 }
 
 /// Used to build a system address map for use in creating a `SystemAllocator`.
@@ -124,10 +137,12 @@ impl AddressRanges {
         self
     }
 
-    pub fn create_allocator(&self, first_irq: u32) -> Option<SystemAllocator> {
+    pub fn create_allocator(&self, first_irq: u32,
+                            gpu_allocation: bool) -> Option<SystemAllocator> {
         SystemAllocator::new(self.io_base, self.io_size,
                              self.device_base?, self.device_size?,
                              self.mmio_base?, self.mmio_size?,
+                             gpu_allocation,
                              first_irq)
     }
 }
diff --git a/src/linux.rs b/src/linux.rs
index cc4abed..1c524db 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -18,8 +18,6 @@ use std::thread::JoinHandle;
 
 use libc;
 use libc::c_int;
-#[cfg(feature = "wl-dmabuf")]
-use libc::EINVAL;
 
 use devices;
 use io_jail::{self, Minijail};
@@ -31,9 +29,7 @@ use sys_util::*;
 use sys_util;
 use resources::SystemAllocator;
 use vhost;
-use vm_control::{VmRequest, GpuMemoryAllocator, GpuMemoryPlaneDesc, GpuMemoryDesc};
-#[cfg(feature = "wl-dmabuf")]
-use gpu_buffer;
+use vm_control::VmRequest;
 
 use Config;
 use DiskType;
@@ -53,7 +49,6 @@ pub enum Error {
     CloneEventFd(sys_util::Error),
     Cmdline(kernel_cmdline::Error),
     CreateEventFd(sys_util::Error),
-    CreateGpuBufferDevice,
     CreateGuestMemory(Box<error::Error>),
     CreateIrqChip(Box<error::Error>),
     CreateKvm(sys_util::Error),
@@ -72,7 +67,6 @@ pub enum Error {
     NetDeviceNew(devices::virtio::NetError),
     NoVarEmpty,
     OpenKernel(PathBuf, io::Error),
-    OpenGpuBufferDevice,
     PollContextAdd(sys_util::Error),
     QcowDeviceCreate(qcow::Error),
     RegisterBalloon(MmioRegisterError),
@@ -107,7 +101,6 @@ impl fmt::Display for Error {
             &Error::CloneEventFd(ref e) => write!(f, "failed to clone eventfd: {:?}", e),
             &Error::Cmdline(ref e) => write!(f, "the given kernel command line was invalid: {}", e),
             &Error::CreateEventFd(ref e) => write!(f, "failed to create eventfd: {:?}", e),
-            &Error::CreateGpuBufferDevice => write!(f, "failed to create GPU buffer device"),
             &Error::CreateGuestMemory(ref e) => write!(f, "failed to create guest memory: {:?}", e),
             &Error::CreateIrqChip(ref e) => {
                 write!(f, "failed to create in-kernel IRQ chip: {:?}", e)
@@ -132,7 +125,6 @@ impl fmt::Display for Error {
             &Error::OpenKernel(ref p, ref e) => {
                 write!(f, "failed to open kernel image {:?}: {}", p, e)
             }
-            &Error::OpenGpuBufferDevice => write!(f, "failed to open GPU buffer device"),
             &Error::PollContextAdd(ref e) => write!(f, "failed to add fd to poll context: {:?}", e),
             &Error::QcowDeviceCreate(ref e) => {
                 write!(f, "failed to read qcow formatted file {:?}", e)
@@ -672,65 +664,6 @@ fn run_vcpu(vcpu: Vcpu,
         .map_err(Error::SpawnVcpu)
 }
 
-#[cfg(feature = "wl-dmabuf")]
-struct GpuBufferDevice {
-    device: gpu_buffer::Device,
-}
-
-#[cfg(feature = "wl-dmabuf")]
-impl GpuMemoryAllocator for GpuBufferDevice {
-    fn allocate(&self, width: u32, height: u32, format: u32) ->
-        sys_util::Result<(File, GpuMemoryDesc)> {
-        let buffer = match self.device.create_buffer(
-            width,
-            height,
-            gpu_buffer::Format::from(format),
-            // Linear layout is a requirement as virtio wayland guest expects
-            // this for CPU access to the buffer. Scanout and texturing are
-            // optional as the consumer (wayland compositor) is expected to
-            // fall-back to a less efficient meachnisms for presentation if
-            // neccesary. In practice, linear buffers for commonly used formats
-            // will also support scanout and texturing.
-            gpu_buffer::Flags::empty().use_linear(true)) {
-            Ok(v) => v,
-            Err(_) => return Err(sys_util::Error::new(EINVAL)),
-        };
-        // We only support one FD. Buffers with multiple planes are supported
-        // as long as each plane is associated with the same handle.
-        let fd = match buffer.export_plane_fd(0) {
-            Ok(v) => v,
-            Err(e) => return Err(sys_util::Error::new(e)),
-        };
-
-        let mut desc = GpuMemoryDesc::default();
-        for i in 0..buffer.num_planes() {
-            // Use stride and offset for plane if handle matches first plane.
-            if buffer.plane_handle(i) == buffer.plane_handle(0) {
-                desc.planes[i] = GpuMemoryPlaneDesc { stride: buffer.plane_stride(i),
-                                                      offset: buffer.plane_offset(i) }
-            }
-        }
-
-        Ok((fd, desc))
-    }
-}
-
-#[cfg(feature = "wl-dmabuf")]
-fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>> {
-    let undesired: &[&str] = &["vgem", "pvr"];
-    let fd = gpu_buffer::rendernode::open_device(undesired)
-        .map_err(|_| Error::OpenGpuBufferDevice)?;
-    let device = gpu_buffer::Device::new(fd)
-        .map_err(|_| Error::CreateGpuBufferDevice)?;
-    info!("created GPU buffer device for DMABuf allocations");
-    Ok(Some(Box::new(GpuBufferDevice { device })))
-}
-
-#[cfg(not(feature = "wl-dmabuf"))]
-fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>> {
-    Ok(None)
-}
-
 fn run_control(mut vm: Vm,
                control_sockets: Vec<UnlinkUnixDatagram>,
                mut resources: SystemAllocator,
@@ -740,8 +673,7 @@ fn run_control(mut vm: Vm,
                kill_signaled: Arc<AtomicBool>,
                vcpu_handles: Vec<JoinHandle<()>>,
                balloon_host_socket: UnixDatagram,
-               _irqchip_fd: Option<File>,
-               gpu_memory_allocator: Option<Box<GpuMemoryAllocator>>)
+               _irqchip_fd: Option<File>)
                -> Result<()> {
     const MAX_VM_FD_RECV: usize = 1;
 
@@ -830,10 +762,7 @@ fn run_control(mut vm: Vm,
                                     request.execute(&mut vm,
                                                     &mut resources,
                                                     &mut running,
-                                                    &balloon_host_socket,
-                                                    gpu_memory_allocator.as_ref().map(|v| {
-                                                                                          v.as_ref()
-                                                                                      }));
+                                                    &balloon_host_socket);
                                 if let Err(e) = response.send(&mut scm, socket.as_ref()) {
                                     error!("failed to send VmResponse: {:?}", e);
                                 }
@@ -915,7 +844,7 @@ pub fn run_config(cfg: Config) -> Result<()> {
     let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
 
     let mem_size = cfg.memory.unwrap_or(256) << 20;
-    let mut resources = Arch::get_resource_allocator(mem_size as u64);
+    let mut resources = Arch::get_resource_allocator(mem_size as u64, cfg.wayland_dmabuf);
     let mem = Arch::setup_memory(mem_size as u64).map_err(|e| Error::CreateGuestMemory(e))?;
     let kvm = Kvm::new().map_err(Error::CreateKvm)?;
     let mut vm = Arch::create_vm(&kvm, mem.clone()).map_err(|e| Error::CreateVm(e))?;
@@ -946,12 +875,6 @@ pub fn run_config(cfg: Config) -> Result<()> {
                                   balloon_device_socket,
                                   &mut resources)?;
 
-    let gpu_memory_allocator = if cfg.wayland_dmabuf {
-        create_gpu_memory_allocator()?
-    } else {
-        None
-    };
-
     for param in &cfg.params {
         cmdline.insert_str(&param).map_err(Error::Cmdline)?;
     }
@@ -988,6 +911,5 @@ pub fn run_config(cfg: Config) -> Result<()> {
                 kill_signaled,
                 vcpu_handles,
                 balloon_host_socket,
-                irq_chip,
-                gpu_memory_allocator)
+                irq_chip)
 }
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index f90520d..ad123a1 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -28,7 +28,7 @@ use libc::{ERANGE, EINVAL, ENODEV};
 use byteorder::{LittleEndian, WriteBytesExt};
 use data_model::{DataInit, Le32, Le64, VolatileMemory};
 use sys_util::{EventFd, Result, Error as SysError, MmapError, MemoryMapping, Scm, GuestAddress};
-use resources::SystemAllocator;
+use resources::{GpuMemoryDesc, GpuMemoryPlaneDesc, SystemAllocator};
 use kvm::{IoeventAddress, Vm};
 
 #[derive(Debug, PartialEq)]
@@ -130,34 +130,6 @@ fn register_memory(vm: &mut Vm, allocator: &mut SystemAllocator,
     Ok((addr >> 12, slot))
 }
 
-/// Struct that describes the offset and stride of a plane located in GPU memory.
-#[derive(Clone, Copy, Debug, PartialEq, Default)]
-pub struct GpuMemoryPlaneDesc {
-    pub stride: u32,
-    pub offset: u32,
-}
-
-/// Struct that describes a GPU memory allocation that consists of up to 3 planes.
-#[derive(Clone, Copy, Debug, Default)]
-pub struct GpuMemoryDesc {
-    pub planes: [GpuMemoryPlaneDesc; 3],
-}
-
-/// Trait that needs to be implemented in order to service GPU memory allocation
-/// requests. Implementations are expected to support some set of buffer sizes and
-/// formats but every possible combination is not required.
-pub trait GpuMemoryAllocator {
-    /// Allocates GPU memory for a buffer of a specific size and format. The memory
-    /// layout for the returned buffer must be linear. A file handle and the
-    /// description of the planes for the buffer are returned on success.
-    ///
-    /// # Arguments
-    /// * `width` - Width of buffer.
-    /// * `height` - Height of buffer.
-    /// * `format` - Fourcc format of buffer.
-    fn allocate(&self, width: u32, height: u32, format: u32) -> Result<(File, GpuMemoryDesc)>;
-}
-
 impl VmRequest {
     /// Receive a `VmRequest` from the given socket.
     ///
@@ -247,8 +219,7 @@ impl VmRequest {
     /// `VmResponse` with the intended purpose of sending the response back over the  socket that
     /// received this `VmRequest`.
     pub fn execute(&self, vm: &mut Vm, sys_allocator: &mut SystemAllocator, running: &mut bool,
-                   balloon_host_socket: &UnixDatagram,
-                   gpu_memory_allocator: Option<&GpuMemoryAllocator>) -> VmResponse {
+                   balloon_host_socket: &UnixDatagram) -> VmResponse {
         *running = true;
         match self {
             &VmRequest::Exit => {
@@ -289,14 +260,15 @@ impl VmRequest {
                 }
             }
             &VmRequest::AllocateAndRegisterGpuMemory {width, height, format} => {
-                let gpu_allocator = match gpu_memory_allocator {
-                    Some(v) => v,
+                let (mut fd, desc) = match sys_allocator.gpu_memory_allocator() {
+                    Some(gpu_allocator) => {
+                        match gpu_allocator.allocate(width, height, format) {
+                            Ok(v) => v,
+                            Err(e) => return VmResponse::Err(e),
+                        }
+                    }
                     None => return VmResponse::Err(SysError::new(ENODEV)),
                 };
-                let (mut fd, desc) = match gpu_allocator.allocate(width, height, format) {
-                    Ok(v) => v,
-                    Err(e) => return VmResponse::Err(e),
-                };
                 // Determine size of buffer using 0 byte seek from end. This is preferred over
                 // `stride * height` as it's not limited to packed pixel formats.
                 let size = match fd.seek(SeekFrom::End(0)) {
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index 1e13e77..c887baa 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -317,14 +317,14 @@ impl arch::LinuxArch for X8664arch {
     }
 
     /// Returns a system resource allocator.
-    fn get_resource_allocator(mem_size: u64) -> SystemAllocator {
+    fn get_resource_allocator(mem_size: u64, gpu_allocation: bool) -> SystemAllocator {
         const MMIO_BASE: u64 = 0xe0000000;
         let device_addr_start = Self::get_base_dev_pfn(mem_size) * sys_util::pagesize() as u64;
         AddressRanges::new()
            .add_io_addresses(0xc000, 0x10000)
            .add_mmio_addresses(MMIO_BASE, 0x10000)
            .add_device_addresses(device_addr_start, u64::max_value() - device_addr_start)
-           .create_allocator(X86_64_IRQ_BASE).unwrap()
+           .create_allocator(X86_64_IRQ_BASE, gpu_allocation).unwrap()
     }
 
     /// Sets up the IO bus for this platform