1 use core::num::NonZeroUsize;
2 use std::{
3     cmp::{max, min},
4     ops::Deref,
5     ptr::NonNull,
6     slice,
7 };
8 use std::{ops::DerefMut, os::unix::io::AsFd};
9 
10 use log::error;
11 use nix::{errno::Errno, libc::off_t, sys::mman};
12 use thiserror::Error;
13 
14 pub struct PlaneMapping {
15     // A mapping remains valid until we munmap it, that is, until the
16     // PlaneMapping object is deleted. Hence the static lifetime.
17     pub data: &'static mut [u8],
18 
19     start: usize,
20     end: usize,
21 }
22 
23 impl PlaneMapping {
size(&self) -> usize24     pub fn size(&self) -> usize {
25         self.end - self.start
26     }
27 
restrict(mut self, start: usize, end: usize) -> Self28     pub fn restrict(mut self, start: usize, end: usize) -> Self {
29         self.start = max(self.start, start);
30         self.end = min(self.end, end);
31 
32         self
33     }
34 }
35 
36 impl AsRef<[u8]> for PlaneMapping {
as_ref(&self) -> &[u8]37     fn as_ref(&self) -> &[u8] {
38         &self.data[self.start..self.end]
39     }
40 }
41 
42 impl AsMut<[u8]> for PlaneMapping {
as_mut(&mut self) -> &mut [u8]43     fn as_mut(&mut self) -> &mut [u8] {
44         &mut self.data[self.start..self.end]
45     }
46 }
47 
48 impl Deref for PlaneMapping {
49     type Target = [u8];
50 
deref(&self) -> &Self::Target51     fn deref(&self) -> &Self::Target {
52         &self.data[self.start..self.end]
53     }
54 }
55 
56 impl DerefMut for PlaneMapping {
deref_mut(&mut self) -> &mut Self::Target57     fn deref_mut(&mut self) -> &mut Self::Target {
58         &mut self.data[self.start..self.end]
59     }
60 }
61 
62 impl Drop for PlaneMapping {
drop(&mut self)63     fn drop(&mut self) {
64         // Safe because the pointer and length were constructed in mmap() and
65         // are always valid.
66         unsafe {
67             mman::munmap(
68                 NonNull::new_unchecked(self.data.as_mut_ptr().cast()),
69                 self.data.len(),
70             )
71         }
72         .unwrap_or_else(|e| {
73             error!("Error while unmapping plane: {}", e);
74         });
75     }
76 }
77 
78 #[derive(Debug, Error)]
79 pub enum MmapError {
80     #[error("provided length was 0")]
81     ZeroLength,
82     #[error("ioctl error: {0}")]
83     IoctlError(#[from] Errno),
84 }
85 
86 impl From<MmapError> for Errno {
from(err: MmapError) -> Self87     fn from(err: MmapError) -> Self {
88         match err {
89             MmapError::ZeroLength => Errno::EINVAL,
90             MmapError::IoctlError(e) => e,
91         }
92     }
93 }
94 
95 // TODO should be unsafe because the mapping can be used after a buffer is queued?
96 // Or not, since this cannot cause a crash...
mmap(fd: &impl AsFd, mem_offset: u32, length: u32) -> Result<PlaneMapping, MmapError>97 pub fn mmap(fd: &impl AsFd, mem_offset: u32, length: u32) -> Result<PlaneMapping, MmapError> {
98     let non_zero_length = NonZeroUsize::new(length as usize).ok_or(MmapError::ZeroLength)?;
99     let data = unsafe {
100         mman::mmap(
101             None,
102             non_zero_length,
103             mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE,
104             mman::MapFlags::MAP_SHARED,
105             fd,
106             mem_offset as off_t,
107         )
108     }?;
109 
110     Ok(PlaneMapping {
111         // Safe because we know the pointer is valid and has enough data mapped
112         // to cover the length.
113         data: unsafe { slice::from_raw_parts_mut(data.as_ptr().cast(), length as usize) },
114         start: 0,
115         end: length as usize,
116     })
117 }
118