virtio/devices/virtio_gpu/messages/
ctrl_header.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5use super::super::helpers::{bytes_from_iter, copy_to_iter};
6use kernel::ErrorCode;
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9#[repr(u32)]
10#[allow(dead_code)]
11pub enum CtrlType {
12    /* 2d commands */
13    CmdGetDisplayInfo = 0x0100,
14    CmdResourceCreate2d,
15    CmdResourceUref,
16    CmdSetScanout,
17    CmdResourceFlush,
18    CmdTransferToHost2d,
19    CmdResourceAttachBacking,
20    CmdResourceDetachBacking,
21    CmdGetCapsetInfo,
22    CmdGetCapset,
23    CmdGetEdid,
24
25    /* cursor commands */
26    CmdUpdateCursor = 0x0300,
27    CmdMoveCursor,
28
29    /* success responses */
30    RespOkNoData = 0x1100,
31    RespOkDisplayInfo,
32    RespOkCapsetInfo,
33    RespOkCapset,
34    RespOkEdid,
35
36    /* error responses */
37    RespErrUnspec = 0x1200,
38    RespErrOutOfMemory,
39    RespErrInvalidScanoutId,
40    RespErrInvalidResourceId,
41    RespErrInvalidContextId,
42    RespErrInvalidParameter,
43}
44
45impl TryFrom<u32> for CtrlType {
46    type Error = ();
47
48    fn try_from(int: u32) -> Result<Self, Self::Error> {
49        match int {
50            /* 2d commands */
51            v if v == CtrlType::CmdGetDisplayInfo as u32 => Ok(CtrlType::CmdGetDisplayInfo),
52            v if v == CtrlType::CmdResourceCreate2d as u32 => Ok(CtrlType::CmdResourceCreate2d),
53            v if v == CtrlType::CmdResourceUref as u32 => Ok(CtrlType::CmdResourceUref),
54            v if v == CtrlType::CmdSetScanout as u32 => Ok(CtrlType::CmdSetScanout),
55            v if v == CtrlType::CmdResourceFlush as u32 => Ok(CtrlType::CmdResourceFlush),
56            v if v == CtrlType::CmdTransferToHost2d as u32 => Ok(CtrlType::CmdTransferToHost2d),
57            v if v == CtrlType::CmdResourceAttachBacking as u32 => {
58                Ok(CtrlType::CmdResourceAttachBacking)
59            }
60            v if v == CtrlType::CmdResourceDetachBacking as u32 => {
61                Ok(CtrlType::CmdResourceDetachBacking)
62            }
63            v if v == CtrlType::CmdGetCapsetInfo as u32 => Ok(CtrlType::CmdGetCapsetInfo),
64            v if v == CtrlType::CmdGetCapset as u32 => Ok(CtrlType::CmdGetCapset),
65            v if v == CtrlType::CmdGetEdid as u32 => Ok(CtrlType::CmdGetEdid),
66
67            /* cursor commands */
68            v if v == CtrlType::CmdUpdateCursor as u32 => Ok(CtrlType::CmdUpdateCursor),
69            v if v == CtrlType::CmdMoveCursor as u32 => Ok(CtrlType::CmdMoveCursor),
70
71            /* success responses */
72            v if v == CtrlType::RespOkNoData as u32 => Ok(CtrlType::RespOkNoData),
73            v if v == CtrlType::RespOkDisplayInfo as u32 => Ok(CtrlType::RespOkDisplayInfo),
74            v if v == CtrlType::RespOkCapsetInfo as u32 => Ok(CtrlType::RespOkCapsetInfo),
75            v if v == CtrlType::RespOkCapset as u32 => Ok(CtrlType::RespOkCapset),
76            v if v == CtrlType::RespOkEdid as u32 => Ok(CtrlType::RespOkEdid),
77
78            /* error responses */
79            v if v == CtrlType::RespErrUnspec as u32 => Ok(CtrlType::RespErrUnspec),
80            v if v == CtrlType::RespErrOutOfMemory as u32 => Ok(CtrlType::RespErrOutOfMemory),
81            v if v == CtrlType::RespErrInvalidScanoutId as u32 => {
82                Ok(CtrlType::RespErrInvalidScanoutId)
83            }
84            v if v == CtrlType::RespErrInvalidResourceId as u32 => {
85                Ok(CtrlType::RespErrInvalidResourceId)
86            }
87            v if v == CtrlType::RespErrInvalidContextId as u32 => {
88                Ok(CtrlType::RespErrInvalidContextId)
89            }
90            v if v == CtrlType::RespErrInvalidParameter as u32 => {
91                Ok(CtrlType::RespErrInvalidParameter)
92            }
93
94            _ => Err(()),
95        }
96    }
97}
98
99#[derive(Debug, Copy, Clone)]
100#[repr(C)]
101pub struct CtrlHeader {
102    pub ctrl_type: CtrlType,
103    pub flags: u32,
104    pub fence_id: u64,
105    pub ctx_id: u32,
106    pub padding: u32,
107}
108
109impl CtrlHeader {
110    pub const ENCODED_SIZE: usize = core::mem::size_of::<Self>();
111
112    pub fn write_to_byte_iter<'a>(
113        &self,
114        dst: &mut impl Iterator<Item = &'a mut u8>,
115    ) -> Result<(), ErrorCode> {
116        // Write out fields to iterator.
117        //
118        // This struct doesn't need any padding bytes.
119        copy_to_iter(dst, u32::to_le_bytes(self.ctrl_type as u32).into_iter())?;
120        copy_to_iter(dst, u32::to_le_bytes(self.flags).into_iter())?;
121        copy_to_iter(dst, u64::to_le_bytes(self.fence_id).into_iter())?;
122        copy_to_iter(dst, u32::to_le_bytes(self.ctx_id).into_iter())?;
123        copy_to_iter(dst, u32::to_le_bytes(self.padding).into_iter())?;
124
125        Ok(())
126    }
127
128    pub fn from_byte_iter(src: &mut impl Iterator<Item = u8>) -> Result<Self, ErrorCode> {
129        let ctrl_type = CtrlType::try_from(u32::from_le_bytes(bytes_from_iter(src)?))
130            .map_err(|()| ErrorCode::INVAL)?;
131        let flags = u32::from_le_bytes(bytes_from_iter(src)?);
132        let fence_id = u64::from_le_bytes(bytes_from_iter(src)?);
133        let ctx_id = u32::from_le_bytes(bytes_from_iter(src)?);
134        let padding = u32::from_le_bytes(bytes_from_iter(src)?);
135
136        Ok(CtrlHeader {
137            ctrl_type,
138            flags,
139            fence_id,
140            ctx_id,
141            padding,
142        })
143    }
144}