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