1#![allow(non_upper_case_globals)]
6
7use crate::ffi::{
8 create_connection, device_import, execute_command, execute_inline_commands, export_buffer,
9 flush, get_buffer_handle, import_semaphore2, query, read_notification_channel,
10};
11use crate::image_file::{ImageFile, ImageInfo};
12use crate::magma::{StarnixPollItem, read_control_and_response, read_magma_command_and_type};
13
14use magma::{
15 MAGMA_CACHE_POLICY_CACHED, MAGMA_IMPORT_SEMAPHORE_ONE_SHOT, MAGMA_POLL_CONDITION_SIGNALED,
16 MAGMA_POLL_TYPE_SEMAPHORE, MAGMA_PRIORITY_MEDIUM, MAGMA_STATUS_INVALID_ARGS,
17 MAGMA_STATUS_MEMORY_ERROR, MAGMA_STATUS_OK, MAGMA_STATUS_TIMED_OUT, magma_buffer_clean_cache,
18 magma_buffer_get_cache_policy, magma_buffer_get_info, magma_buffer_id_t, magma_buffer_info_t,
19 magma_buffer_set_cache_policy, magma_buffer_set_name, magma_buffer_t, magma_cache_operation_t,
20 magma_cache_policy_t, magma_connection_create_buffer, magma_connection_create_context,
21 magma_connection_create_context2, magma_connection_get_error,
22 magma_connection_get_notification_channel_handle, magma_connection_import_buffer,
23 magma_connection_map_buffer, magma_connection_perform_buffer_op, magma_connection_release,
24 magma_connection_release_buffer, magma_connection_release_context,
25 magma_connection_release_semaphore, magma_connection_t, magma_connection_unmap_buffer,
26 magma_device_release, magma_device_t, magma_initialize_logging, magma_poll, magma_poll_item,
27 magma_poll_item_t, magma_semaphore_export, magma_semaphore_id_t, magma_semaphore_reset,
28 magma_semaphore_signal, magma_semaphore_t, virtio_magma_buffer_clean_cache_ctrl_t,
29 virtio_magma_buffer_clean_cache_resp_t, virtio_magma_buffer_export_ctrl_t,
30 virtio_magma_buffer_export_resp_t, virtio_magma_buffer_get_cache_policy_ctrl_t,
31 virtio_magma_buffer_get_cache_policy_resp_t, virtio_magma_buffer_get_handle_ctrl_t,
32 virtio_magma_buffer_get_handle_resp_t, virtio_magma_buffer_get_info_ctrl_t,
33 virtio_magma_buffer_get_info_resp_t, virtio_magma_buffer_set_cache_policy_ctrl_t,
34 virtio_magma_buffer_set_cache_policy_resp_t, virtio_magma_buffer_set_name_ctrl_t,
35 virtio_magma_buffer_set_name_resp_t, virtio_magma_connection_create_buffer_ctrl_t,
36 virtio_magma_connection_create_buffer_resp_t, virtio_magma_connection_create_context_ctrl_t,
37 virtio_magma_connection_create_context_resp_t, virtio_magma_connection_create_context2_ctrl_t,
38 virtio_magma_connection_create_context2_resp_t,
39 virtio_magma_connection_create_semaphore_ctrl_t,
40 virtio_magma_connection_create_semaphore_resp_t,
41 virtio_magma_connection_execute_command_ctrl_t, virtio_magma_connection_execute_command_resp_t,
42 virtio_magma_connection_execute_inline_commands_ctrl_t,
43 virtio_magma_connection_execute_inline_commands_resp_t, virtio_magma_connection_flush_ctrl_t,
44 virtio_magma_connection_flush_resp_t, virtio_magma_connection_get_error_ctrl_t,
45 virtio_magma_connection_get_error_resp_t,
46 virtio_magma_connection_get_notification_channel_handle_ctrl_t,
47 virtio_magma_connection_get_notification_channel_handle_resp_t,
48 virtio_magma_connection_import_buffer_ctrl_t, virtio_magma_connection_import_buffer_resp_t,
49 virtio_magma_connection_import_semaphore2_ctrl_t,
50 virtio_magma_connection_import_semaphore2_resp_t, virtio_magma_connection_map_buffer_ctrl_t,
51 virtio_magma_connection_map_buffer_resp_t, virtio_magma_connection_perform_buffer_op_ctrl_t,
52 virtio_magma_connection_perform_buffer_op_resp_t,
53 virtio_magma_connection_read_notification_channel_ctrl_t,
54 virtio_magma_connection_read_notification_channel_resp_t,
55 virtio_magma_connection_release_buffer_ctrl_t, virtio_magma_connection_release_buffer_resp_t,
56 virtio_magma_connection_release_context_ctrl_t, virtio_magma_connection_release_context_resp_t,
57 virtio_magma_connection_release_ctrl_t, virtio_magma_connection_release_resp_t,
58 virtio_magma_connection_release_semaphore_ctrl_t,
59 virtio_magma_connection_release_semaphore_resp_t, virtio_magma_connection_unmap_buffer_ctrl_t,
60 virtio_magma_connection_unmap_buffer_resp_t,
61 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_CLEAN_CACHE,
62 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_EXPORT,
63 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_GET_CACHE_POLICY,
64 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_GET_HANDLE,
65 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_GET_INFO,
66 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_SET_CACHE_POLICY,
67 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_SET_NAME,
68 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_BUFFER,
69 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_CONTEXT,
70 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_CONTEXT2,
71 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_SEMAPHORE,
72 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_EXECUTE_COMMAND,
73 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_EXECUTE_INLINE_COMMANDS,
74 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_FLUSH,
75 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_GET_ERROR,
76 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_GET_NOTIFICATION_CHANNEL_HANDLE,
77 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_IMPORT_BUFFER,
78 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_IMPORT_SEMAPHORE2,
79 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_MAP_BUFFER,
80 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_PERFORM_BUFFER_OP,
81 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_READ_NOTIFICATION_CHANNEL,
82 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE,
83 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE_BUFFER,
84 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE_CONTEXT,
85 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE_SEMAPHORE,
86 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_UNMAP_BUFFER,
87 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_CREATE_CONNECTION,
88 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_IMPORT,
89 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_QUERY,
90 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_RELEASE,
91 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_POLL,
92 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_SEMAPHORE_EXPORT,
93 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_SEMAPHORE_RESET,
94 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_SEMAPHORE_SIGNAL,
95 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_CLEAN_CACHE,
96 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_GET_CACHE_POLICY,
97 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_GET_INFO,
98 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_SET_CACHE_POLICY,
99 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_SET_NAME,
100 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_BUFFER,
101 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_CONTEXT,
102 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_CONTEXT2,
103 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_SEMAPHORE,
104 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_EXECUTE_COMMAND,
105 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_EXECUTE_INLINE_COMMANDS,
106 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_GET_ERROR,
107 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_GET_NOTIFICATION_CHANNEL_HANDLE,
108 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_IMPORT_BUFFER,
109 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_IMPORT_SEMAPHORE2,
110 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_MAP_BUFFER,
111 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_PERFORM_BUFFER_OP,
112 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE,
113 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE_BUFFER,
114 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE_CONTEXT,
115 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE_SEMAPHORE,
116 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_UNMAP_BUFFER,
117 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_CREATE_CONNECTION,
118 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_IMPORT,
119 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_QUERY,
120 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_RELEASE,
121 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_POLL,
122 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_SEMAPHORE_EXPORT,
123 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_SEMAPHORE_RESET,
124 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_SEMAPHORE_SIGNAL,
125 virtio_magma_device_create_connection_ctrl, virtio_magma_device_create_connection_resp_t,
126 virtio_magma_device_import_ctrl_t, virtio_magma_device_import_resp_t,
127 virtio_magma_device_query_ctrl_t, virtio_magma_device_query_resp_t,
128 virtio_magma_device_release_ctrl_t, virtio_magma_device_release_resp_t,
129 virtio_magma_poll_ctrl_t, virtio_magma_poll_resp_t, virtio_magma_semaphore_export_ctrl_t,
130 virtio_magma_semaphore_export_resp_t, virtio_magma_semaphore_reset_ctrl_t,
131 virtio_magma_semaphore_reset_resp_t, virtio_magma_semaphore_signal_ctrl_t,
132 virtio_magma_semaphore_signal_resp_t, virtmagma_buffer_set_name_wrapper,
133};
134use starnix_core::fileops_impl_nonseekable;
135use starnix_core::fs::fuchsia::sync_file::{SyncFence, SyncFile, SyncPoint, Timeline};
136use starnix_core::fs::fuchsia::{
137 AnonymousRemoteFileObject, RemoteFileObject, RemoteZxioFileObject,
138};
139use starnix_core::mm::memory::MemoryObject;
140use starnix_core::mm::{MemoryAccessorExt, ProtectionFlags};
141use starnix_core::task::CurrentTask;
142use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
143use starnix_core::vfs::{
144 FdFlags, FdNumber, FileObject, FileOps, FsNode, MemoryRegularFile, fileops_impl_noop_sync,
145};
146use starnix_lifecycle::AtomicCounter;
147use starnix_logging::{impossible_error, log_error, log_warn, track_stub};
148use starnix_sync::{
149 LockDepMutex, MagmaBuffersLock, MagmaConnectionsLock, MagmaDevicesLock, MagmaSemaphoresLock,
150};
151use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
152use starnix_types::user_buffer::UserBuffer;
153use starnix_uapi::device_id::DeviceId;
154use starnix_uapi::errors::Errno;
155use starnix_uapi::open_flags::OpenFlags;
156use starnix_uapi::user_address::{UserAddress, UserRef};
157use starnix_uapi::{errno, error};
158use std::collections::HashMap;
159use std::sync::{Arc, Once};
160use zerocopy::IntoBytes;
161
162#[derive(Clone)]
163pub enum BufferInfo {
164 Default,
165 Image(ImageInfo),
166}
167
168pub struct MagmaConnection {
170 pub handle: magma_connection_t,
171}
172
173impl Drop for MagmaConnection {
174 fn drop(&mut self) {
175 #[allow(clippy::undocumented_unsafe_blocks)]
176 unsafe {
177 magma_connection_release(self.handle)
178 }
179 }
180}
181
182pub struct MagmaDevice {
184 pub handle: magma_device_t,
185}
186
187impl Drop for MagmaDevice {
188 fn drop(&mut self) {
190 #[allow(clippy::undocumented_unsafe_blocks)]
191 unsafe {
192 magma_device_release(self.handle)
193 }
194 }
195}
196
197pub struct MagmaBuffer {
199 pub connection: Arc<MagmaConnection>,
201 pub handle: magma_buffer_t,
202}
203
204impl Drop for MagmaBuffer {
205 fn drop(&mut self) {
208 #[allow(clippy::undocumented_unsafe_blocks)]
209 unsafe {
210 magma_connection_release_buffer(self.connection.handle, self.handle)
211 }
212 }
213}
214
215pub struct MagmaSemaphore {
218 pub connection: Arc<MagmaConnection>,
220 pub handles: Vec<magma_semaphore_t>,
221 pub ids: Vec<magma_semaphore_id_t>,
222}
223
224impl Drop for MagmaSemaphore {
225 fn drop(&mut self) {
228 for handle in &self.handles {
229 #[allow(clippy::undocumented_unsafe_blocks)]
230 unsafe {
231 magma_connection_release_semaphore(self.connection.handle, *handle)
232 }
233 }
234 }
235}
236
237type BufferMap = HashMap<magma_buffer_id_t, BufferInfo>;
239
240pub type ConnectionMap = HashMap<u64, ConnectionInfo>;
242
243pub struct ConnectionInfo {
244 pub connection: Arc<MagmaConnection>,
245 pub buffer_map: BufferMap,
246}
247
248impl ConnectionInfo {
249 pub fn new(connection: Arc<MagmaConnection>) -> Self {
250 Self { connection, buffer_map: HashMap::new() }
251 }
252}
253
254pub type DeviceMap = HashMap<u64, Arc<MagmaDevice>>;
255
256pub struct MagmaFile {
257 supported_vendors: Vec<u16>,
258 devices: Arc<LockDepMutex<DeviceMap, MagmaDevicesLock>>,
259 connections: Arc<LockDepMutex<ConnectionMap, MagmaConnectionsLock>>,
260 buffers: Arc<LockDepMutex<HashMap<magma_buffer_id_t, Arc<MagmaBuffer>>, MagmaBuffersLock>>,
261 semaphores:
262 Arc<LockDepMutex<HashMap<magma_semaphore_t, Arc<MagmaSemaphore>>, MagmaSemaphoresLock>>,
263 semaphore_id_generator: AtomicCounter<u64>,
264}
265
266impl MagmaFile {
267 pub fn init() {
268 let (server_end, client_end) = zx::Channel::create();
270
271 let result = fuchsia_component::client::connect_channel_to_protocol::<
272 fidl_fuchsia_logger::LogSinkMarker,
273 >(server_end);
274
275 if result.is_ok() {
276 #[allow(clippy::undocumented_unsafe_blocks)]
277 unsafe {
278 magma_initialize_logging(client_end.into_raw());
279 }
280 }
281 }
282
283 pub fn new_file(
284 _current_task: &CurrentTask,
285 _dev: DeviceId,
286 _node: &FsNode,
287 _flags: OpenFlags,
288 supported_vendors: Vec<u16>,
289 ) -> Result<Box<dyn FileOps>, Errno> {
290 static INIT: Once = Once::new();
291 INIT.call_once(|| {
292 Self::init();
293 });
294
295 Ok(Box::new(Self {
296 supported_vendors,
297 devices: Default::default(),
298 connections: Default::default(),
299 buffers: Default::default(),
300 semaphores: Default::default(),
301 semaphore_id_generator: AtomicCounter::new(1),
302 }))
303 }
304
305 fn get_memory_and_magma_buffer(
310 current_task: &CurrentTask,
311 fd: FdNumber,
312 ) -> Result<(MemoryObject, BufferInfo), Errno> {
313 let file = current_task.files().get(fd)?;
314 if let Some(file) = file.downcast_file::<ImageFile>() {
315 let buffer = BufferInfo::Image(file.info.clone());
316 Ok((
317 file.memory.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?,
318 buffer,
319 ))
320 } else if let Some(file) = file.downcast_file::<MemoryRegularFile>() {
321 let buffer = BufferInfo::Default;
322 Ok((
323 file.memory.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?,
324 buffer,
325 ))
326 } else if file.downcast_file::<RemoteFileObject>().is_some()
327 || file.downcast_file::<RemoteZxioFileObject>().is_some()
328 || file.downcast_file::<AnonymousRemoteFileObject>().is_some()
329 {
330 let buffer = BufferInfo::Default;
340 let memory = file
343 .get_memory(current_task, None, ProtectionFlags::READ | ProtectionFlags::WRITE)
344 .map_err(|_| errno!(EINVAL))?;
345 Ok((
346 memory.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?,
347 buffer,
348 ))
349 } else {
350 error!(EINVAL)
351 }
352 }
353
354 fn add_buffer_info(
359 &self,
360 connection_id: u64,
361 connection: Arc<MagmaConnection>,
362 buffer: magma_buffer_t,
363 buffer_id: magma_buffer_id_t,
364 buffer_info: BufferInfo,
365 ) {
366 let arc_buffer = Arc::new(MagmaBuffer { connection, handle: buffer });
367 self.connections
368 .lock()
369 .get_mut(&connection_id)
370 .map(|connection_info| connection_info.buffer_map.insert(buffer_id, buffer_info));
371 self.buffers.lock().insert(buffer_id, arc_buffer);
372 }
373
374 fn get_device(&self, device_id: u64) -> Result<Arc<MagmaDevice>, Errno> {
375 Ok(self.devices.lock().get(&device_id).ok_or_else(|| errno!(EINVAL))?.clone())
376 }
377
378 fn get_connection(&self, connection: u64) -> Result<Arc<MagmaConnection>, Errno> {
379 Ok(self
380 .connections
381 .lock()
382 .get(&connection)
383 .ok_or_else(|| errno!(EINVAL))?
384 .connection
385 .clone())
386 }
387
388 fn get_buffer(&self, buffer: magma_buffer_t) -> Result<Arc<MagmaBuffer>, Errno> {
389 Ok(self.buffers.lock().get(&buffer).ok_or_else(|| errno!(EINVAL))?.clone())
390 }
391
392 fn get_semaphore(&self, semaphore: magma_semaphore_t) -> Result<Arc<MagmaSemaphore>, i32> {
393 Ok(self.semaphores.lock().get(&semaphore).ok_or(MAGMA_STATUS_INVALID_ARGS)?.clone())
394 }
395
396 fn import_semaphore2(
397 &self,
398 current_task: &CurrentTask,
399 control: &virtio_magma_connection_import_semaphore2_ctrl_t,
400 response: &mut virtio_magma_connection_import_semaphore2_resp_t,
401 ) {
402 let mut status: i32 = MAGMA_STATUS_OK;
403
404 let fd = FdNumber::from_raw(control.semaphore_handle as i32);
405 let mut result_semaphore_id = 0;
406
407 if let (Ok(connection), Ok(file)) =
408 (self.get_connection(control.connection), current_task.files().get(fd))
409 {
410 let mut handles: Vec<magma_semaphore_t> = vec![];
411 let mut ids: Vec<magma_semaphore_id_t> = vec![];
412
413 if let Some(sync_file) = file.downcast_file::<SyncFile>() {
414 for sync_point in &sync_file.fence.sync_points {
415 if let Ok(counter) =
416 sync_point.counter.duplicate_handle(zx::Rights::SAME_RIGHTS)
417 {
418 if control.flags & MAGMA_IMPORT_SEMAPHORE_ONE_SHOT == 0 {
419 log_warn!(
421 "Importing magma semaphore without MAGMA_IMPORT_SEMAPHORE_ONE_SHOT"
422 );
423 }
424 let semaphore;
425 let semaphore_id;
426 (status, semaphore, semaphore_id) =
427 import_semaphore2(&connection, counter, control.flags);
428 if status != MAGMA_STATUS_OK {
429 break;
430 }
431 handles.push(semaphore as magma_semaphore_t);
432 ids.push(semaphore_id as magma_semaphore_id_t);
433 } else {
434 status = MAGMA_STATUS_MEMORY_ERROR;
435 break;
436 }
437 }
438 } else {
439 status = MAGMA_STATUS_INVALID_ARGS;
440 }
441
442 if status == MAGMA_STATUS_OK {
443 result_semaphore_id = self.semaphore_id_generator.next();
444
445 self.semaphores.lock().insert(
446 result_semaphore_id,
447 Arc::new(MagmaSemaphore { connection, handles, ids }),
448 );
449 }
450 } else {
451 status = MAGMA_STATUS_INVALID_ARGS;
452 }
453
454 let _ = current_task.files().close(fd);
456
457 response.result_return = status as u64;
458 response.semaphore_out = result_semaphore_id;
459 response.id_out = result_semaphore_id;
460 response.hdr.type_ =
461 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_IMPORT_SEMAPHORE2 as u32;
462 }
463}
464
465impl FileOps for MagmaFile {
466 fileops_impl_nonseekable!();
467 fileops_impl_noop_sync!();
468
469 fn ioctl(
470 &self,
471 _file: &FileObject,
472 current_task: &CurrentTask,
473 _request: u32,
474 arg: SyscallArg,
475 ) -> Result<SyscallResult, Errno> {
476 let user_addr = UserAddress::from(arg);
477 let (command, command_type) = read_magma_command_and_type(current_task, user_addr)?;
478 let response_address = UserAddress::from(command.response_address);
479
480 match command_type {
481 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_IMPORT => {
482 let (control, mut response): (
483 virtio_magma_device_import_ctrl_t,
484 virtio_magma_device_import_resp_t,
485 ) = read_control_and_response(current_task, &command)?;
486
487 let device = device_import(&self.supported_vendors, control)?;
488
489 {
490 let mut device_id = 0u64;
491 let mut retry_count = 0u64;
492 let mut device_map = self.devices.lock();
493
494 while device_id == 0 || device_map.contains_key(&device_id) {
495 starnix_crypto::cprng_draw(device_id.as_mut_bytes());
496 retry_count += 1;
497 if retry_count % 10 == 0 {
498 log_warn!("Too many retries generating device id: {}", retry_count);
499 }
500 }
501
502 device_map.insert(device_id, Arc::new(device));
503 response.device_out = device_id;
504 }
505
506 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_IMPORT as u32;
507
508 current_task.write_object(UserRef::new(response_address), &response)
509 }
510 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_CREATE_CONNECTION => {
511 let (control, mut response): (
512 virtio_magma_device_create_connection_ctrl,
513 virtio_magma_device_create_connection_resp_t,
514 ) = read_control_and_response(current_task, &command)?;
515
516 let device = self.get_device(control.device)?;
517
518 if let Ok(connection) = create_connection(device.handle) {
519 let mut connection_id = 0u64;
520 let mut retry_count = 0u64;
521 let mut connection_map = self.connections.lock();
522
523 while connection_id == 0 || connection_map.contains_key(&connection_id) {
524 starnix_crypto::cprng_draw(connection_id.as_mut_bytes());
525 retry_count += 1;
526 if retry_count % 10 == 0 {
527 log_warn!("Too many retries generating connection id: {}", retry_count);
528 }
529 }
530
531 connection_map.insert(connection_id, ConnectionInfo::new(Arc::new(connection)));
532 response.connection_out = connection_id;
533 response.result_return = MAGMA_STATUS_OK as u64;
534 } else {
535 response.result_return = MAGMA_STATUS_MEMORY_ERROR as u64;
536 }
537 response.hdr.type_ =
538 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_CREATE_CONNECTION as u32;
539
540 current_task.write_object(UserRef::new(response_address), &response)
541 }
542 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE => {
543 let (control, mut response): (
544 virtio_magma_connection_release_ctrl_t,
545 virtio_magma_connection_release_resp_t,
546 ) = read_control_and_response(current_task, &command)?;
547
548 let connection_id = control.connection;
549 self.connections.lock().remove(&connection_id);
551
552 response.hdr.type_ =
553 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE as u32;
554
555 current_task.write_object(UserRef::new(response_address), &response)
556 }
557 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_RELEASE => {
558 let (control, mut response): (
559 virtio_magma_device_release_ctrl_t,
560 virtio_magma_device_release_resp_t,
561 ) = read_control_and_response(current_task, &command)?;
562
563 let device_id = control.device;
564 self.devices.lock().remove(&device_id);
566 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_RELEASE as u32;
567
568 current_task.write_object(UserRef::new(response_address), &response)
569 }
570 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_FLUSH => {
571 let (control, mut response): (
572 virtio_magma_connection_flush_ctrl_t,
573 virtio_magma_connection_flush_resp_t,
574 ) = read_control_and_response(current_task, &command)?;
575 let connection = self.get_connection(control.connection)?;
576
577 flush(control, &mut response, &connection);
578
579 current_task.write_object(UserRef::new(response_address), &response)
580 }
581 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_READ_NOTIFICATION_CHANNEL => {
582 let (control, mut response): (
583 virtio_magma_connection_read_notification_channel_ctrl_t,
584 virtio_magma_connection_read_notification_channel_resp_t,
585 ) = read_control_and_response(current_task, &command)?;
586 let connection = self.get_connection(control.connection)?;
587
588 read_notification_channel(current_task, control, &mut response, &connection)?;
589
590 current_task.write_object(UserRef::new(response_address), &response)
591 }
592 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_GET_HANDLE => {
593 let (control, mut response): (
594 virtio_magma_buffer_get_handle_ctrl_t,
595 virtio_magma_buffer_get_handle_resp_t,
596 ) = read_control_and_response(current_task, &command)?;
597 let buffer = self.get_buffer(control.buffer)?;
598
599 get_buffer_handle(current_task, control, &mut response, &buffer)?;
600
601 current_task.write_object(UserRef::new(response_address), &response)
602 }
603 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE_BUFFER => {
604 let (control, mut response): (
605 virtio_magma_connection_release_buffer_ctrl_t,
606 virtio_magma_connection_release_buffer_resp_t,
607 ) = read_control_and_response(current_task, &command)?;
608
609 if let Some(buffers) = self.connections.lock().get_mut(&{ control.connection }) {
610 match buffers.buffer_map.remove(&{ control.buffer }) {
611 Some(_) => (),
612 _ => {
613 log_error!("Calling magma_release_buffer with an invalid buffer.");
614 }
615 };
616 }
617 self.buffers.lock().remove(&{ control.buffer });
618
619 response.hdr.type_ =
620 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE_BUFFER as u32;
621
622 current_task.write_object(UserRef::new(response_address), &response)
623 }
624 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_EXPORT => {
625 let (control, mut response): (
626 virtio_magma_buffer_export_ctrl_t,
627 virtio_magma_buffer_export_resp_t,
628 ) = read_control_and_response(current_task, &command)?;
629 let buffer = self.get_buffer(control.buffer)?;
630
631 export_buffer(
632 current_task,
633 control,
634 &mut response,
635 &buffer,
636 &self.connections.lock(),
637 )?;
638
639 current_task.write_object(UserRef::new(response_address), &response)
640 }
641 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_IMPORT_BUFFER => {
642 let (control, mut response): (
643 virtio_magma_connection_import_buffer_ctrl_t,
644 virtio_magma_connection_import_buffer_resp_t,
645 ) = read_control_and_response(current_task, &command)?;
646 let connection_id = control.connection;
647 let connection = self.get_connection(connection_id)?;
648
649 let buffer_fd = FdNumber::from_raw(control.buffer_handle as i32);
650 let (memory, buffer) =
651 MagmaFile::get_memory_and_magma_buffer(current_task, buffer_fd)?;
652 let vmo = memory.into_vmo().ok_or_else(|| errno!(EINVAL))?;
653
654 let mut buffer_out = magma_buffer_t::default();
655 let mut size_out = 0u64;
656 let mut id_out = magma_buffer_id_t::default();
657 response.result_return = {
658 #[allow(clippy::undocumented_unsafe_blocks)]
659 unsafe {
660 magma_connection_import_buffer(
661 connection.handle,
662 vmo.into_raw(),
663 &mut size_out,
664 &mut buffer_out,
665 &mut id_out,
666 ) as u64
667 }
668 };
669
670 self.add_buffer_info(connection_id, connection, buffer_out, id_out, buffer);
672 let _ = current_task.files().close(buffer_fd);
674
675 response.buffer_out = id_out;
676 response.id_out = id_out;
677 response.size_out = size_out;
678 response.hdr.type_ =
679 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_IMPORT_BUFFER as u32;
680 current_task.write_object(UserRef::new(response_address), &response)
681 }
682 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_GET_NOTIFICATION_CHANNEL_HANDLE => {
683 let (control, mut response): (
684 virtio_magma_connection_get_notification_channel_handle_ctrl_t,
685 virtio_magma_connection_get_notification_channel_handle_resp_t,
686 ) = read_control_and_response(current_task, &command)?;
687 let connection = self.get_connection(control.connection)?;
688
689 response.result_return = {
690 #[allow(clippy::undocumented_unsafe_blocks)]
691 unsafe {
692 magma_connection_get_notification_channel_handle(connection.handle)
693 }
694 };
695
696 response.hdr.type_ =
697 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_GET_NOTIFICATION_CHANNEL_HANDLE as u32;
698 current_task.write_object(UserRef::new(response_address), &response)
699 }
700 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_CONTEXT => {
701 let (control, mut response): (
702 virtio_magma_connection_create_context_ctrl_t,
703 virtio_magma_connection_create_context_resp_t,
704 ) = read_control_and_response(current_task, &command)?;
705 let connection = self.get_connection(control.connection)?;
706
707 let mut context_id_out = 0;
708 response.result_return = {
709 #[allow(clippy::undocumented_unsafe_blocks)]
710 unsafe {
711 magma_connection_create_context(connection.handle, &mut context_id_out)
712 as u64
713 }
714 };
715 response.context_id_out = context_id_out as u64;
716
717 response.hdr.type_ =
718 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_CONTEXT as u32;
719 current_task.write_object(UserRef::new(response_address), &response)
720 }
721 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_CONTEXT2 => {
722 let (control, mut response): (
723 virtio_magma_connection_create_context2_ctrl_t,
724 virtio_magma_connection_create_context2_resp_t,
725 ) = read_control_and_response(current_task, &command)?;
726 let connection = self.get_connection(control.connection)?;
727
728 let priority = if control.priority > MAGMA_PRIORITY_MEDIUM {
730 MAGMA_PRIORITY_MEDIUM
731 } else {
732 control.priority
733 };
734
735 let mut context_id_out = 0;
736 response.result_return = {
737 #[allow(clippy::undocumented_unsafe_blocks)]
738 unsafe {
739 magma_connection_create_context2(
740 connection.handle,
741 priority,
742 &mut context_id_out,
743 ) as u64
744 }
745 };
746 response.context_id_out = context_id_out as u64;
747
748 response.hdr.type_ =
749 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_CONTEXT2 as u32;
750 current_task.write_object(UserRef::new(response_address), &response)
751 }
752 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE_CONTEXT => {
753 let (control, mut response): (
754 virtio_magma_connection_release_context_ctrl_t,
755 virtio_magma_connection_release_context_resp_t,
756 ) = read_control_and_response(current_task, &command)?;
757 let connection = self.get_connection(control.connection)?;
758
759 #[allow(clippy::undocumented_unsafe_blocks)]
760 unsafe {
761 magma_connection_release_context(connection.handle, control.context_id);
762 }
763
764 response.hdr.type_ =
765 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE_CONTEXT as u32;
766 current_task.write_object(UserRef::new(response_address), &response)
767 }
768 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_BUFFER => {
769 let (control, mut response): (
770 virtio_magma_connection_create_buffer_ctrl_t,
771 virtio_magma_connection_create_buffer_resp_t,
772 ) = read_control_and_response(current_task, &command)?;
773 let connection_id = control.connection;
774 let connection = self.get_connection(connection_id)?;
775
776 let mut size_out = 0;
777 let mut buffer_out = 0;
778 let mut id_out = 0;
779 response.result_return = {
780 #[allow(clippy::undocumented_unsafe_blocks)]
781 unsafe {
782 magma_connection_create_buffer(
783 connection.handle,
784 control.size,
785 &mut size_out,
786 &mut buffer_out,
787 &mut id_out,
788 ) as u64
789 }
790 };
791 response.size_out = size_out;
792 response.buffer_out = id_out;
793 response.id_out = id_out;
794
795 self.add_buffer_info(
796 connection_id,
797 connection,
798 buffer_out,
799 id_out,
800 BufferInfo::Default,
801 );
802
803 response.hdr.type_ =
804 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_BUFFER as u32;
805 current_task.write_object(UserRef::new(response_address), &response)
806 }
807 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_CREATE_SEMAPHORE => {
808 let (control, mut response): (
809 virtio_magma_connection_create_semaphore_ctrl_t,
810 virtio_magma_connection_create_semaphore_resp_t,
811 ) = read_control_and_response(current_task, &command)?;
812 let connection = self.get_connection(control.connection)?;
813 let status: i32;
814 let mut result_semaphore_id = 0;
815
816 let counter = zx::Counter::create();
818 let flags: u64 = 0;
819 let semaphore;
820 let semaphore_id;
821 (status, semaphore, semaphore_id) = import_semaphore2(&connection, counter, flags);
822 if status == MAGMA_STATUS_OK {
823 result_semaphore_id = self.semaphore_id_generator.next();
824
825 self.semaphores.lock().insert(
826 result_semaphore_id,
827 Arc::new(MagmaSemaphore {
828 connection,
829 handles: vec![semaphore; 1],
830 ids: vec![semaphore_id; 1],
831 }),
832 );
833 }
834 response.result_return = status as u64;
835 response.semaphore_out = result_semaphore_id;
836 response.id_out = result_semaphore_id;
837 response.hdr.type_ =
838 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_CREATE_SEMAPHORE as u32;
839 current_task.write_object(UserRef::new(response_address), &response)
840 }
841 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_GET_ERROR => {
842 let (control, mut response): (
843 virtio_magma_connection_get_error_ctrl_t,
844 virtio_magma_connection_get_error_resp_t,
845 ) = read_control_and_response(current_task, &command)?;
846 let connection = self.get_connection(control.connection)?;
847
848 response.result_return = {
849 #[allow(clippy::undocumented_unsafe_blocks)]
850 unsafe {
851 magma_connection_get_error(connection.handle) as u64
852 }
853 };
854
855 response.hdr.type_ =
856 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_GET_ERROR as u32;
857 current_task.write_object(UserRef::new(response_address), &response)
858 }
859 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_IMPORT_SEMAPHORE2 => {
860 let (control, mut response): (
861 virtio_magma_connection_import_semaphore2_ctrl_t,
862 virtio_magma_connection_import_semaphore2_resp_t,
863 ) = read_control_and_response(current_task, &command)?;
864
865 self.import_semaphore2(current_task, &control, &mut response);
866
867 current_task.write_object(UserRef::new(response_address), &response)
868 }
869 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_RELEASE_SEMAPHORE => {
870 let (control, mut response): (
871 virtio_magma_connection_release_semaphore_ctrl_t,
872 virtio_magma_connection_release_semaphore_resp_t,
873 ) = read_control_and_response(current_task, &command)?;
874
875 self.semaphores.lock().remove(&{ control.semaphore });
876
877 response.hdr.type_ =
878 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_RELEASE_SEMAPHORE as u32;
879 current_task.write_object(UserRef::new(response_address), &response)
880 }
881 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_SEMAPHORE_EXPORT => {
882 let (control, mut response): (
883 virtio_magma_semaphore_export_ctrl_t,
884 virtio_magma_semaphore_export_resp_t,
885 ) = read_control_and_response(current_task, &command)?;
886 let mut status: i32 = MAGMA_STATUS_OK;
887
888 let mut sync_points: Vec<SyncPoint> = vec![];
889 let mut sync_file_fd: i32 = -1;
890
891 match self.get_semaphore(control.semaphore) {
892 Ok(semaphore) => {
893 for handle in &semaphore.handles {
894 let mut raw_handle = 0;
895 status = {
896 #[allow(clippy::undocumented_unsafe_blocks)]
897 unsafe {
898 magma_semaphore_export(*handle, &mut raw_handle)
899 }
900 };
901 if status != MAGMA_STATUS_OK {
902 break;
903 }
904 let handle = {
905 #[allow(clippy::undocumented_unsafe_blocks)]
906 unsafe {
907 zx::NullableHandle::from_raw(raw_handle)
908 }
909 };
910
911 sync_points.push(SyncPoint::new(Timeline::Magma, handle.into()));
912 }
913 }
914 Err(s) => status = s,
915 }
916
917 if status == MAGMA_STATUS_OK {
918 let sync_file_name: &[u8; 32] =
919 b"magma semaphore\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
920 let file = SyncFile::new_file(
921 current_task,
922 *sync_file_name,
923 SyncFence { sync_points },
924 )?;
925
926 let fd = current_task.add_file(file, FdFlags::empty())?;
927 sync_file_fd = fd.raw();
928 }
929
930 response.result_return = status as u64;
931 response.semaphore_handle_out = sync_file_fd as u64;
932 response.hdr.type_ =
933 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_SEMAPHORE_EXPORT as u32;
934 current_task.write_object(UserRef::new(response_address), &response)
935 }
936 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_SEMAPHORE_RESET => {
937 let (control, mut response): (
938 virtio_magma_semaphore_reset_ctrl_t,
939 virtio_magma_semaphore_reset_resp_t,
940 ) = read_control_and_response(current_task, &command)?;
941
942 if let Ok(semaphore) = self.get_semaphore(control.semaphore) {
943 for handle in &semaphore.handles {
944 #[allow(clippy::undocumented_unsafe_blocks)]
945 unsafe {
946 magma_semaphore_reset(*handle);
947 }
948 }
949 }
950 response.hdr.type_ =
951 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_SEMAPHORE_RESET as u32;
952 current_task.write_object(UserRef::new(response_address), &response)
953 }
954 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_SEMAPHORE_SIGNAL => {
955 let (control, mut response): (
956 virtio_magma_semaphore_signal_ctrl_t,
957 virtio_magma_semaphore_signal_resp_t,
958 ) = read_control_and_response(current_task, &command)?;
959
960 if let Ok(semaphore) = self.get_semaphore(control.semaphore) {
961 for handle in &semaphore.handles {
962 #[allow(clippy::undocumented_unsafe_blocks)]
963 unsafe {
964 magma_semaphore_signal(*handle);
965 }
966 }
967 }
968 response.hdr.type_ =
969 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_SEMAPHORE_SIGNAL as u32;
970 current_task.write_object(UserRef::new(response_address), &response)
971 }
972 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_MAP_BUFFER => {
973 let (control, mut response): (
974 virtio_magma_connection_map_buffer_ctrl_t,
975 virtio_magma_connection_map_buffer_resp_t,
976 ) = read_control_and_response(current_task, &command)?;
977 let connection = self.get_connection(control.connection)?;
978 let buffer = self.get_buffer(control.buffer)?;
979
980 response.result_return = {
981 #[allow(clippy::undocumented_unsafe_blocks)]
982 unsafe {
983 magma_connection_map_buffer(
984 connection.handle,
985 control.hw_va,
986 buffer.handle,
987 control.offset,
988 control.length,
989 control.map_flags,
990 ) as u64
991 }
992 };
993
994 response.hdr.type_ =
995 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_MAP_BUFFER as u32;
996 current_task.write_object(UserRef::new(response_address), &response)
997 }
998 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_POLL => {
999 let (control, mut response): (virtio_magma_poll_ctrl_t, virtio_magma_poll_resp_t) =
1000 read_control_and_response(current_task, &command)?;
1001
1002 let num_items = control.count as usize / std::mem::size_of::<StarnixPollItem>();
1003 let items_ref = UserRef::<StarnixPollItem>::new(UserAddress::from(control.items));
1004 let starnix_items =
1008 current_task.read_objects_to_vec(items_ref, std::cmp::max(num_items, 1))?;
1009 let mut magma_items: Vec<magma_poll_item_t> =
1011 starnix_items.iter().map(|item| item.as_poll_item()).collect();
1012
1013 let mut status: i32 = MAGMA_STATUS_OK;
1015 let mut child_semaphore_items: Vec<magma_poll_item_t> = vec![];
1016
1017 for i in 0..magma_items.len() {
1018 magma_items[i].result = 0;
1019
1020 if magma_items[i].type_ == MAGMA_POLL_TYPE_SEMAPHORE
1021 && magma_items[i].condition == MAGMA_POLL_CONDITION_SIGNALED
1022 {
1023 match self.get_semaphore(starnix_items[i].semaphore_or_handle) {
1024 Ok(semaphore) => {
1025 magma_items[i].condition = 0; let handles_ref = &semaphore.handles;
1029 let child_count = handles_ref.len() as u32;
1030 magma_items[i].unused = child_count;
1031
1032 for handle in handles_ref {
1033 child_semaphore_items.push(
1034 StarnixPollItem {
1035 semaphore_or_handle: *handle,
1036 type_: MAGMA_POLL_TYPE_SEMAPHORE,
1037 condition: MAGMA_POLL_CONDITION_SIGNALED,
1038 result: 0,
1039 unused: i as u32,
1041 }
1042 .as_poll_item(),
1043 );
1044 }
1045 }
1046 Err(s) => status = s,
1047 }
1048 }
1049 }
1050
1051 if status == MAGMA_STATUS_OK {
1052 magma_items.append(&mut child_semaphore_items);
1053
1054 let abs_timeout_ns = if control.timeout_ns == u64::MAX {
1055 0
1056 } else {
1057 zx::MonotonicInstant::get().into_nanos() as u64 + control.timeout_ns
1058 };
1059
1060 'outer: while status == MAGMA_STATUS_OK {
1061 for i in (0..magma_items.len()).rev() {
1063 if i < num_items && magma_items[i].result > 0 {
1064 break 'outer;
1066 } else if magma_items[i].result > 0 {
1067 assert_eq!(magma_items[i].condition, MAGMA_POLL_CONDITION_SIGNALED);
1069 let parent_index = magma_items[i].unused as usize;
1070 assert_ne!(magma_items[parent_index].unused, 0);
1071 magma_items[parent_index].unused -= 1;
1072 if magma_items[parent_index].unused == 0 {
1073 magma_items[parent_index].result = magma_items[i].result;
1075 }
1076 magma_items[i].condition = 0;
1078 }
1079 }
1080
1081 let current_time_ns = zx::MonotonicInstant::get().into_nanos() as u64;
1082 let rel_timeout_ns = if abs_timeout_ns == 0 {
1083 u64::MAX
1084 } else if abs_timeout_ns > current_time_ns {
1085 abs_timeout_ns - current_time_ns
1086 } else {
1087 0
1088 };
1089
1090 let capped_rel_timeout_ns = std::cmp::min(rel_timeout_ns, 1_000_000_000);
1093
1094 status = {
1095 #[allow(clippy::undocumented_unsafe_blocks)]
1096 unsafe {
1097 magma_poll(
1098 &mut magma_items[0] as *mut magma_poll_item,
1099 magma_items.len() as u32,
1100 capped_rel_timeout_ns,
1101 )
1102 }
1103 };
1104 let current_time = zx::MonotonicInstant::get().into_nanos();
1105
1106 if status == MAGMA_STATUS_TIMED_OUT
1108 && (control.timeout_ns == u64::MAX
1109 || (current_time as u64) < abs_timeout_ns)
1110 {
1111 if control.timeout_ns != u64::MAX {
1112 let mut control = control;
1114 control.timeout_ns = abs_timeout_ns - (current_time as u64);
1115 let request_address = UserAddress::from(command.request_address);
1116 let _ = current_task
1117 .write_object(UserRef::new(request_address), &control);
1118 }
1119 return error!(EINTR);
1120 }
1121 }
1122 }
1123
1124 for i in num_items..magma_items.len() {
1126 assert_eq!(magma_items[i].type_, MAGMA_POLL_TYPE_SEMAPHORE);
1127 let parent_index = magma_items[i].unused as usize;
1128 magma_items[parent_index].condition = MAGMA_POLL_CONDITION_SIGNALED;
1129 magma_items[parent_index].unused = 0;
1130 }
1131
1132 magma_items.truncate(num_items);
1134
1135 let starnix_items: Vec<StarnixPollItem> =
1138 magma_items.iter().map(StarnixPollItem::new).collect();
1139 current_task.write_objects(items_ref, &starnix_items)?;
1140
1141 response.result_return = status as u64;
1142 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_POLL as u32;
1143 current_task.write_object(UserRef::new(response_address), &response)
1144 }
1145 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_EXECUTE_COMMAND => {
1146 let (control, mut response): (
1147 virtio_magma_connection_execute_command_ctrl_t,
1148 virtio_magma_connection_execute_command_resp_t,
1149 ) = read_control_and_response(current_task, &command)?;
1150 let connection = self.get_connection(control.connection)?;
1151
1152 let status = execute_command(current_task, control, &connection, |semaphore_id| {
1153 self.get_semaphore(semaphore_id)
1154 })?;
1155
1156 response.result_return = status as u64;
1157 response.hdr.type_ =
1158 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_EXECUTE_COMMAND as u32;
1159 current_task.write_object(UserRef::new(response_address), &response)
1160 }
1161 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_EXECUTE_INLINE_COMMANDS => {
1162 let (control, mut response): (
1163 virtio_magma_connection_execute_inline_commands_ctrl_t,
1164 virtio_magma_connection_execute_inline_commands_resp_t,
1165 ) = read_control_and_response(current_task, &command)?;
1166 let connection = self.get_connection(control.connection)?;
1167
1168 let status =
1169 execute_inline_commands(current_task, control, &connection, |semaphore_id| {
1170 self.get_semaphore(semaphore_id)
1171 })?;
1172
1173 response.hdr.type_ =
1174 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_EXECUTE_INLINE_COMMANDS
1175 as u32;
1176 response.result_return = status as u64;
1177
1178 current_task.write_object(UserRef::new(response_address), &response)
1179 }
1180 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_DEVICE_QUERY => {
1181 let (control, mut response): (
1182 virtio_magma_device_query_ctrl_t,
1183 virtio_magma_device_query_resp_t,
1184 ) = read_control_and_response(current_task, &command)?;
1185
1186 let device = self.get_device(control.device)?;
1187
1188 query(current_task, device.handle, control.id, &mut response)?;
1189
1190 response.hdr.type_ = virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_DEVICE_QUERY as u32;
1191 current_task.write_object(UserRef::new(response_address), &response)
1192 }
1193 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_UNMAP_BUFFER => {
1194 let (control, mut response): (
1195 virtio_magma_connection_unmap_buffer_ctrl_t,
1196 virtio_magma_connection_unmap_buffer_resp_t,
1197 ) = read_control_and_response(current_task, &command)?;
1198 let connection = self.get_connection(control.connection)?;
1199 let buffer = self.get_buffer(control.buffer)?;
1200
1201 #[allow(clippy::undocumented_unsafe_blocks)]
1202 unsafe {
1203 magma_connection_unmap_buffer(connection.handle, control.hw_va, buffer.handle)
1204 };
1205
1206 response.hdr.type_ =
1207 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_UNMAP_BUFFER as u32;
1208
1209 current_task.write_object(UserRef::new(response_address), &response)
1210 }
1211 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_CONNECTION_PERFORM_BUFFER_OP => {
1212 let (control, mut response): (
1213 virtio_magma_connection_perform_buffer_op_ctrl_t,
1214 virtio_magma_connection_perform_buffer_op_resp_t,
1215 ) = read_control_and_response(current_task, &command)?;
1216 let connection = self.get_connection(control.connection)?;
1217 let buffer = self.get_buffer(control.buffer)?;
1218
1219 response.result_return = {
1220 #[allow(clippy::undocumented_unsafe_blocks)]
1221 unsafe {
1222 magma_connection_perform_buffer_op(
1223 connection.handle,
1224 buffer.handle,
1225 control.options,
1226 control.start_offset,
1227 control.length,
1228 ) as u64
1229 }
1230 };
1231
1232 response.hdr.type_ =
1233 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_CONNECTION_PERFORM_BUFFER_OP as u32;
1234
1235 current_task.write_object(UserRef::new(response_address), &response)
1236 }
1237 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_GET_INFO => {
1238 let (control, mut response): (
1239 virtio_magma_buffer_get_info_ctrl_t,
1240 virtio_magma_buffer_get_info_resp_t,
1241 ) = read_control_and_response(current_task, &command)?;
1242 let buffer = self.get_buffer(control.buffer)?;
1243
1244 let mut buffer_info = magma_buffer_info_t { committed_byte_count: 0, size: 0 };
1245
1246 let status = {
1247 #[allow(clippy::undocumented_unsafe_blocks)]
1248 unsafe {
1249 magma_buffer_get_info(buffer.handle, &mut buffer_info)
1250 }
1251 };
1252
1253 if status == MAGMA_STATUS_OK {
1254 current_task.write_object(
1255 UserRef::<magma_buffer_info_t>::new(UserAddress::from(control.info_out)),
1256 &buffer_info,
1257 )?;
1258 }
1259
1260 response.hdr.type_ =
1261 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_GET_INFO as u32;
1262
1263 current_task.write_object(UserRef::new(response_address), &response)
1264 }
1265 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_SET_CACHE_POLICY => {
1266 let (control, mut response): (
1267 virtio_magma_buffer_set_cache_policy_ctrl_t,
1268 virtio_magma_buffer_set_cache_policy_resp_t,
1269 ) = read_control_and_response(current_task, &command)?;
1270 let buffer = self.get_buffer(control.buffer)?;
1271
1272 response.result_return = {
1273 #[allow(clippy::undocumented_unsafe_blocks)]
1274 unsafe {
1275 magma_buffer_set_cache_policy(
1276 buffer.handle,
1277 control.policy as magma_cache_policy_t,
1278 ) as u64
1279 }
1280 };
1281
1282 response.hdr.type_ =
1283 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_SET_CACHE_POLICY as u32;
1284
1285 current_task.write_object(UserRef::new(response_address), &response)
1286 }
1287 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_GET_CACHE_POLICY => {
1288 let (control, mut response): (
1289 virtio_magma_buffer_get_cache_policy_ctrl_t,
1290 virtio_magma_buffer_get_cache_policy_resp_t,
1291 ) = read_control_and_response(current_task, &command)?;
1292 let buffer = self.get_buffer(control.buffer)?;
1293
1294 let mut policy: magma_cache_policy_t = MAGMA_CACHE_POLICY_CACHED;
1295
1296 let status = {
1297 #[allow(clippy::undocumented_unsafe_blocks)]
1298 unsafe {
1299 magma_buffer_get_cache_policy(buffer.handle, &mut policy)
1300 }
1301 };
1302
1303 if status == MAGMA_STATUS_OK {
1304 response.cache_policy_out = policy as u64;
1305 }
1306 response.result_return = status as u64;
1307 response.hdr.type_ =
1308 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_GET_CACHE_POLICY as u32;
1309
1310 current_task.write_object(UserRef::new(response_address), &response)
1311 }
1312 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_CLEAN_CACHE => {
1313 let (control, mut response): (
1314 virtio_magma_buffer_clean_cache_ctrl_t,
1315 virtio_magma_buffer_clean_cache_resp_t,
1316 ) = read_control_and_response(current_task, &command)?;
1317 let buffer = self.get_buffer(control.buffer)?;
1318
1319 response.result_return = {
1320 #[allow(clippy::undocumented_unsafe_blocks)]
1321 unsafe {
1322 magma_buffer_clean_cache(
1323 buffer.handle,
1324 control.offset,
1325 control.size,
1326 control.operation as magma_cache_operation_t,
1327 ) as u64
1328 }
1329 };
1330
1331 response.hdr.type_ =
1332 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_CLEAN_CACHE as u32;
1333
1334 current_task.write_object(UserRef::new(response_address), &response)
1335 }
1336 virtio_magma_ctrl_type_VIRTIO_MAGMA_CMD_BUFFER_SET_NAME => {
1337 let (control, mut response): (
1338 virtio_magma_buffer_set_name_ctrl_t,
1339 virtio_magma_buffer_set_name_resp_t,
1340 ) = read_control_and_response(current_task, &command)?;
1341 let buffer = self.get_buffer(control.buffer)?;
1342
1343 let wrapper_ref = UserRef::<virtmagma_buffer_set_name_wrapper>::new(
1344 UserAddress::from(control.name),
1345 );
1346 let wrapper = current_task.read_object(wrapper_ref)?;
1347
1348 let name = current_task.read_buffer(&UserBuffer {
1349 address: UserAddress::from(wrapper.name_address),
1350 length: wrapper.name_size as usize, })?;
1352
1353 response.result_return = {
1354 #[allow(clippy::undocumented_unsafe_blocks)]
1355 unsafe {
1356 let name_ptr = &name[0] as *const u8 as *const std::os::raw::c_char;
1357 magma_buffer_set_name(buffer.handle, name_ptr) as u64
1358 }
1359 };
1360
1361 response.hdr.type_ =
1362 virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_BUFFER_SET_NAME as u32;
1363
1364 current_task.write_object(UserRef::new(response_address), &response)
1365 }
1366 t => {
1367 track_stub!(TODO("https://fxbug.dev/322874166"), "virtio magma ioctl", t);
1368 error!(ENOSYS)
1369 }
1370 }?;
1371
1372 Ok(SUCCESS)
1373 }
1374
1375 fn read(
1376 &self,
1377 _file: &FileObject,
1378 _current_task: &CurrentTask,
1379 offset: usize,
1380 _data: &mut dyn OutputBuffer,
1381 ) -> Result<usize, Errno> {
1382 debug_assert!(offset == 0);
1383 error!(EINVAL)
1384 }
1385
1386 fn write(
1387 &self,
1388 _file: &FileObject,
1389 _current_task: &CurrentTask,
1390 offset: usize,
1391 _data: &mut dyn InputBuffer,
1392 ) -> Result<usize, Errno> {
1393 debug_assert!(offset == 0);
1394 error!(EINVAL)
1395 }
1396}