support dmabuf in virtio_wl
This commit is contained in:
parent
3e5b802487
commit
0a06043e32
@ -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")
|
||||
|
@ -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::<dma_buf_sync>() 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)?;
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<u32> {
|
||||
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)
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
#[macro_use] mod log;
|
||||
mod vm;
|
||||
mod memory;
|
||||
#[macro_use]
|
||||
mod system;
|
||||
mod memory;
|
||||
mod devices;
|
||||
mod kvm;
|
||||
mod virtio;
|
||||
|
192
src/memory/drm.rs
Normal file
192
src/memory/drm.rs
Normal file
@ -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<DrmDevice>,
|
||||
}
|
||||
|
||||
impl DrmBufferAllocator {
|
||||
|
||||
pub fn open() -> Result<Self> {
|
||||
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<DrmBuffer> {
|
||||
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<Self> {
|
||||
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<Self> {
|
||||
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<DrmDevice>,
|
||||
bo: *mut GbmBo,
|
||||
}
|
||||
unsafe impl Send for DrmDevice {}
|
||||
unsafe impl Sync for DrmDevice {}
|
||||
|
||||
impl DrmBuffer {
|
||||
fn new(dev: Arc<DrmDevice>, 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<FileDesc> {
|
||||
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::<DrmPrimeHandle>() 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;
|
||||
}
|
||||
|
||||
|
@ -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<RwLock<DeviceMemory>>,
|
||||
drm_allocator: Option<DrmBufferAllocator>,
|
||||
}
|
||||
|
||||
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<Self> {
|
||||
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 {
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<PathBuf>,
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
@ -67,20 +67,22 @@ impl Vm {
|
||||
kvm.create_irqchip()?;
|
||||
Ok(kvm)
|
||||
}
|
||||
fn create_memory_manager(ram_size: usize) -> Result<MemoryManager> {
|
||||
fn create_memory_manager(ram_size: usize, use_drm: bool) -> Result<MemoryManager> {
|
||||
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<Vm> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user