1use bitflags::bitflags;
8use zerocopy::{FromBytes, Immutable};
9use zx_sys::zx_paddr_t;
10
11use crate::{Iommu, NullableHandle, ObjectQuery, Pmt, Status, Topic, Vmo, ok, sys};
12
13#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
18#[repr(transparent)]
19pub struct Bti(NullableHandle);
20impl_handle_based!(Bti);
21
22static_assert_align!(
23 #[doc="Ergonomic equivalent of [sys::zx_info_bti_t]. Must be ABI-compatible with it."]
24 #[repr(C)]
25 #[derive(Debug, Copy, Clone, Eq, PartialEq, FromBytes, Immutable)]
26 <sys::zx_info_bti_t> pub struct BtiInfo {
27 pub minimum_contiguity: u64,
28 pub aspace_size: u64,
29 pub pmo_count: u64,
30 pub quarantine_count: u64,
31 }
32);
33
34impl Default for BtiInfo {
35 fn default() -> BtiInfo {
36 Self::from(sys::zx_info_bti_t::default())
37 }
38}
39
40impl From<sys::zx_info_bti_t> for BtiInfo {
41 fn from(info: sys::zx_info_bti_t) -> BtiInfo {
42 zerocopy::transmute!(info)
43 }
44}
45
46struct BtiInfoQuery;
47unsafe impl ObjectQuery for BtiInfoQuery {
48 const TOPIC: Topic = Topic::BTI;
49 type InfoTy = sys::zx_info_bti_t;
50}
51
52bitflags! {
53 #[repr(transparent)]
55 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
56 pub struct BtiOptions: u32 {
57 const PERM_READ = sys::ZX_BTI_PERM_READ;
58 const PERM_WRITE = sys::ZX_BTI_PERM_WRITE;
59 const PERM_EXECUTE = sys::ZX_BTI_PERM_EXECUTE;
60 const COMPRESS = sys::ZX_BTI_COMPRESS;
61 const CONTIGUOUS = sys::ZX_BTI_CONTIGUOUS;
62 }
63}
64
65impl Bti {
66 pub fn create(iommu: &Iommu, id: u64) -> Result<Bti, Status> {
70 let mut bti_handle = crate::sys::zx_handle_t::default();
71 let status = unsafe {
72 crate::sys::zx_bti_create(iommu.raw_handle(), 0, id, &mut bti_handle)
74 };
75 ok(status)?;
76 unsafe {
77 Ok(Bti::from(NullableHandle::from_raw(bti_handle)))
80 }
81 }
82
83 pub fn info(&self) -> Result<BtiInfo, Status> {
86 Ok(BtiInfo::from(self.0.get_info_single::<BtiInfoQuery>()?))
87 }
88
89 pub fn pin(
93 &self,
94 options: BtiOptions,
95 vmo: &Vmo,
96 offset: u64,
97 size: u64,
98 out_paddrs: &mut [zx_paddr_t],
99 ) -> Result<Pmt, Status> {
100 let mut pmt = crate::sys::zx_handle_t::default();
101 let status = unsafe {
102 crate::sys::zx_bti_pin(
105 self.raw_handle(),
106 options.bits(),
107 vmo.raw_handle(),
108 offset,
109 size,
110 out_paddrs.as_mut_ptr(),
111 out_paddrs.len(),
112 &mut pmt,
113 )
114 };
115 ok(status)?;
116 unsafe {
117 Ok(Pmt::from(NullableHandle::from_raw(pmt)))
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::{IommuDescStub, ObjectType, Resource, Vmo};
128 use fidl_fuchsia_kernel as fkernel;
129 use fuchsia_component::client::connect_channel_to_protocol;
130
131 #[test]
132 fn create_bti_wrong_handle() {
133 let vmo = Vmo::create(0).unwrap();
134 let wrong_handle = unsafe { Iommu::from(NullableHandle::from_raw(vmo.into_raw())) };
135
136 let status = Bti::create(&wrong_handle, 0);
137 assert_eq!(status, Err(Status::WRONG_TYPE));
138 }
139
140 fn create_iommu() -> Iommu {
141 use zx::{Channel, MonotonicInstant};
142 let (client_end, server_end) = Channel::create();
143 connect_channel_to_protocol::<fkernel::IommuResourceMarker>(server_end).unwrap();
144 let service = fkernel::IommuResourceSynchronousProxy::new(client_end);
145 let resource =
146 service.get(MonotonicInstant::INFINITE).expect("couldn't get iommu resource");
147 let resource = unsafe { Resource::from(NullableHandle::from_raw(resource.into_raw())) };
151 Iommu::create_stub(&resource, IommuDescStub::default()).unwrap()
152 }
153
154 #[test]
155 fn create_from_valid_iommu() {
156 let iommu = create_iommu();
157 let bti = Bti::create(&iommu, 0).unwrap();
158
159 let info = bti.as_handle_ref().basic_info().unwrap();
160 assert_eq!(info.object_type, ObjectType::BTI);
161 let bti_info = bti.info().unwrap();
162 assert!(bti_info.minimum_contiguity >= crate::system_get_page_size() as u64);
164 assert!(bti_info.minimum_contiguity % crate::system_get_page_size() as u64 == 0);
165 }
166
167 #[test]
168 fn create_and_pin_from_valid_iommu() {
169 let iommu = create_iommu();
170 let bti = Bti::create(&iommu, 0).unwrap();
171
172 let vmo = Vmo::create_contiguous(&bti, 4096, 0).unwrap();
173 let mut paddr = [0x1]; let pmt = bti.pin(BtiOptions::PERM_READ, &vmo, 0, 4096, &mut paddr[..]).unwrap();
176 assert_ne!(paddr, [0x1]);
177
178 let info = pmt.as_handle_ref().basic_info().unwrap();
179 assert_eq!(info.object_type, ObjectType::PMT);
180
181 unsafe {
182 pmt.unpin().unwrap();
183 }
184 }
185}