1pub mod error;
2pub mod sys;
3
4use error::{Error, Result};
5use nix::errno::Errno;
6use std::{
7 fs::{File, OpenOptions},
8 marker::PhantomData,
9 os::{fd::AsRawFd, raw::c_void},
10 sync::Arc,
11 thread::sleep,
12 time::Duration,
13};
14use sys::{
15 AllocGref, DeallocGref, GetOffsetForVaddr, GrantRef, MapGrantRef, SetMaxGrants, UnmapGrantRef,
16 UnmapNotify, UNMAP_NOTIFY_CLEAR_BYTE, UNMAP_NOTIFY_SEND_EVENT,
17};
18
19use libc::{mmap, munmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
20
21#[derive(Clone)]
22pub struct GrantDevice {
23 handle: Arc<File>,
24}
25
26impl GrantDevice {
27 pub fn open() -> Result<GrantDevice> {
28 let handle = OpenOptions::new()
29 .read(true)
30 .write(true)
31 .open("/dev/xen/gntdev")?;
32 Ok(GrantDevice {
33 handle: Arc::new(handle),
34 })
35 }
36
37 pub fn map_grant_ref(&self, refs: Vec<GrantRef>) -> Result<(u64, Vec<GrantRef>)> {
38 let mut request = MapGrantRef::write(refs.as_slice());
39 unsafe {
40 sys::map_grant_ref(self.handle.as_raw_fd(), request.as_mut_ptr())?;
41 };
42 let result =
43 MapGrantRef::read(refs.len() as u32, request).ok_or(Error::StructureReadFailed)?;
44 Ok((result.index, result.refs))
45 }
46
47 pub fn unmap_grant_ref(&self, index: u64, count: u32) -> Result<()> {
48 let mut request = UnmapGrantRef {
49 index,
50 count,
51 pad: 0,
52 };
53 unsafe {
54 sys::unmap_grant_ref(self.handle.as_raw_fd(), &mut request)?;
55 }
56 Ok(())
57 }
58
59 pub fn get_offset_for_vaddr(&self, vaddr: u64) -> Result<(u64, u32)> {
60 let mut request = GetOffsetForVaddr {
61 vaddr,
62 pad: 0,
63 offset: 0,
64 count: 0,
65 };
66 unsafe {
67 sys::get_offset_for_vaddr(self.handle.as_raw_fd(), &mut request)?;
68 }
69 Ok((request.offset, request.count))
70 }
71
72 pub fn set_max_grants(&self, count: u32) -> Result<()> {
73 let mut request = SetMaxGrants { count };
74 unsafe {
75 sys::set_max_grants(self.handle.as_raw_fd(), &mut request)?;
76 }
77 Ok(())
78 }
79
80 pub fn unmap_notify(&self, index: u64, send: bool, port: u32) -> Result<()> {
81 let mut request = UnmapNotify {
82 index,
83 action: if send {
84 UNMAP_NOTIFY_SEND_EVENT
85 } else {
86 UNMAP_NOTIFY_CLEAR_BYTE
87 },
88 port,
89 };
90 unsafe {
91 sys::unmap_notify(self.handle.as_raw_fd(), &mut request)?;
92 }
93 Ok(())
94 }
95}
96
97#[derive(Clone)]
98pub struct GrantAlloc {
99 handle: Arc<File>,
100}
101
102impl GrantAlloc {
103 pub fn open() -> Result<GrantAlloc> {
104 let handle = OpenOptions::new()
105 .read(true)
106 .write(true)
107 .open("/dev/xen/gntalloc")?;
108 Ok(GrantAlloc {
109 handle: Arc::new(handle),
110 })
111 }
112
113 pub fn alloc_gref(&self, domid: u16, flags: u16, count: u32) -> Result<(u64, Vec<u32>)> {
114 let mut request = AllocGref::write(AllocGref {
115 domid,
116 flags,
117 count,
118 });
119 unsafe {
120 sys::alloc_gref(self.handle.as_raw_fd(), request.as_mut_ptr())?;
121 };
122 AllocGref::read(count, request).ok_or(Error::StructureReadFailed)
123 }
124
125 pub fn dealloc_gref(&self, index: u64, count: u32) -> Result<()> {
126 let mut request = DeallocGref { index, count };
127 unsafe {
128 sys::dealloc_gref(self.handle.as_raw_fd(), &mut request)?;
129 };
130 Ok(())
131 }
132
133 pub fn unmap_notify(&self, index: u64, send: bool, port: u32) -> Result<()> {
134 let mut request = UnmapNotify {
135 index,
136 action: if send {
137 UNMAP_NOTIFY_SEND_EVENT
138 } else {
139 UNMAP_NOTIFY_CLEAR_BYTE
140 },
141 port,
142 };
143 unsafe {
144 sys::unmap_notify(self.handle.as_raw_fd(), &mut request)?;
145 }
146 Ok(())
147 }
148}
149
150#[derive(Clone)]
151pub struct GrantTab {
152 device: GrantDevice,
153}
154
155const PAGE_SIZE: usize = 4096;
156
157#[allow(clippy::len_without_is_empty)]
158pub struct MappedMemory<'a> {
159 gnttab: GrantTab,
160 length: usize,
161 addr: u64,
162 _ptr: PhantomData<&'a c_void>,
163}
164
165unsafe impl Send for MappedMemory<'_> {}
166
167impl MappedMemory<'_> {
168 pub fn len(&self) -> usize {
169 self.length
170 }
171
172 pub fn ptr(&self) -> *mut c_void {
173 self.addr as *mut c_void
174 }
175}
176
177impl Drop for MappedMemory<'_> {
178 fn drop(&mut self) {
179 let _ = self.gnttab.unmap(self);
180 }
181}
182
183impl GrantTab {
184 pub fn open() -> Result<GrantTab> {
185 Ok(GrantTab {
186 device: GrantDevice::open()?,
187 })
188 }
189
190 pub fn map_grant_refs<'a>(
191 &self,
192 refs: Vec<GrantRef>,
193 read: bool,
194 write: bool,
195 ) -> Result<MappedMemory<'a>> {
196 let (index, refs) = self.device.map_grant_ref(refs)?;
197 unsafe {
198 let mut flags: i32 = 0;
199 if read {
200 flags |= PROT_READ;
201 }
202
203 if write {
204 flags |= PROT_WRITE;
205 }
206
207 let addr = loop {
208 let addr = mmap(
209 std::ptr::null_mut(),
210 PAGE_SIZE * refs.len(),
211 flags,
212 MAP_SHARED,
213 self.device.handle.as_raw_fd(),
214 index as i64,
215 );
216 let errno = Errno::last();
217 if addr == MAP_FAILED {
218 if errno == Errno::EAGAIN {
219 sleep(Duration::from_micros(1000));
220 continue;
221 }
222 return Err(Error::MmapFailed(errno));
223 }
224 break addr;
225 };
226
227 Ok(MappedMemory {
228 gnttab: self.clone(),
229 addr: addr as u64,
230 length: PAGE_SIZE * refs.len(),
231 _ptr: PhantomData,
232 })
233 }
234 }
235
236 fn unmap(&self, memory: &MappedMemory<'_>) -> Result<()> {
237 let (offset, count) = self.device.get_offset_for_vaddr(memory.addr)?;
238 let _ = unsafe { munmap(memory.addr as *mut c_void, memory.length) };
239 self.device.unmap_grant_ref(offset, count)?;
240 Ok(())
241 }
242}