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