summary refs log tree commit diff
diff options
context:
space:
mode:
authorGurchetan Singh <gurchetansingh@chromium.org>2019-05-15 17:44:46 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-01 07:53:32 +0000
commit7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec (patch)
treeefab4022bfa9ad49a795488fa143adaca9e20d25
parentf585543065c052fc67d3e9f8683e6a91395ca1ae (diff)
downloadcrosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.tar
crosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.tar.gz
crosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.tar.bz2
crosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.tar.lz
crosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.tar.xz
crosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.tar.zst
crosvm-7ca5e3dba3f56c8b8b762e63af7808bf9414c1ec.zip
vm_control: support registering memory at a specific address
The guest kernel will allocate from PCI range of the virtgpu
device, and send physical addresses via a hypercall.

Right now, only support buffers that can be mmap'ed.  We could
add optimizations for GBM buffers later if needed.

BUG=chromium:924405
TEST=compile

Change-Id: I094de96a2c35bcd2e18c8a6a2d8cdc39bb392e36
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1626794
Tested-by: kokoro <noreply+kokoro@google.com>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
-rw-r--r--resources/src/lib.rs3
-rw-r--r--vm_control/src/lib.rs63
2 files changed, 51 insertions, 15 deletions
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index c10608e..ce4855a 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -10,6 +10,7 @@ extern crate libc;
 extern crate msg_socket;
 extern crate sys_util;
 
+use msg_socket::MsgOnSocket;
 use std::fmt::Display;
 
 pub use crate::address_allocator::AddressAllocator;
@@ -23,7 +24,7 @@ mod gpu_allocator;
 mod system_allocator;
 
 /// Used to tag SystemAllocator allocations.
-#[derive(Debug, Eq, PartialEq, Hash)]
+#[derive(Debug, Eq, PartialEq, Hash, MsgOnSocket, Copy, Clone)]
 pub enum Alloc {
     /// An anonymous resource allocation.
     /// Should only be instantiated through `SystemAllocator::get_anon_alloc()`.
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 8023abe..e5d18e3 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -19,7 +19,7 @@ use libc::{EINVAL, EIO, ENODEV};
 
 use kvm::Vm;
 use msg_socket::{MsgOnSocket, MsgReceiver, MsgResult, MsgSender, MsgSocket};
-use resources::{GpuMemoryDesc, SystemAllocator};
+use resources::{Alloc, GpuMemoryDesc, SystemAllocator};
 use sys_util::{error, Error as SysError, GuestAddress, MemoryMapping, MmapError, Result};
 
 /// A file descriptor either borrowed or owned by this.
@@ -189,6 +189,9 @@ pub enum VmMemoryRequest {
     /// Register shared memory represented by the given fd into guest address space. The response
     /// variant is `VmResponse::RegisterMemory`.
     RegisterMemory(MaybeOwnedFd, usize),
+    /// Similiar to `VmMemoryRequest::RegisterMemory`, but doesn't allocate new address space.
+    /// Useful for cases where the address space is already allocated (PCI regions).
+    RegisterMemoryAtAddress(Alloc, MaybeOwnedFd, usize, u64),
     /// Unregister the given memory slot that was previously registereed with `RegisterMemory`.
     UnregisterMemory(u32),
     /// Allocate GPU buffer of a given size/format and register the memory into guest address space.
@@ -213,10 +216,18 @@ impl VmMemoryRequest {
     pub fn execute(&self, vm: &mut Vm, sys_allocator: &mut SystemAllocator) -> VmMemoryResponse {
         use self::VmMemoryRequest::*;
         match *self {
-            RegisterMemory(ref fd, size) => match register_memory(vm, sys_allocator, fd, size) {
-                Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
-                Err(e) => VmMemoryResponse::Err(e),
-            },
+            RegisterMemory(ref fd, size) => {
+                match register_memory(vm, sys_allocator, fd, size, None) {
+                    Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
+                    Err(e) => VmMemoryResponse::Err(e),
+                }
+            }
+            RegisterMemoryAtAddress(alloc, ref fd, size, guest_addr) => {
+                match register_memory(vm, sys_allocator, fd, size, Some((alloc, guest_addr))) {
+                    Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
+                    Err(e) => VmMemoryResponse::Err(e),
+                }
+            }
             UnregisterMemory(slot) => match vm.remove_device_memory(slot) {
                 Ok(_) => VmMemoryResponse::Ok,
                 Err(e) => VmMemoryResponse::Err(e),
@@ -239,7 +250,7 @@ impl VmMemoryRequest {
                     Ok(v) => v,
                     Err(e) => return VmMemoryResponse::Err(SysError::from(e)),
                 };
-                match register_memory(vm, sys_allocator, &fd, size as usize) {
+                match register_memory(vm, sys_allocator, &fd, size as usize, None) {
                     Ok((pfn, slot)) => VmMemoryResponse::AllocateAndRegisterGpuMemory {
                         fd: MaybeOwnedFd::Owned(fd),
                         pfn,
@@ -315,21 +326,45 @@ fn register_memory(
     allocator: &mut SystemAllocator,
     fd: &dyn AsRawFd,
     size: usize,
+    allocation: Option<(Alloc, u64)>,
 ) -> Result<(u64, u32)> {
     let mmap = match MemoryMapping::from_fd(fd, size) {
         Ok(v) => v,
         Err(MmapError::SystemCallFailed(e)) => return Err(e),
         _ => return Err(SysError::new(EINVAL)),
     };
-    let alloc = allocator.get_anon_alloc();
-    let addr = match allocator.device_allocator().allocate(
-        size as u64,
-        alloc,
-        "vmcontrol_register_memory".to_string(),
-    ) {
-        Ok(a) => a,
-        Err(_) => return Err(SysError::new(EINVAL)),
+
+    let addr = match allocation {
+        Some((Alloc::PciBar { bus, dev, bar }, address)) => {
+            match allocator
+                .device_allocator()
+                .get(&Alloc::PciBar { bus, dev, bar })
+            {
+                Some((start_addr, length, _)) => {
+                    let range = *start_addr..*start_addr + *length;
+                    let end = address + (size as u64);
+                    match (range.contains(&address), range.contains(&end)) {
+                        (true, true) => address,
+                        _ => return Err(SysError::new(EINVAL)),
+                    }
+                }
+                None => return Err(SysError::new(EINVAL)),
+            }
+        }
+        None => {
+            let alloc = allocator.get_anon_alloc();
+            match allocator.device_allocator().allocate(
+                size as u64,
+                alloc,
+                "vmcontrol_register_memory".to_string(),
+            ) {
+                Ok(a) => a,
+                _ => return Err(SysError::new(EINVAL)),
+            }
+        }
+        _ => return Err(SysError::new(EINVAL)),
     };
+
     let slot = match vm.add_device_memory(GuestAddress(addr), mmap, false, false) {
         Ok(v) => v,
         Err(e) => return Err(e),