mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-12-24 11:58:41 +00:00
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
This commit is contained in:
parent
20d71f8928
commit
228e4a6a91
14 changed files with 160 additions and 129 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" }
|
||||
|
|
106
resources/src/gpu_allocator.rs
Normal file
106
resources/src/gpu_allocator.rs
Normal file
|
@ -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)
|
||||
}
|
|
@ -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};
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
88
src/linux.rs
88
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(¶m).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)
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue