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