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<()> {
|
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")
|
let dbus = ServiceLaunch::new("dbus-daemon", "/usr/bin/dbus-daemon")
|
||||||
.base_environment()
|
.base_environment()
|
||||||
.uidgid(1000,1000)
|
.uidgid(1000,1000)
|
||||||
@ -178,20 +184,34 @@ impl InitServer {
|
|||||||
|
|
||||||
self.services.insert(dbus.pid(), dbus);
|
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")
|
let sommelier = ServiceLaunch::new("sommelier", "/opt/ph/usr/bin/sommelier")
|
||||||
.base_environment()
|
.base_environment()
|
||||||
.uidgid(1000,1000)
|
.uidgid(1000,1000)
|
||||||
|
.env("SOMMELIER_SHM_DRIVER", shm_driver)
|
||||||
.arg("--master")
|
.arg("--master")
|
||||||
.pipe_output()
|
.pipe_output()
|
||||||
.launch()?;
|
.launch()?;
|
||||||
|
|
||||||
self.services.insert(sommelier.pid(), sommelier);
|
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")
|
let sommelierx = ServiceLaunch::new("sommelier-x", "/opt/ph/usr/bin/sommelier")
|
||||||
.base_environment()
|
.base_environment()
|
||||||
.uidgid(1000,1000)
|
.uidgid(1000,1000)
|
||||||
|
.env("SOMMELIER_SHM_DRIVER", shm_driver)
|
||||||
.arg("-X")
|
.arg("-X")
|
||||||
.arg("--x-display=0")
|
.arg("--x-display=0")
|
||||||
.arg("--no-exit-with-child")
|
.arg("--no-exit-with-child")
|
||||||
|
@ -4,10 +4,19 @@ use std::thread;
|
|||||||
|
|
||||||
use crate::{vm, system};
|
use crate::{vm, system};
|
||||||
use crate::system::EPoll;
|
use crate::system::EPoll;
|
||||||
use crate::memory::MemoryManager;
|
use crate::memory::{MemoryManager, DrmDescriptor};
|
||||||
use crate::virtio::{VirtQueue, EventFd, Chain, VirtioBus, VirtioDeviceOps};
|
use crate::virtio::{VirtQueue, EventFd, Chain, VirtioBus, VirtioDeviceOps};
|
||||||
|
|
||||||
use crate::devices::virtio_wl::{vfd::VfdManager, consts::*, Error, Result, VfdObject};
|
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 {
|
pub struct VirtioWayland {
|
||||||
feature_bits: u64,
|
feature_bits: u64,
|
||||||
@ -165,6 +174,8 @@ impl <'a> MessageHandler<'a> {
|
|||||||
VIRTIO_WL_CMD_VFD_NEW => self.cmd_new_alloc(),
|
VIRTIO_WL_CMD_VFD_NEW => self.cmd_new_alloc(),
|
||||||
VIRTIO_WL_CMD_VFD_CLOSE => self.cmd_close(),
|
VIRTIO_WL_CMD_VFD_CLOSE => self.cmd_close(),
|
||||||
VIRTIO_WL_CMD_VFD_SEND => self.cmd_send(),
|
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_CTX => self.cmd_new_ctx(),
|
||||||
VIRTIO_WL_CMD_VFD_NEW_PIPE => self.cmd_new_pipe(),
|
VIRTIO_WL_CMD_VFD_NEW_PIPE => self.cmd_new_pipe(),
|
||||||
v => {
|
v => {
|
||||||
@ -198,6 +209,70 @@ impl <'a> MessageHandler<'a> {
|
|||||||
Ok(())
|
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<()> {
|
fn cmd_close(&mut self) -> Result<()> {
|
||||||
let id = self.chain.r32()?;
|
let id = self.chain.r32()?;
|
||||||
self.device.vfd_manager.close_vfd(id)?;
|
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_CTX: u32 = 260;
|
||||||
pub const VIRTIO_WL_CMD_VFD_NEW_PIPE: u32 = 261;
|
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_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_OK: u32 = 4096;
|
||||||
pub const VIRTIO_WL_RESP_VFD_NEW: u32 = 4097;
|
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_ERR: u32 = 4352;
|
||||||
pub const VIRTIO_WL_RESP_OUT_OF_MEMORY: u32 = 4353;
|
pub const VIRTIO_WL_RESP_OUT_OF_MEMORY: u32 = 4353;
|
||||||
pub const VIRTIO_WL_RESP_INVALID_ID: u32 = 4354;
|
pub const VIRTIO_WL_RESP_INVALID_ID: u32 = 4354;
|
||||||
@ -93,6 +96,9 @@ pub enum Error {
|
|||||||
TooManySendVfds(usize),
|
TooManySendVfds(usize),
|
||||||
FailedPollContextCreate(system::Error),
|
FailedPollContextCreate(system::Error),
|
||||||
FailedPollAdd(system::Error),
|
FailedPollAdd(system::Error),
|
||||||
|
DmaSync(vm::Error),
|
||||||
|
DmaBuf(MemError),
|
||||||
|
DmaBufSize(system::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for 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),
|
TooManySendVfds(n) => write!(f, "message has too many vfd ids: {}", n),
|
||||||
FailedPollContextCreate(e) => write!(f, "failed creating poll context: {}", e),
|
FailedPollContextCreate(e) => write!(f, "failed creating poll context: {}", e),
|
||||||
FailedPollAdd(e) => write!(f, "failed adding fd to 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 std::os::unix::io::{AsRawFd,RawFd};
|
||||||
|
|
||||||
use crate::memory::MemoryManager;
|
use crate::memory::{MemoryManager, DrmDescriptor};
|
||||||
use crate::system::MemoryFd;
|
use crate::system::MemoryFd;
|
||||||
|
|
||||||
use crate::devices::virtio_wl::{
|
use crate::devices::virtio_wl::{
|
||||||
@ -37,6 +37,15 @@ impl VfdSharedMemory {
|
|||||||
.map_err(Error::RegisterMemoryFailed)?;
|
.map_err(Error::RegisterMemoryFailed)?;
|
||||||
Ok(Self::new(vfd_id, transition_flags, mm.clone(), memfd, slot, pfn))
|
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 {
|
impl VfdObject for VfdSharedMemory {
|
||||||
|
@ -4,7 +4,7 @@ use std::os::unix::io::{AsRawFd,RawFd};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::memory::MemoryManager;
|
use crate::memory::{MemoryManager, DrmDescriptor};
|
||||||
use crate::system::{FileDesc, FileFlags,EPoll,MemoryFd};
|
use crate::system::{FileDesc, FileFlags,EPoll,MemoryFd};
|
||||||
use crate::virtio::{VirtQueue, Chain};
|
use crate::virtio::{VirtQueue, Chain};
|
||||||
|
|
||||||
@ -68,6 +68,13 @@ impl VfdManager {
|
|||||||
Ok((pfn,size))
|
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> {
|
pub fn create_socket(&mut self, vfd_id: u32) -> Result<u32> {
|
||||||
let sock = VfdSocket::open(vfd_id, self.use_transition_flags,&self.wayland_path)?;
|
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)
|
self.poll_ctx.add_read(sock.poll_fd().unwrap(), vfd_id as u64)
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
#[macro_use] mod log;
|
#[macro_use] mod log;
|
||||||
mod vm;
|
mod vm;
|
||||||
mod memory;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod system;
|
mod system;
|
||||||
|
mod memory;
|
||||||
mod devices;
|
mod devices;
|
||||||
mod kvm;
|
mod kvm;
|
||||||
mod virtio;
|
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::collections::HashMap;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::{AsRawFd,RawFd};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use crate::memory::{GuestRam, SystemAllocator, Mapping, Error, Result};
|
use crate::memory::{GuestRam, SystemAllocator, Mapping, Error, Result};
|
||||||
use crate::kvm::Kvm;
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct MemoryManager {
|
pub struct MemoryManager {
|
||||||
kvm: Kvm,
|
kvm: Kvm,
|
||||||
ram: GuestRam,
|
ram: GuestRam,
|
||||||
device_memory: Arc<RwLock<DeviceMemory>>,
|
device_memory: Arc<RwLock<DeviceMemory>>,
|
||||||
|
drm_allocator: Option<DrmBufferAllocator>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryManager {
|
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();
|
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,
|
kvm, ram, device_memory,
|
||||||
}
|
drm_allocator,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn guest_ram(&self) -> &GuestRam {
|
pub fn guest_ram(&self) -> &GuestRam {
|
||||||
@ -43,6 +52,22 @@ impl MemoryManager {
|
|||||||
let mut devmem = self.device_memory.write().unwrap();
|
let mut devmem = self.device_memory.write().unwrap();
|
||||||
devmem.unregister(self.kvm(), slot)
|
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 {
|
pub struct MemoryRegistration {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
mod ram;
|
mod ram;
|
||||||
|
mod drm;
|
||||||
mod manager;
|
mod manager;
|
||||||
mod mmap;
|
mod mmap;
|
||||||
mod address;
|
mod address;
|
||||||
@ -10,8 +11,12 @@ pub use self::mmap::Mapping;
|
|||||||
pub use self::ram::GuestRam;
|
pub use self::ram::GuestRam;
|
||||||
pub use self::ram::{PCI_MMIO_RESERVED_BASE,HIMEM_BASE};
|
pub use self::ram::{PCI_MMIO_RESERVED_BASE,HIMEM_BASE};
|
||||||
pub use manager::MemoryManager;
|
pub use manager::MemoryManager;
|
||||||
|
|
||||||
|
pub use drm::{DrmDescriptor,DrmPlaneDescriptor};
|
||||||
|
|
||||||
use crate::vm::Error as VmError;
|
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 KVM_KERNEL_LOAD_ADDRESS: u64 = 0x1000000;
|
||||||
pub const KERNEL_CMDLINE_ADDRESS: u64 = 0x20000;
|
pub const KERNEL_CMDLINE_ADDRESS: u64 = 0x20000;
|
||||||
@ -23,6 +28,12 @@ pub enum Error {
|
|||||||
MappingFailed(VmError),
|
MappingFailed(VmError),
|
||||||
RegisterMemoryFailed(VmError),
|
RegisterMemoryFailed(VmError),
|
||||||
UnregisterMemoryFailed(VmError),
|
UnregisterMemoryFailed(VmError),
|
||||||
|
GbmCreateDevice(system::Error),
|
||||||
|
GbmCreateBuffer(system::Error),
|
||||||
|
OpenRenderNode(io::Error),
|
||||||
|
PrimeHandleToFD(VmError),
|
||||||
|
CreateBuffer(io::Error),
|
||||||
|
NoDrmAllocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
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),
|
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),
|
RegisterMemoryFailed(e) => write!(f, "failed to register memory for device memory: {}", e),
|
||||||
UnregisterMemoryFailed(e) => write!(f, "failed to unregister 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,
|
ncpus: usize,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
rootshell: bool,
|
rootshell: bool,
|
||||||
|
wayland: bool,
|
||||||
|
dmabuf: bool,
|
||||||
home: String,
|
home: String,
|
||||||
launch_systemd: bool,
|
launch_systemd: bool,
|
||||||
kernel_path: Option<PathBuf>,
|
kernel_path: Option<PathBuf>,
|
||||||
@ -31,8 +33,9 @@ impl VmConfig {
|
|||||||
ncpus: 1,
|
ncpus: 1,
|
||||||
verbose: false,
|
verbose: false,
|
||||||
rootshell: false,
|
rootshell: false,
|
||||||
home: String::from("/home/user"),
|
wayland: true,
|
||||||
launch_systemd: false,
|
dmabuf: false,
|
||||||
|
home: Self::default_homedir(),
|
||||||
kernel_path: None,
|
kernel_path: None,
|
||||||
init_path: None,
|
init_path: None,
|
||||||
init_cmd: None,
|
init_cmd: None,
|
||||||
@ -45,6 +48,15 @@ impl VmConfig {
|
|||||||
config
|
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 {
|
pub fn ram_size_megs(mut self, megs: usize) -> Self {
|
||||||
self.ram_size = megs * 1024 * 1024;
|
self.ram_size = megs * 1024 * 1024;
|
||||||
self
|
self
|
||||||
@ -155,6 +167,21 @@ impl VmConfig {
|
|||||||
self.realm_name.as_ref().map(|s| s.as_str())
|
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) {
|
fn add_realmfs_by_name(&mut self, realmfs: &str) {
|
||||||
let path = Path::new("/realms/realmfs-images")
|
let path = Path::new("/realms/realmfs-images")
|
||||||
.join(format!("{}-realmfs.img", realmfs));
|
.join(format!("{}-realmfs.img", realmfs));
|
||||||
@ -184,6 +211,13 @@ impl VmConfig {
|
|||||||
if args.has_arg("--root") {
|
if args.has_arg("--root") {
|
||||||
self.rootshell = true;
|
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") {
|
if let Some(home) = args.arg_with_value("--home") {
|
||||||
self.home = home.to_string();
|
self.home = home.to_string();
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ pub enum ErrorKind {
|
|||||||
DiskImageOpen(disk::Error),
|
DiskImageOpen(disk::Error),
|
||||||
TerminalTermios(io::Error),
|
TerminalTermios(io::Error),
|
||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
|
MemoryManagerCreate,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorKind {
|
impl ErrorKind {
|
||||||
@ -45,6 +46,7 @@ impl ErrorKind {
|
|||||||
ErrorKind::DiskImageOpen(_) => "failed to open disk image",
|
ErrorKind::DiskImageOpen(_) => "failed to open disk image",
|
||||||
ErrorKind::TerminalTermios(_) => "failed termios",
|
ErrorKind::TerminalTermios(_) => "failed termios",
|
||||||
ErrorKind::IoError(_) => "i/o error",
|
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::DiskImageOpen(ref e) => write!(f, "failed to open disk image: {}", e),
|
||||||
ErrorKind::TerminalTermios(ref e) => write!(f, "error reading/restoring terminal state: {}", e),
|
ErrorKind::TerminalTermios(ref e) => write!(f, "error reading/restoring terminal state: {}", e),
|
||||||
ErrorKind::IoError(ref e) => write!(f, "i/o error: {}", e),
|
ErrorKind::IoError(ref e) => write!(f, "i/o error: {}", e),
|
||||||
|
ErrorKind::MemoryManagerCreate => write!(f, "error creating memory manager"),
|
||||||
_ => write!(f, "{}", self.as_str()),
|
_ => write!(f, "{}", self.as_str()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,20 +67,22 @@ impl Vm {
|
|||||||
kvm.create_irqchip()?;
|
kvm.create_irqchip()?;
|
||||||
Ok(kvm)
|
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 kvm = Self::create_kvm()?;
|
||||||
let ram = GuestRam::new(ram_size, &kvm)?;
|
let ram = GuestRam::new(ram_size, &kvm)?;
|
||||||
let dev_addr_start = get_base_dev_pfn(ram_size as u64) * 4096;
|
let dev_addr_start = get_base_dev_pfn(ram_size as u64) * 4096;
|
||||||
let dev_addr_size = u64::max_value() - dev_addr_start;
|
let dev_addr_size = u64::max_value() - dev_addr_start;
|
||||||
let allocator = SystemAllocator::new(AddressRange::new(dev_addr_start,dev_addr_size as usize));
|
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<()> {
|
fn setup_virtio(config: &mut VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus) -> Result<()> {
|
||||||
devices::VirtioSerial::create(virtio)?;
|
devices::VirtioSerial::create(virtio)?;
|
||||||
devices::VirtioRandom::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;
|
let mut block_root = false;
|
||||||
|
|
||||||
@ -131,7 +133,8 @@ impl Vm {
|
|||||||
|
|
||||||
pub fn open(mut config: VmConfig) -> Result<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();
|
let mut cmdline = KernelCmdLine::new_default();
|
||||||
|
|
||||||
@ -152,6 +155,11 @@ impl Vm {
|
|||||||
if config.rootshell() {
|
if config.rootshell() {
|
||||||
cmdline.push("phinit.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() {
|
if let Some(realm) = config.realm_name() {
|
||||||
cmdline.push_set_val("phinit.realm", realm);
|
cmdline.push_set_val("phinit.realm", realm);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user