From 0a06043e327d51db09bbb7295cb15a0408845bc8 Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Mon, 23 Sep 2019 15:20:28 -0400 Subject: [PATCH] support dmabuf in virtio_wl --- ph-init/src/init.rs | 22 +++- src/devices/virtio_wl/device.rs | 77 ++++++++++++- src/devices/virtio_wl/mod.rs | 9 ++ src/devices/virtio_wl/shm.rs | 11 +- src/devices/virtio_wl/vfd.rs | 9 +- src/main.rs | 2 +- src/memory/drm.rs | 192 ++++++++++++++++++++++++++++++++ src/memory/manager.rs | 35 +++++- src/memory/mod.rs | 19 +++- src/vm/config.rs | 38 ++++++- src/vm/error.rs | 3 + src/vm/mod.rs | 18 ++- 12 files changed, 417 insertions(+), 18 deletions(-) create mode 100644 src/memory/drm.rs diff --git a/ph-init/src/init.rs b/ph-init/src/init.rs index 9a8f843..933e90f 100644 --- a/ph-init/src/init.rs +++ b/ph-init/src/init.rs @@ -160,6 +160,12 @@ impl InitServer { } pub fn run_daemons(&mut self) -> Result<()> { + if !Path::new("/dev/wl0").exists() { + return Ok(()); + } + + chmod("/dev/wl0", 0o666)?; + let dbus = ServiceLaunch::new("dbus-daemon", "/usr/bin/dbus-daemon") .base_environment() .uidgid(1000,1000) @@ -178,20 +184,34 @@ impl InitServer { self.services.insert(dbus.pid(), dbus); + let shm_driver = if self.cmdline.has_var("phinit.virtwl_dmabuf") { + "virtwl-dmabuf" + } else { + "virtwl" + }; + let sommelier = ServiceLaunch::new("sommelier", "/opt/ph/usr/bin/sommelier") .base_environment() .uidgid(1000,1000) + .env("SOMMELIER_SHM_DRIVER", shm_driver) .arg("--master") .pipe_output() .launch()?; self.services.insert(sommelier.pid(), sommelier); - Self::write_xauth().map_err(Error::XAuthFail)?; + + if self.cmdline.has_var("phinit.no_x11") { + return Ok(()); + } + + mkdir_mode("/tmp/.X11-unix", 0o1777)?; + self.write_xauth().map_err(Error::XAuthFail)?; let sommelierx = ServiceLaunch::new("sommelier-x", "/opt/ph/usr/bin/sommelier") .base_environment() .uidgid(1000,1000) + .env("SOMMELIER_SHM_DRIVER", shm_driver) .arg("-X") .arg("--x-display=0") .arg("--no-exit-with-child") diff --git a/src/devices/virtio_wl/device.rs b/src/devices/virtio_wl/device.rs index ea185d2..d481834 100644 --- a/src/devices/virtio_wl/device.rs +++ b/src/devices/virtio_wl/device.rs @@ -4,10 +4,19 @@ use std::thread; use crate::{vm, system}; use crate::system::EPoll; -use crate::memory::MemoryManager; +use crate::memory::{MemoryManager, DrmDescriptor}; use crate::virtio::{VirtQueue, EventFd, Chain, VirtioBus, VirtioDeviceOps}; use crate::devices::virtio_wl::{vfd::VfdManager, consts::*, Error, Result, VfdObject}; +use crate::system::ioctl::ioctl_with_ref; +use std::os::raw::{c_ulong, c_uint, c_ulonglong}; + +#[repr(C)] +struct dma_buf_sync { + flags: c_ulonglong, +} +const DMA_BUF_IOCTL_BASE: c_uint = 0x62; +const DMA_BUF_IOCTL_SYNC: c_ulong = iow!(DMA_BUF_IOCTL_BASE, 0, ::std::mem::size_of::() as i32); pub struct VirtioWayland { feature_bits: u64, @@ -165,6 +174,8 @@ impl <'a> MessageHandler<'a> { VIRTIO_WL_CMD_VFD_NEW => self.cmd_new_alloc(), VIRTIO_WL_CMD_VFD_CLOSE => self.cmd_close(), VIRTIO_WL_CMD_VFD_SEND => self.cmd_send(), + VIRTIO_WL_CMD_VFD_NEW_DMABUF => self.cmd_new_dmabuf(), + VIRTIO_WL_CMD_VFD_DMABUF_SYNC => self.cmd_dmabuf_sync(), VIRTIO_WL_CMD_VFD_NEW_CTX => self.cmd_new_ctx(), VIRTIO_WL_CMD_VFD_NEW_PIPE => self.cmd_new_pipe(), v => { @@ -198,6 +209,70 @@ impl <'a> MessageHandler<'a> { Ok(()) } + fn cmd_new_dmabuf(&mut self) -> Result<()> { + let id = self.chain.r32()?; + let _flags = self.chain.r32()?; + let _pfn = self.chain.r64()?; + let _size = self.chain.r32()?; + let width = self.chain.r32()?; + let height = self.chain.r32()?; + let format = self.chain.r32()?; + + match self.device.vfd_manager.create_dmabuf(id, width,height, format) { + Ok((pfn, size, desc)) => self.resp_dmabuf_new(id, pfn, size as u32, desc), + Err(e) => { + if !(height == 0 && width == 0) { + warn!("virtio_wl: Failed to create dmabuf: {}", e); + } + self.responded = true; + self.send_err() + } + } + } + + fn resp_dmabuf_new(&mut self, id: u32, pfn: u64, size: u32, desc: DrmDescriptor) -> Result<()> { + self.chain.w32(VIRTIO_WL_RESP_VFD_NEW_DMABUF)?; + self.chain.w32(0)?; + self.chain.w32(id)?; + self.chain.w32(0)?; + self.chain.w64(pfn)?; + self.chain.w32(size)?; + self.chain.w32(0)?; + self.chain.w32(0)?; + self.chain.w32(0)?; + self.chain.w32(desc.planes[0].stride)?; + self.chain.w32(desc.planes[1].stride)?; + self.chain.w32(desc.planes[2].stride)?; + self.chain.w32(desc.planes[0].offset)?; + self.chain.w32(desc.planes[1].offset)?; + self.chain.w32(desc.planes[2].offset)?; + self.responded = true; + Ok(()) + } + + fn cmd_dmabuf_sync(&mut self) -> Result<()> { + let id = self.chain.r32()?; + let flags = self.chain.r32()?; + + let vfd = match self.device.get_mut_vfd(id) { + Some(vfd) => vfd, + None => return self.send_invalid_id(), + }; + let fd = match vfd.send_fd() { + Some(fd) => fd, + None => return self.send_invalid_id(), + }; + + unsafe { + let sync = dma_buf_sync { + flags: flags as u64, + }; + ioctl_with_ref(fd, DMA_BUF_IOCTL_SYNC, &sync).map_err(Error::DmaSync)?; + } + + self.send_ok() + } + fn cmd_close(&mut self) -> Result<()> { let id = self.chain.r32()?; self.device.vfd_manager.close_vfd(id)?; diff --git a/src/devices/virtio_wl/mod.rs b/src/devices/virtio_wl/mod.rs index ce49985..e749f22 100644 --- a/src/devices/virtio_wl/mod.rs +++ b/src/devices/virtio_wl/mod.rs @@ -23,8 +23,11 @@ mod consts { pub const VIRTIO_WL_CMD_VFD_NEW_CTX: u32 = 260; pub const VIRTIO_WL_CMD_VFD_NEW_PIPE: u32 = 261; pub const VIRTIO_WL_CMD_VFD_HUP: u32 = 262; + pub const VIRTIO_WL_CMD_VFD_NEW_DMABUF: u32 = 263; + pub const VIRTIO_WL_CMD_VFD_DMABUF_SYNC: u32 = 264; pub const VIRTIO_WL_RESP_OK: u32 = 4096; pub const VIRTIO_WL_RESP_VFD_NEW: u32 = 4097; + pub const VIRTIO_WL_RESP_VFD_NEW_DMABUF: u32 = 4098; pub const VIRTIO_WL_RESP_ERR: u32 = 4352; pub const VIRTIO_WL_RESP_OUT_OF_MEMORY: u32 = 4353; pub const VIRTIO_WL_RESP_INVALID_ID: u32 = 4354; @@ -93,6 +96,9 @@ pub enum Error { TooManySendVfds(usize), FailedPollContextCreate(system::Error), FailedPollAdd(system::Error), + DmaSync(vm::Error), + DmaBuf(MemError), + DmaBufSize(system::Error), } impl fmt::Display for Error { @@ -113,6 +119,9 @@ impl fmt::Display for Error { TooManySendVfds(n) => write!(f, "message has too many vfd ids: {}", n), FailedPollContextCreate(e) => write!(f, "failed creating poll context: {}", e), FailedPollAdd(e) => write!(f, "failed adding fd to poll context: {}", e), + DmaSync(e) => write!(f, "error calling dma sync: {}", e), + DmaBuf(e) => write!(f, "failed creating DMA buf: {}", e), + DmaBufSize(e) => write!(f, "failed getting DMA buf size: {}", e), } } } diff --git a/src/devices/virtio_wl/shm.rs b/src/devices/virtio_wl/shm.rs index 49a9164..facf4f3 100644 --- a/src/devices/virtio_wl/shm.rs +++ b/src/devices/virtio_wl/shm.rs @@ -1,6 +1,6 @@ use std::os::unix::io::{AsRawFd,RawFd}; -use crate::memory::MemoryManager; +use crate::memory::{MemoryManager, DrmDescriptor}; use crate::system::MemoryFd; use crate::devices::virtio_wl::{ @@ -37,6 +37,15 @@ impl VfdSharedMemory { .map_err(Error::RegisterMemoryFailed)?; Ok(Self::new(vfd_id, transition_flags, mm.clone(), memfd, slot, pfn)) } + + pub fn create_dmabuf(vfd_id: u32, tflags: bool, width: u32, height: u32, format: u32, mm: &MemoryManager) -> Result<(Self, DrmDescriptor)> { + let (pfn, slot, fd, desc) = mm.allocate_drm_buffer(width, height, format) + .map_err(Error::DmaBuf)?; + let memfd = MemoryFd::from_filedesc(fd) + .map_err(Error::DmaBufSize)?; + let vfd = Self::new(vfd_id, tflags, mm.clone(), memfd, slot, pfn); + Ok((vfd, desc)) + } } impl VfdObject for VfdSharedMemory { diff --git a/src/devices/virtio_wl/vfd.rs b/src/devices/virtio_wl/vfd.rs index 0e7b1f3..c8d27b4 100644 --- a/src/devices/virtio_wl/vfd.rs +++ b/src/devices/virtio_wl/vfd.rs @@ -4,7 +4,7 @@ use std::os::unix::io::{AsRawFd,RawFd}; use std::path::PathBuf; use std::time::Duration; -use crate::memory::MemoryManager; +use crate::memory::{MemoryManager, DrmDescriptor}; use crate::system::{FileDesc, FileFlags,EPoll,MemoryFd}; use crate::virtio::{VirtQueue, Chain}; @@ -68,6 +68,13 @@ impl VfdManager { Ok((pfn,size)) } + pub fn create_dmabuf(&mut self, vfd_id: u32, width: u32, height: u32, format: u32) -> Result<(u64, u64, DrmDescriptor)> { + let (vfd, desc) = VfdSharedMemory::create_dmabuf(vfd_id, self.use_transition_flags, width, height, format, &self.mm)?; + let (pfn, size) = vfd.pfn_and_size().unwrap(); + self.vfd_map.insert(vfd_id, Box::new(vfd)); + Ok((pfn, size, desc)) + } + pub fn create_socket(&mut self, vfd_id: u32) -> Result { let sock = VfdSocket::open(vfd_id, self.use_transition_flags,&self.wayland_path)?; self.poll_ctx.add_read(sock.poll_fd().unwrap(), vfd_id as u64) diff --git a/src/main.rs b/src/main.rs index 301232b..0388e4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,9 +4,9 @@ #[macro_use] mod log; mod vm; -mod memory; #[macro_use] mod system; +mod memory; mod devices; mod kvm; mod virtio; diff --git a/src/memory/drm.rs b/src/memory/drm.rs new file mode 100644 index 0000000..af62825 --- /dev/null +++ b/src/memory/drm.rs @@ -0,0 +1,192 @@ +use std::fs::{OpenOptions, File}; +use std::os::raw::{c_ulong, c_int, c_uint}; +use std::os::unix::io::{RawFd,AsRawFd}; +use std::path::Path; +use std::sync::Arc; + +use crate::system::{self, ioctl::ioctl_with_mut_ref, FileDesc }; +use crate::memory::{Error,Result}; + +#[derive(Default,Debug)] +pub struct DrmPlaneDescriptor { + pub stride: u32, + pub offset: u32, +} + +#[derive(Default,Debug)] +pub struct DrmDescriptor { + pub planes: [DrmPlaneDescriptor; 3] +} + +#[derive(Clone)] +pub struct DrmBufferAllocator { + dev: Arc, +} + +impl DrmBufferAllocator { + + pub fn open() -> Result { + let dev = DrmDevice::open_render_node()?; + Ok(DrmBufferAllocator{ + dev: Arc::new(dev) + }) + } + + pub fn allocate(&self, width: u32, height: u32, format: u32) -> Result<(FileDesc, DrmDescriptor)> { + const GBM_BO_USE_LINEAR: u32 = 16; + + let buffer = self.create_buffer(width, height, format, GBM_BO_USE_LINEAR)?; + let fd = buffer.buffer_fd()?; + Ok((fd, buffer.drm_descriptor())) + } + + fn create_buffer(&self, width: u32, height: u32, format: u32, flags: u32) -> Result { + let bo = unsafe { + gbm_bo_create(self.dev.gbm, width, height, format, flags) + }; + if bo.is_null() { + let e = system::Error::last_os_error(); + Err(Error::GbmCreateBuffer(e)) + } else { + Ok(DrmBuffer::new(self.dev.clone(), bo)) + } + } +} + +struct DrmDevice { + file: File, + gbm: *mut GbmDevice, +} + +impl DrmDevice { + fn open_render_node() -> Result { + let path = Path::new("/dev/dri/renderD128"); + let file = OpenOptions::new() + .read(true) + .write(true) + .open(path) + .map_err(Error::OpenRenderNode)?; + Self::create(file) + } + + fn create(file: File) -> Result { + let gbm = unsafe { gbm_create_device(file.as_raw_fd()) }; + if gbm.is_null() { + let e = system::Error::last_os_error(); + Err(Error::GbmCreateDevice(e)) + } else { + Ok(DrmDevice{ file, gbm }) + } + } +} + +impl Drop for DrmDevice { + fn drop(&mut self) { + unsafe { gbm_device_destroy(self.gbm); } + } +} + +impl AsRawFd for DrmDevice { + fn as_raw_fd(&self) -> RawFd { + self.file.as_raw_fd() + } +} + +pub struct DrmBuffer { + dev: Arc, + bo: *mut GbmBo, +} +unsafe impl Send for DrmDevice {} +unsafe impl Sync for DrmDevice {} + +impl DrmBuffer { + fn new(dev: Arc, bo: *mut GbmBo) -> Self { + DrmBuffer { dev, bo } + } + + fn drm_descriptor(&self) -> DrmDescriptor { + let mut desc = DrmDescriptor::default(); + for i in 0..self.plane_count() { + if self.plane_handle(i) == self.plane_handle(0) { + desc.planes[i].stride = self.plane_stride(i); + desc.planes[i].offset = self.plane_offset(i); + } + } + desc + } + + fn plane_count(&self) -> usize { + unsafe { gbm_bo_get_plane_count(self.bo) } + } + + fn plane_handle(&self, plane: usize) -> u32 { + unsafe { gbm_bo_get_handle_for_plane(self.bo, plane).u32 } + } + + fn plane_offset(&self, plane: usize) -> u32 { + unsafe { gbm_bo_get_offset(self.bo, plane) } + } + + fn plane_stride(&self, plane: usize) -> u32 { + unsafe { gbm_bo_get_stride_for_plane(self.bo, plane) } + } + + fn buffer_fd(&self) -> Result { + const DRM_CLOEXEC: u32 = libc::O_CLOEXEC as u32; + const DRM_RDWR: u32 = libc::O_RDWR as u32; + let mut prime = DrmPrimeHandle { + handle: self.plane_handle(0), + flags: DRM_CLOEXEC | DRM_RDWR, + ..Default::default() + }; + + unsafe { + ioctl_with_mut_ref(self.dev.as_raw_fd(), DRM_IOCTL_PRIME_HANDLE_TO_FD, &mut prime) + .map_err(Error::PrimeHandleToFD)?; + } + Ok(FileDesc::new(prime.fd)) + } +} + +impl Drop for DrmBuffer { + fn drop(&mut self) { + unsafe { gbm_bo_destroy(self.bo); } + } +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +struct DrmPrimeHandle { + pub handle: c_uint, + pub flags: c_uint, + pub fd: c_int, +} + +const DRM_IOCTL_BASE: c_uint = 0x64; +const DRM_IOCTL_PRIME_HANDLE_TO_FD: c_ulong = iorw!(DRM_IOCTL_BASE, 0x2d, ::std::mem::size_of::() as i32); + +#[repr(C)] +struct GbmDevice([u8; 0]); + +#[repr(C)] +struct GbmBo([u8; 0]); + +#[repr(C)] +pub union GbmBoHandle { + pub u32: u32, + _align: u64, +} + +#[link(name = "gbm")] +extern "C" { + fn gbm_bo_create(gbm: *mut GbmDevice, width: u32, height: u32, format: u32, flags: u32) -> *mut GbmBo; + fn gbm_create_device(fd: libc::c_int) -> *mut GbmDevice; + fn gbm_device_destroy(gbm: *mut GbmDevice); + fn gbm_bo_destroy(bo: *mut GbmBo); + fn gbm_bo_get_plane_count(bo: *mut GbmBo) -> usize; + fn gbm_bo_get_handle_for_plane(bo: *mut GbmBo, plane: usize) -> GbmBoHandle; + fn gbm_bo_get_offset(bo: *mut GbmBo, plane: usize) -> u32; + fn gbm_bo_get_stride_for_plane(bo: *mut GbmBo, plane: usize) -> u32; +} + + diff --git a/src/memory/manager.rs b/src/memory/manager.rs index 40cca56..42d6791 100644 --- a/src/memory/manager.rs +++ b/src/memory/manager.rs @@ -1,25 +1,34 @@ use std::collections::HashMap; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsRawFd,RawFd}; use std::sync::{Arc, RwLock}; use crate::memory::{GuestRam, SystemAllocator, Mapping, Error, Result}; use crate::kvm::Kvm; -use crate::system::BitVec; +use crate::system::{BitVec, FileDesc}; +use crate::memory::drm::{DrmBufferAllocator, DrmDescriptor}; +use std::io::SeekFrom; #[derive(Clone)] pub struct MemoryManager { kvm: Kvm, ram: GuestRam, device_memory: Arc>, + drm_allocator: Option, } impl MemoryManager { - pub fn new(kvm: Kvm, ram: GuestRam, allocator: SystemAllocator) -> Self { + pub fn new(kvm: Kvm, ram: GuestRam, allocator: SystemAllocator, use_drm: bool) -> Result { let device_memory = RwLock::new(DeviceMemory::new(ram.region_count(), allocator)).into(); - MemoryManager { + let drm_allocator = if use_drm { + DrmBufferAllocator::open().ok() + } else { + None + }; + Ok(MemoryManager { kvm, ram, device_memory, - } + drm_allocator, + }) } pub fn guest_ram(&self) -> &GuestRam { @@ -43,6 +52,22 @@ impl MemoryManager { let mut devmem = self.device_memory.write().unwrap(); devmem.unregister(self.kvm(), slot) } + + pub fn drm_available(&self) -> bool { + self.drm_allocator.is_some() + } + + pub fn allocate_drm_buffer(&self, width: u32, height: u32, format: u32) -> Result<(u64, u32, FileDesc, DrmDescriptor)> { + if let Some(drm_allocator) = self.drm_allocator.as_ref() { + let (fd, desc) = drm_allocator.allocate(width, height, format)?; + let size = fd.seek(SeekFrom::End(0)).map_err(Error::CreateBuffer)?; + + let (pfn, slot) = self.register_device_memory(fd.as_raw_fd(), size as usize)?; + Ok((pfn, slot, fd, desc)) + } else { + Err(Error::NoDrmAllocator) + } + } } pub struct MemoryRegistration { diff --git a/src/memory/mod.rs b/src/memory/mod.rs index a17d42d..f949c8a 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,4 +1,5 @@ mod ram; +mod drm; mod manager; mod mmap; mod address; @@ -10,8 +11,12 @@ pub use self::mmap::Mapping; pub use self::ram::GuestRam; pub use self::ram::{PCI_MMIO_RESERVED_BASE,HIMEM_BASE}; pub use manager::MemoryManager; + +pub use drm::{DrmDescriptor,DrmPlaneDescriptor}; + use crate::vm::Error as VmError; -use std::{result, fmt}; +use std::{result, fmt, io}; +use crate::system; pub const KVM_KERNEL_LOAD_ADDRESS: u64 = 0x1000000; pub const KERNEL_CMDLINE_ADDRESS: u64 = 0x20000; @@ -23,6 +28,12 @@ pub enum Error { MappingFailed(VmError), RegisterMemoryFailed(VmError), UnregisterMemoryFailed(VmError), + GbmCreateDevice(system::Error), + GbmCreateBuffer(system::Error), + OpenRenderNode(io::Error), + PrimeHandleToFD(VmError), + CreateBuffer(io::Error), + NoDrmAllocator, } impl fmt::Display for Error { @@ -33,6 +44,12 @@ impl fmt::Display for Error { MappingFailed(e) => write!(f, "failed to create memory mapping for device memory: {}", e), RegisterMemoryFailed(e) => write!(f, "failed to register memory for device memory: {}", e), UnregisterMemoryFailed(e) => write!(f, "failed to unregister memory for device memory: {}", e), + GbmCreateDevice(e) => write!(f, "failed to open device with libgbm: {}", e), + GbmCreateBuffer(e) => write!(f, "failed to allocate buffer with libgbm: {}", e), + PrimeHandleToFD(err) => write!(f, "exporting prime handle to fd failed: {}", err), + OpenRenderNode(err) => write!(f, "error opening render node: {}", err), + CreateBuffer(err) => write!(f, "failed to create buffer: {}", err), + NoDrmAllocator => write!(f, "no DRM allocator is available"), } } } diff --git a/src/vm/config.rs b/src/vm/config.rs index 6f99e07..81ffa4a 100644 --- a/src/vm/config.rs +++ b/src/vm/config.rs @@ -11,6 +11,8 @@ pub struct VmConfig { ncpus: usize, verbose: bool, rootshell: bool, + wayland: bool, + dmabuf: bool, home: String, launch_systemd: bool, kernel_path: Option, @@ -31,8 +33,9 @@ impl VmConfig { ncpus: 1, verbose: false, rootshell: false, - home: String::from("/home/user"), - launch_systemd: false, + wayland: true, + dmabuf: false, + home: Self::default_homedir(), kernel_path: None, init_path: None, init_cmd: None, @@ -45,6 +48,15 @@ impl VmConfig { config } + fn default_homedir() -> String { + if let Ok(home) = env::var("HOME") { + if Path::new(&home).exists() { + return home; + } + } + String::from("/home/user") + } + pub fn ram_size_megs(mut self, megs: usize) -> Self { self.ram_size = megs * 1024 * 1024; self @@ -155,6 +167,21 @@ impl VmConfig { self.realm_name.as_ref().map(|s| s.as_str()) } + pub fn is_wayland_enabled(&self) -> bool { + if !self.wayland { + return false; + } + let display = env::var("WAYLAND_DISPLAY").unwrap_or("wayland-0".to_string()); + let xdg_runtime = env::var("XDG_RUNTIME_DIR").unwrap_or("/run/user/1000".to_string()); + + let socket= Path::new(xdg_runtime.as_str()).join(display); + socket.exists() + } + + pub fn is_dmabuf_enabled(&self) -> bool { + self.dmabuf + } + fn add_realmfs_by_name(&mut self, realmfs: &str) { let path = Path::new("/realms/realmfs-images") .join(format!("{}-realmfs.img", realmfs)); @@ -184,6 +211,13 @@ impl VmConfig { if args.has_arg("--root") { self.rootshell = true; } + if args.has_arg("--no-wayland") { + self.wayland = false; + self.dmabuf = false; + } + if args.has_arg("--use-dmabuf") { + self.dmabuf = true; + } if let Some(home) = args.arg_with_value("--home") { self.home = home.to_string(); } diff --git a/src/vm/error.rs b/src/vm/error.rs index f301097..b71bf17 100644 --- a/src/vm/error.rs +++ b/src/vm/error.rs @@ -25,6 +25,7 @@ pub enum ErrorKind { DiskImageOpen(disk::Error), TerminalTermios(io::Error), IoError(io::Error), + MemoryManagerCreate, } impl ErrorKind { @@ -45,6 +46,7 @@ impl ErrorKind { ErrorKind::DiskImageOpen(_) => "failed to open disk image", ErrorKind::TerminalTermios(_) => "failed termios", ErrorKind::IoError(_) => "i/o error", + ErrorKind::MemoryManagerCreate => "memory manager", } } } @@ -58,6 +60,7 @@ impl fmt::Display for ErrorKind { ErrorKind::DiskImageOpen(ref e) => write!(f, "failed to open disk image: {}", e), ErrorKind::TerminalTermios(ref e) => write!(f, "error reading/restoring terminal state: {}", e), ErrorKind::IoError(ref e) => write!(f, "i/o error: {}", e), + ErrorKind::MemoryManagerCreate => write!(f, "error creating memory manager"), _ => write!(f, "{}", self.as_str()), } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 709c43c..fed123e 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -67,20 +67,22 @@ impl Vm { kvm.create_irqchip()?; Ok(kvm) } - fn create_memory_manager(ram_size: usize) -> Result { + fn create_memory_manager(ram_size: usize, use_drm: bool) -> Result { let kvm = Self::create_kvm()?; let ram = GuestRam::new(ram_size, &kvm)?; let dev_addr_start = get_base_dev_pfn(ram_size as u64) * 4096; let dev_addr_size = u64::max_value() - dev_addr_start; let allocator = SystemAllocator::new(AddressRange::new(dev_addr_start,dev_addr_size as usize)); - Ok(MemoryManager::new(kvm, ram, allocator)) + Ok(MemoryManager::new(kvm, ram, allocator, use_drm).map_err(|_| ErrorKind::MemoryManagerCreate)?) } fn setup_virtio(config: &mut VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus) -> Result<()> { devices::VirtioSerial::create(virtio)?; devices::VirtioRandom::create(virtio)?; - devices::VirtioWayland::create(virtio)?; - devices::VirtioP9::create(virtio, "home", config.homedir(), false, false)?; + + if config.is_wayland_enabled() { + devices::VirtioWayland::create(virtio)?; + } let mut block_root = false; @@ -131,7 +133,8 @@ impl Vm { pub fn open(mut config: VmConfig) -> Result { - let mut memory = Self::create_memory_manager(config.ram_size())?; + let with_drm = config.is_wayland_enabled() && config.is_dmabuf_enabled(); + let mut memory = Self::create_memory_manager(config.ram_size(), with_drm)?; let mut cmdline = KernelCmdLine::new_default(); @@ -152,6 +155,11 @@ impl Vm { if config.rootshell() { cmdline.push("phinit.rootshell"); } + + if memory.drm_available() && config.is_dmabuf_enabled() { + cmdline.push("phinit.virtwl_dmabuf"); + } + if let Some(realm) = config.realm_name() { cmdline.push_set_val("phinit.realm", realm); }