vhost_user: Add gpu_message protocol bits
This commit adds the basic definitions of GPU commands on the socket obtained from VHOST_USER_GPU_SET_SOCKET. This also introduces a new feature flag `gpu-socket` in the vhost crate. Signed-off-by: Matej Hrica <mhrica@redhat.com>
This commit is contained in:
parent
c66e3a9e0f
commit
ca57fb165d
3 changed files with 174 additions and 0 deletions
|
|
@ -23,6 +23,7 @@ vhost-net = ["vhost-kern"]
|
|||
vhost-user = []
|
||||
vhost-user-frontend = ["vhost-user"]
|
||||
vhost-user-backend = ["vhost-user"]
|
||||
gpu-socket = ["vhost-user"]
|
||||
xen = ["vm-memory/xen"]
|
||||
postcopy = []
|
||||
|
||||
|
|
|
|||
171
vhost/src/vhost_user/gpu_message.rs
Normal file
171
vhost/src/vhost_user/gpu_message.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (C) 2024 Red Hat, Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Implementation parts of the protocol on the socket from VHOST_USER_SET_GPU_SOCKET
|
||||
//! see: https://www.qemu.org/docs/master/interop/vhost-user-gpu.html
|
||||
|
||||
use super::enum_value;
|
||||
use crate::vhost_user::message::{MsgHeader, Req, VhostUserMsgValidator};
|
||||
use crate::vhost_user::Error;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
use vm_memory::ByteValued;
|
||||
|
||||
enum_value! {
|
||||
/// Type of requests sending from gpu backends to gpu frontends.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||
pub enum GpuBackendReq: u32 {
|
||||
/// Get the supported protocol features bitmask.
|
||||
GET_PROTOCOL_FEATURES = 1,
|
||||
/// Enable protocol features using a bitmask.
|
||||
SET_PROTOCOL_FEATURES = 2,
|
||||
/// Get the preferred display configuration.
|
||||
GET_DISPLAY_INFO = 3,
|
||||
/// Set/show the cursor position.
|
||||
CURSOR_POS = 4,
|
||||
/// Set/hide the cursor.
|
||||
CURSOR_POS_HIDE = 5,
|
||||
/// Update the cursor shape and location.
|
||||
CURSOR_UPDATE = 6,
|
||||
/// Set the scanout resolution.
|
||||
/// To disable a scanout, the dimensions width/height are set to 0.
|
||||
SCANOUT = 7,
|
||||
/// Update the scanout content. The data payload contains the graphical bits.
|
||||
/// The display should be flushed and presented.
|
||||
UPDATE = 8,
|
||||
/// Set the scanout resolution/configuration, and share a DMABUF file descriptor for the
|
||||
/// scanout content, which is passed as ancillary data.
|
||||
/// To disable a scanout, the dimensions width/height are set to 0, there is no file
|
||||
/// descriptor passed.
|
||||
DMABUF_SCANOUT = 9,
|
||||
/// The display should be flushed and presented according to updated region from
|
||||
/// VhostUserGpuUpdate.
|
||||
/// Note: there is no data payload, since the scanout is shared thanks to DMABUF,
|
||||
/// that must have been set previously with VHOST_USER_GPU_DMABUF_SCANOUT.
|
||||
DMABUF_UPDATE = 10,
|
||||
/// Retrieve the EDID data for a given scanout.
|
||||
/// This message requires the VHOST_USER_GPU_PROTOCOL_F_EDID protocol feature to be
|
||||
/// supported.
|
||||
GET_EDID = 11,
|
||||
/// Same as DMABUF_SCANOUT, but also sends the dmabuf modifiers appended to the message,
|
||||
/// which were not provided in the other message.
|
||||
/// This message requires the VHOST_USER_GPU_PROTOCOL_F_DMABUF2 protocol feature to be
|
||||
/// supported.
|
||||
DMABUF_SCANOUT2 = 12,
|
||||
}
|
||||
}
|
||||
|
||||
impl Req for GpuBackendReq {}
|
||||
|
||||
// Bit mask for common message flags.
|
||||
bitflags! {
|
||||
/// Common message flags for vhost-user requests and replies.
|
||||
pub struct VhostUserGpuHeaderFlag: u32 {
|
||||
/// Mark message as reply.
|
||||
const REPLY = 0x4;
|
||||
}
|
||||
}
|
||||
|
||||
/// A vhost-user message consists of 3 header fields and an optional payload. All numbers are in the
|
||||
/// machine native byte order.
|
||||
#[repr(C, packed)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct VhostUserGpuMsgHeader<R: Req> {
|
||||
request: u32,
|
||||
flags: u32,
|
||||
size: u32,
|
||||
_r: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<R: Req> Debug for VhostUserGpuMsgHeader<R> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VhostUserMsgHeader")
|
||||
.field("request", &{ self.request })
|
||||
.field("flags", &{ self.flags })
|
||||
.field("size", &{ self.size })
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Req> PartialEq for VhostUserGpuMsgHeader<R> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.request == other.request && self.flags == other.flags && self.size == other.size
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<R: Req> VhostUserGpuMsgHeader<R> {
|
||||
/// Create a new instance of `VhostUserMsgHeader`.
|
||||
pub fn new(request: R, flags: u32, size: u32) -> Self {
|
||||
VhostUserGpuMsgHeader {
|
||||
request: request.into(),
|
||||
flags,
|
||||
size,
|
||||
_r: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get message type.
|
||||
pub fn get_code(&self) -> crate::vhost_user::Result<R> {
|
||||
R::try_from(self.request).map_err(|_| Error::InvalidMessage)
|
||||
}
|
||||
|
||||
/// Check whether it's a reply message.
|
||||
pub fn is_reply(&self) -> bool {
|
||||
(self.flags & VhostUserGpuHeaderFlag::REPLY.bits()) != 0
|
||||
}
|
||||
|
||||
/// Mark message as reply.
|
||||
pub fn set_reply(&mut self, is_reply: bool) {
|
||||
if is_reply {
|
||||
self.flags |= VhostUserGpuHeaderFlag::REPLY.bits();
|
||||
} else {
|
||||
self.flags &= !VhostUserGpuHeaderFlag::REPLY.bits();
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether it's the reply message for the request `req`.
|
||||
pub fn is_reply_for(&self, req: &VhostUserGpuMsgHeader<R>) -> bool {
|
||||
if let (Ok(code1), Ok(code2)) = (self.get_code(), req.get_code()) {
|
||||
self.is_reply() && !req.is_reply() && code1 == code2
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Get message size.
|
||||
pub fn get_size(&self) -> u32 {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Set message size.
|
||||
pub fn set_size(&mut self, size: u32) {
|
||||
self.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Req> Default for VhostUserGpuMsgHeader<R> {
|
||||
fn default() -> Self {
|
||||
VhostUserGpuMsgHeader {
|
||||
request: 0,
|
||||
flags: 0,
|
||||
size: 0,
|
||||
_r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: Safe because all fields of VhostUserGpuMsgHeader are POD.
|
||||
unsafe impl<R: Req> ByteValued for VhostUserGpuMsgHeader<R> {}
|
||||
|
||||
impl<T: Req> VhostUserMsgValidator for VhostUserGpuMsgHeader<T> {
|
||||
fn is_valid(&self) -> bool {
|
||||
self.get_code().is_ok() && VhostUserGpuHeaderFlag::from_bits(self.flags).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Req> MsgHeader for VhostUserGpuMsgHeader<R> {
|
||||
type Request = R;
|
||||
}
|
||||
|
|
@ -52,6 +52,8 @@ pub use self::backend_req_handler::{
|
|||
mod backend_req;
|
||||
#[cfg(feature = "vhost-user-backend")]
|
||||
pub use self::backend_req::Backend;
|
||||
#[cfg(feature = "gpu-socket")]
|
||||
pub mod gpu_message;
|
||||
|
||||
/// Errors for vhost-user operations
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue