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