// Copyright 2022 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.

//! Type-safe bindings for Zircon bti objects.

use crate::ok;
use crate::{AsHandleRef, Handle, HandleBased, HandleRef, Iommu, Status};
use fuchsia_zircon_sys as sys;

/// An object representing a Zircon Bus Transaction Initiator object.
/// See [BTI Documentation](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/bus_transaction_initiator) for details.
///
/// As essentially a subtype of `Handle`, it can be freely interconverted.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Bti(Handle);
impl_handle_based!(Bti);

impl Bti {
    // Create a Bus Transaction Initiator object.
    // Wraps the
    // [`zx_bti_create`](https://fuchsia.dev/fuchsia-src/reference/syscalls/bti_create) system call to create a bti.
    pub fn create(iommu: &Iommu, id: u64) -> Result<Bti, Status> {
        let mut bti_handle = sys::zx_handle_t::default();
        let status = unsafe {
            // SAFETY: regular system call with no unsafe parameters.
            sys::zx_bti_create(iommu.raw_handle(), 0, id, &mut bti_handle)
        };
        ok(status)?;
        unsafe {
            // SAFETY: The syscall docs claim that upon success, bti_handle will be a valid
            // handle to bti object.
            Ok(Bti::from(Handle::from_raw(bti_handle)))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{IommuDescDummy, ObjectType, Resource, Vmo};
    use fidl_fuchsia_boot as fboot;
    use fuchsia_component::client::connect_channel_to_protocol;

    #[test]
    fn create_bti_invalid_handle() {
        let status = Bti::create(&Iommu::from(Handle::invalid()), 0);
        assert_eq!(status, Err(Status::BAD_HANDLE));
    }

    #[test]
    fn create_bti_wrong_handle() {
        let vmo = Vmo::create(0).unwrap();
        let wrong_handle = unsafe { Iommu::from(Handle::from_raw(vmo.into_raw())) };

        let status = Bti::create(&wrong_handle, 0);
        assert_eq!(status, Err(Status::WRONG_TYPE));
    }

    fn create_iommu() -> Iommu {
        use fuchsia_zircon::{Channel, HandleBased, Time};
        let (client_end, server_end) = Channel::create();
        connect_channel_to_protocol::<fboot::RootResourceMarker>(server_end).unwrap();
        let service = fboot::RootResourceSynchronousProxy::new(client_end);
        let resource = service.get(Time::INFINITE).expect("couldn't get root resource");
        // This test and fuchsia-zircon are different crates, so we need
        // to use from_raw to convert between the fuchsia_zircon handle and this test handle.
        // See https://fxbug.dev/42173139 for details.
        let resource = unsafe { Resource::from(Handle::from_raw(resource.into_raw())) };
        Iommu::create_dummy(&resource, IommuDescDummy::default()).unwrap()
    }

    #[test]
    fn create_from_valid_iommu() {
        let iommu = create_iommu();
        let bti = Bti::create(&iommu, 0).unwrap();

        let info = bti.as_handle_ref().basic_info().unwrap();
        assert_eq!(info.object_type, ObjectType::BTI);
    }
}
