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