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