| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #![allow(non_upper_case_globals)] |
| |
| use magma::{ |
| MAGMA_POLL_TYPE_SEMAPHORE, magma_handle_t, magma_poll_item__bindgen_ty_1, magma_poll_item_t, |
| magma_semaphore_t, virtio_magma_ctrl_hdr_t, virtio_magma_ctrl_type, |
| virtmagma_ioctl_args_magma_command, |
| }; |
| use starnix_core::mm::MemoryAccessorExt; |
| use starnix_core::task::CurrentTask; |
| use starnix_uapi::errors::Errno; |
| use starnix_uapi::user_address::{UserAddress, UserRef}; |
| use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; |
| |
| /// Reads a magma command and its type from user space. |
| /// |
| /// # Parameters |
| /// - `current_task`: The task to which the command memory belongs. |
| /// - `command_address`: The address of the `virtmagma_ioctl_args_magma_command`. |
| pub fn read_magma_command_and_type( |
| current_task: &CurrentTask, |
| command_address: UserAddress, |
| ) -> Result<(virtmagma_ioctl_args_magma_command, virtio_magma_ctrl_type), Errno> { |
| let command: virtmagma_ioctl_args_magma_command = |
| current_task.read_object(UserRef::new(command_address))?; |
| |
| let request_address = UserAddress::from(command.request_address); |
| let header: virtio_magma_ctrl_hdr_t = |
| current_task.read_object(UserRef::new(request_address))?; |
| |
| Ok((command, header.type_ as u16)) |
| } |
| |
| /// Reads the control and response structs from the given magma command struct. |
| /// |
| /// # Parameters |
| /// - `current_task`: The task to which the memory belongs. |
| /// - `command`: The command struct that contains the pointers to the control and response structs. |
| pub fn read_control_and_response<C: Default + IntoBytes + FromBytes, R: Default>( |
| current_task: &CurrentTask, |
| command: &virtmagma_ioctl_args_magma_command, |
| ) -> Result<(C, R), Errno> { |
| let request_address = UserAddress::from(command.request_address); |
| let ctrl = current_task.read_object(UserRef::new(request_address))?; |
| |
| Ok((ctrl, R::default())) |
| } |
| |
| #[repr(C)] |
| #[derive(IntoBytes, KnownLayout, FromBytes, Immutable, Copy, Clone, Default, Debug)] |
| /// `StarnixPollItem` exists to be able to `IntoBytes` and `FromBytes` the union that exists in |
| /// `magma_poll_item_t`. |
| pub struct StarnixPollItem { |
| pub semaphore_or_handle: u64, |
| pub type_: u32, |
| pub condition: u32, |
| pub result: u32, |
| pub unused: u32, |
| } |
| |
| impl StarnixPollItem { |
| pub fn new(poll_item: &magma_poll_item_t) -> StarnixPollItem { |
| #[allow( |
| clippy::undocumented_unsafe_blocks, |
| reason = "Force documented unsafe blocks in Starnix" |
| )] |
| let semaphore_or_handle = unsafe { |
| if poll_item.type_ == MAGMA_POLL_TYPE_SEMAPHORE { |
| poll_item.__bindgen_anon_1.semaphore |
| } else { |
| poll_item.__bindgen_anon_1.handle as u64 |
| } |
| }; |
| StarnixPollItem { |
| semaphore_or_handle, |
| type_: poll_item.type_, |
| condition: poll_item.condition, |
| result: poll_item.result, |
| unused: 0, |
| } |
| } |
| |
| pub fn as_poll_item(&self) -> magma_poll_item_t { |
| let handle = if self.type_ == MAGMA_POLL_TYPE_SEMAPHORE { |
| magma_poll_item__bindgen_ty_1 { |
| semaphore: self.semaphore_or_handle as magma_semaphore_t, |
| } |
| } else { |
| magma_poll_item__bindgen_ty_1 { handle: self.semaphore_or_handle as magma_handle_t } |
| }; |
| magma_poll_item_t { |
| __bindgen_anon_1: handle, |
| type_: self.type_, |
| condition: self.condition, |
| result: self.result, |
| unused: self.unused, |
| } |
| } |
| } |