Skip to main content

xengnt/
lib.rs

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}