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