summary refs log tree commit diff
diff options
context:
space:
mode:
-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