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