1use crate::{ok, sys, AsHandleRef, Handle, HandleBased, HandleRef, Status};
8use bitflags::bitflags;
9
10#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
16#[repr(transparent)]
17pub struct Iob(Handle);
18impl_handle_based!(Iob);
19
20#[derive(Default)]
21pub struct IobOptions;
22
23#[derive(Clone, Copy)]
24pub enum IobRegionType {
25 Private { size: u64, options: IobRegionPrivateOptions },
26}
27
28impl IobRegionType {
29 fn to_raw(&self) -> (sys::zx_iob_region_type_t, sys::zx_iob_region_extension_t) {
30 match self {
31 IobRegionType::Private { .. } => (
32 sys::ZX_IOB_REGION_TYPE_PRIVATE,
33 sys::zx_iob_region_extension_t { private_region: Default::default() },
34 ),
35 }
36 }
37}
38
39#[derive(Clone, Copy, Default)]
40pub struct IobRegionPrivateOptions;
41
42pub struct IobRegion {
43 pub region_type: IobRegionType,
44 pub access: IobAccess,
45 pub discipline: IobDiscipline,
46}
47
48bitflags! {
49 #[repr(transparent)]
50 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51 pub struct IobAccess: u32 {
52 const EP0_CAN_MAP_READ = sys::ZX_IOB_ACCESS_EP0_CAN_MAP_READ;
53 const EP0_CAN_MAP_WRITE = sys::ZX_IOB_ACCESS_EP0_CAN_MAP_WRITE;
54 const EP0_CAN_MEDIATED_READ = sys::ZX_IOB_ACCESS_EP0_CAN_MEDIATED_READ;
55 const EP0_CAN_MEDIATED_WRITE = sys::ZX_IOB_ACCESS_EP0_CAN_MEDIATED_WRITE;
56 const EP1_CAN_MAP_READ = sys::ZX_IOB_ACCESS_EP1_CAN_MAP_READ;
57 const EP1_CAN_MAP_WRITE = sys::ZX_IOB_ACCESS_EP1_CAN_MAP_WRITE;
58 const EP1_CAN_MEDIATED_READ = sys::ZX_IOB_ACCESS_EP1_CAN_MEDIATED_READ;
59 const EP1_CAN_MEDIATED_WRITE = sys::ZX_IOB_ACCESS_EP1_CAN_MEDIATED_WRITE;
60 }
61}
62
63#[derive(Clone, Copy)]
64pub enum IobDiscipline {
65 None,
66}
67
68impl IobDiscipline {
69 fn to_raw(&self) -> sys::zx_iob_discipline_t {
70 match self {
71 IobDiscipline::None => sys::zx_iob_discipline_t {
72 r#type: sys::ZX_IOB_DISCIPLINE_TYPE_NONE,
73 ..Default::default()
74 },
75 }
76 }
77}
78
79impl Iob {
80 pub fn create(_options: IobOptions, regions: &[IobRegion]) -> Result<(Iob, Iob), Status> {
84 let raw_regions: Vec<_> = regions
85 .iter()
86 .map(|r| {
87 let (r#type, extension) = r.region_type.to_raw();
88 sys::zx_iob_region_t {
89 r#type,
90 access: r.access.bits(),
91 size: match &r.region_type {
92 IobRegionType::Private { size, .. } => *size,
93 },
94 discipline: r.discipline.to_raw(),
95 extension,
96 }
97 })
98 .collect();
99 let mut handle1 = 0;
100 let mut handle2 = 0;
101 let status = unsafe {
102 sys::zx_iob_create(
103 0,
104 raw_regions.as_ptr() as *const u8,
105 raw_regions.len(),
106 &mut handle1,
107 &mut handle2,
108 )
109 };
110 ok(status)?;
111 unsafe { Ok((Iob::from(Handle::from_raw(handle1)), Iob::from(Handle::from_raw(handle2)))) }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::{Iob, IobAccess, IobDiscipline, IobRegion, IobRegionType};
118 use crate::{Unowned, Vmar, VmarFlags};
119 use std::sync::atomic::{AtomicU64, Ordering};
120
121 #[test]
122 fn test_create_iob() {
123 let region_size = zx::system_get_page_size() as usize * 8;
124 let (ep0, ep1) = Iob::create(
125 Default::default(),
126 &[IobRegion {
127 region_type: IobRegionType::Private {
128 size: region_size as u64,
129 options: Default::default(),
130 },
131 access: IobAccess::EP0_CAN_MAP_READ
132 | IobAccess::EP0_CAN_MAP_WRITE
133 | IobAccess::EP1_CAN_MAP_READ,
134 discipline: IobDiscipline::None,
135 }],
136 )
137 .expect("create failed");
138
139 let root_vmar =
142 unsafe { Unowned::<Vmar>::from_raw_handle(fuchsia_runtime::zx_vmar_root_self()) };
143
144 let write_addr = root_vmar
145 .map_iob(VmarFlags::PERM_READ | VmarFlags::PERM_WRITE, 0, &ep0, 0, 0, region_size)
146 .expect("map_iob failed");
147 let read_addr = root_vmar
148 .map_iob(VmarFlags::PERM_READ, 0, &ep1, 0, 0, region_size)
149 .expect("map_iob failed");
150
151 const VALUE: u64 = 0x123456789abcdef;
152
153 unsafe { &*(write_addr as *const AtomicU64) }.store(VALUE, Ordering::Relaxed);
154
155 assert_eq!(unsafe { &*(read_addr as *const AtomicU64) }.load(Ordering::Relaxed), VALUE);
156
157 unsafe {
158 root_vmar.unmap(write_addr, region_size).expect("unmap failed");
159 root_vmar.unmap(read_addr, region_size).expect("unmap failed");
160 }
161 }
162}