• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::VecDeque;
6 use std::mem::size_of;
7 
8 use zerocopy::FromBytes;
9 use zerocopy::Immutable;
10 use zerocopy::IntoBytes;
11 
12 use crate::bytestream::Reader;
13 use crate::bytestream::Writer;
14 use crate::ipc::kumquat_gpu_protocol::*;
15 use crate::rutabaga_os::AsBorrowedDescriptor;
16 use crate::rutabaga_os::AsRawDescriptor;
17 use crate::rutabaga_os::OwnedDescriptor;
18 use crate::rutabaga_os::RawDescriptor;
19 use crate::rutabaga_os::Tube;
20 use crate::rutabaga_os::DEFAULT_RAW_DESCRIPTOR;
21 use crate::rutabaga_utils::RutabagaError;
22 use crate::rutabaga_utils::RutabagaHandle;
23 use crate::rutabaga_utils::RutabagaResult;
24 use crate::rutabaga_utils::RUTABAGA_HANDLE_TYPE_SIGNAL_EVENT_FD;
25 
26 const MAX_DESCRIPTORS: usize = 1;
27 const MAX_COMMAND_SIZE: usize = 4096;
28 
29 pub struct RutabagaStream {
30     stream: Tube,
31     write_buffer: [u8; MAX_COMMAND_SIZE],
32     read_buffer: [u8; MAX_COMMAND_SIZE],
33     descriptors: [RawDescriptor; MAX_DESCRIPTORS],
34 }
35 
36 impl RutabagaStream {
new(stream: Tube) -> RutabagaStream37     pub fn new(stream: Tube) -> RutabagaStream {
38         RutabagaStream {
39             stream,
40             write_buffer: [0; MAX_COMMAND_SIZE],
41             read_buffer: [0; MAX_COMMAND_SIZE],
42             descriptors: [DEFAULT_RAW_DESCRIPTOR; MAX_DESCRIPTORS],
43         }
44     }
45 
write<T: FromBytes + IntoBytes + Immutable>( &mut self, encode: KumquatGpuProtocolWrite<T>, ) -> RutabagaResult<()>46     pub fn write<T: FromBytes + IntoBytes + Immutable>(
47         &mut self,
48         encode: KumquatGpuProtocolWrite<T>,
49     ) -> RutabagaResult<()> {
50         let mut writer = Writer::new(&mut self.write_buffer);
51         let mut num_descriptors = 0;
52 
53         let _handle_opt: Option<RutabagaHandle> = match encode {
54             KumquatGpuProtocolWrite::Cmd(cmd) => {
55                 writer.write_obj(cmd)?;
56                 None
57             }
58             KumquatGpuProtocolWrite::CmdWithHandle(cmd, handle) => {
59                 writer.write_obj(cmd)?;
60                 num_descriptors = 1;
61                 self.descriptors[0] = handle.os_handle.as_raw_descriptor();
62                 Some(handle)
63             }
64             KumquatGpuProtocolWrite::CmdWithData(cmd, data) => {
65                 writer.write_obj(cmd)?;
66                 writer.write_all(&data)?;
67                 None
68             }
69         };
70 
71         let bytes_written = writer.bytes_written();
72         self.stream.send(
73             &self.write_buffer[0..bytes_written],
74             &self.descriptors[0..num_descriptors],
75         )?;
76         Ok(())
77     }
78 
read(&mut self) -> RutabagaResult<Vec<KumquatGpuProtocol>>79     pub fn read(&mut self) -> RutabagaResult<Vec<KumquatGpuProtocol>> {
80         let mut vec: Vec<KumquatGpuProtocol> = Vec::new();
81         let (bytes_read, descriptor_vec) = self.stream.receive(&mut self.read_buffer)?;
82         let mut descriptors: VecDeque<OwnedDescriptor> = descriptor_vec.into();
83 
84         if bytes_read == 0 {
85             vec.push(KumquatGpuProtocol::OkNoData);
86             return Ok(vec);
87         }
88 
89         let mut reader = Reader::new(&self.read_buffer[0..bytes_read]);
90         while reader.available_bytes() != 0 {
91             let hdr = reader.peek_obj::<kumquat_gpu_protocol_ctrl_hdr>()?;
92             let protocol = match hdr.type_ {
93                 KUMQUAT_GPU_PROTOCOL_GET_NUM_CAPSETS => {
94                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
95                     KumquatGpuProtocol::GetNumCapsets
96                 }
97                 KUMQUAT_GPU_PROTOCOL_GET_CAPSET_INFO => {
98                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
99                     KumquatGpuProtocol::GetCapsetInfo(hdr.payload)
100                 }
101                 KUMQUAT_GPU_PROTOCOL_GET_CAPSET => {
102                     KumquatGpuProtocol::GetCapset(reader.read_obj()?)
103                 }
104                 KUMQUAT_GPU_PROTOCOL_CTX_CREATE => {
105                     KumquatGpuProtocol::CtxCreate(reader.read_obj()?)
106                 }
107                 KUMQUAT_GPU_PROTOCOL_CTX_DESTROY => {
108                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
109                     KumquatGpuProtocol::CtxDestroy(hdr.payload)
110                 }
111                 KUMQUAT_GPU_PROTOCOL_CTX_ATTACH_RESOURCE => {
112                     KumquatGpuProtocol::CtxAttachResource(reader.read_obj()?)
113                 }
114                 KUMQUAT_GPU_PROTOCOL_CTX_DETACH_RESOURCE => {
115                     KumquatGpuProtocol::CtxDetachResource(reader.read_obj()?)
116                 }
117                 KUMQUAT_GPU_PROTOCOL_RESOURCE_CREATE_3D => {
118                     KumquatGpuProtocol::ResourceCreate3d(reader.read_obj()?)
119                 }
120                 KUMQUAT_GPU_PROTOCOL_TRANSFER_TO_HOST_3D => {
121                     let os_handle = descriptors
122                         .pop_front()
123                         .ok_or(RutabagaError::InvalidResourceId)?;
124                     let resp: kumquat_gpu_protocol_transfer_host_3d = reader.read_obj()?;
125 
126                     let handle = RutabagaHandle {
127                         os_handle,
128                         handle_type: RUTABAGA_HANDLE_TYPE_SIGNAL_EVENT_FD,
129                     };
130 
131                     KumquatGpuProtocol::TransferToHost3d(resp, handle)
132                 }
133                 KUMQUAT_GPU_PROTOCOL_TRANSFER_FROM_HOST_3D => {
134                     let os_handle = descriptors
135                         .pop_front()
136                         .ok_or(RutabagaError::InvalidResourceId)?;
137                     let resp: kumquat_gpu_protocol_transfer_host_3d = reader.read_obj()?;
138 
139                     let handle = RutabagaHandle {
140                         os_handle,
141                         handle_type: RUTABAGA_HANDLE_TYPE_SIGNAL_EVENT_FD,
142                     };
143 
144                     KumquatGpuProtocol::TransferFromHost3d(resp, handle)
145                 }
146                 KUMQUAT_GPU_PROTOCOL_SUBMIT_3D => {
147                     let cmd: kumquat_gpu_protocol_cmd_submit = reader.read_obj()?;
148                     if reader.available_bytes() < cmd.size.try_into()? {
149                         // Large command buffers should handled via shared memory.
150                         return Err(RutabagaError::InvalidCommandBuffer);
151                     } else if reader.available_bytes() != 0 {
152                         let num_in_fences = cmd.num_in_fences as usize;
153                         let cmd_size = cmd.size as usize;
154                         let mut cmd_buf = vec![0; cmd_size];
155                         let mut fence_ids: Vec<u64> = Vec::with_capacity(num_in_fences);
156                         for _ in 0..num_in_fences {
157                             match reader.read_obj::<u64>() {
158                                 Ok(fence_id) => {
159                                     fence_ids.push(fence_id);
160                                 }
161                                 Err(_) => return Err(RutabagaError::InvalidIovec),
162                             }
163                         }
164                         reader.read_exact(&mut cmd_buf[..])?;
165                         KumquatGpuProtocol::CmdSubmit3d(cmd, cmd_buf, fence_ids)
166                     } else {
167                         KumquatGpuProtocol::CmdSubmit3d(cmd, Vec::new(), Vec::new())
168                     }
169                 }
170                 KUMQUAT_GPU_PROTOCOL_RESOURCE_CREATE_BLOB => {
171                     KumquatGpuProtocol::ResourceCreateBlob(reader.read_obj()?)
172                 }
173                 KUMQUAT_GPU_PROTOCOL_SNAPSHOT_SAVE => {
174                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
175                     KumquatGpuProtocol::SnapshotSave
176                 }
177                 KUMQUAT_GPU_PROTOCOL_SNAPSHOT_RESTORE => {
178                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
179                     KumquatGpuProtocol::SnapshotRestore
180                 }
181                 KUMQUAT_GPU_PROTOCOL_RESP_NUM_CAPSETS => {
182                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
183                     KumquatGpuProtocol::RespNumCapsets(hdr.payload)
184                 }
185                 KUMQUAT_GPU_PROTOCOL_RESP_CAPSET_INFO => {
186                     KumquatGpuProtocol::RespCapsetInfo(reader.read_obj()?)
187                 }
188                 KUMQUAT_GPU_PROTOCOL_RESP_CAPSET => {
189                     let len: usize = hdr.payload.try_into()?;
190                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
191                     let mut capset: Vec<u8> = vec![0; len];
192                     reader.read_exact(&mut capset)?;
193                     KumquatGpuProtocol::RespCapset(capset)
194                 }
195                 KUMQUAT_GPU_PROTOCOL_RESP_CONTEXT_CREATE => {
196                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
197                     KumquatGpuProtocol::RespContextCreate(hdr.payload)
198                 }
199                 KUMQUAT_GPU_PROTOCOL_RESP_RESOURCE_CREATE => {
200                     let os_handle = descriptors
201                         .pop_front()
202                         .ok_or(RutabagaError::InvalidResourceId)?;
203                     let resp: kumquat_gpu_protocol_resp_resource_create = reader.read_obj()?;
204 
205                     let handle = RutabagaHandle {
206                         os_handle,
207                         handle_type: resp.handle_type,
208                     };
209 
210                     KumquatGpuProtocol::RespResourceCreate(resp, handle)
211                 }
212                 KUMQUAT_GPU_PROTOCOL_RESP_CMD_SUBMIT_3D => {
213                     let os_handle = descriptors
214                         .pop_front()
215                         .ok_or(RutabagaError::InvalidResourceId)?;
216                     let resp: kumquat_gpu_protocol_resp_cmd_submit_3d = reader.read_obj()?;
217 
218                     let handle = RutabagaHandle {
219                         os_handle,
220                         handle_type: resp.handle_type,
221                     };
222 
223                     KumquatGpuProtocol::RespCmdSubmit3d(resp.fence_id, handle)
224                 }
225                 KUMQUAT_GPU_PROTOCOL_RESP_OK_SNAPSHOT => {
226                     reader.consume(size_of::<kumquat_gpu_protocol_ctrl_hdr>());
227                     KumquatGpuProtocol::RespOkSnapshot
228                 }
229                 _ => {
230                     return Err(RutabagaError::Unsupported);
231                 }
232             };
233 
234             vec.push(protocol);
235         }
236 
237         Ok(vec)
238     }
239 
as_borrowed_descriptor(&self) -> &OwnedDescriptor240     pub fn as_borrowed_descriptor(&self) -> &OwnedDescriptor {
241         self.stream.as_borrowed_descriptor()
242     }
243 }
244