1#![no_std]
4#![warn(missing_docs)]
5#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
6
7use core::{fmt, ptr, marker};
8
9pub struct RawPtr<'a, T> {
11 pub ptr: *mut T,
13 _lifetime: marker::PhantomData<&'a mut T>,
14}
15
16#[repr(transparent)]
17pub struct MemoryMap<T> {
19 ptr: *mut T
20}
21
22impl<T> MemoryMap<T> {
23 #[inline]
24 pub fn read(&self) -> T {
26 unsafe {
27 ptr::read_volatile(self.ptr)
28 }
29 }
30
31 #[inline]
32 pub fn write(&mut self, val: T) {
34 unsafe {
35 ptr::write_volatile(self.ptr, val)
36 }
37 }
38
39 #[inline]
40 pub fn read_and_write<F: FnOnce(T) -> T>(&mut self, cb: F) {
42 let new = cb(self.read());
43 self.write(new);
44 }
45
46 #[inline]
47 #[allow(clippy::needless_lifetimes)]
48 pub fn as_ref<'a>(&'a mut self) -> RawPtr<'a, T> {
52 RawPtr {
53 ptr: self.ptr,
54 _lifetime: marker::PhantomData
55 }
56 }
57
58 #[allow(unused)]
59 #[inline]
60 pub unsafe fn open_file_raw(offset: libc::off_t, fd: libc::c_int, prot: libc::c_int, flags: libc::c_int) -> Option<Self> {
69 #[cfg(unix)]
70 {
71 use core::mem;
72
73 let page_size = libc::sysconf(libc::_SC_PAGESIZE) as libc::off_t;
74 let offset_mask = (page_size - 1);
75 let page_mask = !0u32 as libc::off_t ^ offset_mask;
76
77 let ptr = libc::mmap(ptr::null_mut(), mem::size_of::<T>(), prot, flags, fd, offset & page_mask);
78
79 if ptr == libc::MAP_FAILED {
80 return None;
81 }
82
83 Some(Self {
84 ptr: unsafe {
85 (ptr as *mut u8).add(offset as usize & offset_mask as usize) as *mut _
86 }
87 })
88 }
89
90 #[cfg(not(unix))]
91 None
92 }
93
94 pub fn anonymous() -> Option<Self> {
96 #[cfg(unix)]
97 unsafe {
98 Self::open_file_raw(0, -1, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_ANON | libc::MAP_SHARED)
99 }
100
101 #[cfg(not(unix))]
102 None
103 }
104
105 #[allow(unused)]
106 pub unsafe fn dev_mem(offset: libc::off_t) -> Option<Self> {
114 #[cfg(unix)]
115 {
116 const DEV_MEM: [u8; 9] = *b"/dev/mem\0";
117 let fd = libc::open(DEV_MEM.as_ptr() as _, libc::O_RDWR | libc::O_SYNC);
118 if fd == -1 {
119 return None;
120 }
121
122 let result = Self::open_file_raw(offset, fd, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED);
123 libc::close(fd);
124 result
125 }
126
127 #[cfg(not(unix))]
128 None
129 }
130}
131
132impl<T> Drop for MemoryMap<T> {
133 #[inline]
134 fn drop(&mut self) {
135 if self.ptr.is_null() {
136 return;
137 }
138
139 #[cfg(unix)]
140 {
141 use core::mem;
142
143 let page_size = unsafe {
144 libc::sysconf(libc::_SC_PAGESIZE) as u32
145 };
146 let offset_mask = page_size - 1;
147 let page_mask: u32 = !0u32 ^ offset_mask;
148 let base_addr = (self.ptr as usize) & page_mask as usize;
149 unsafe {
150 libc::munmap(mem::transmute(base_addr), mem::size_of::<T>());
151 }
152 }
153 }
154}
155
156impl<T> fmt::Pointer for MemoryMap<T> {
157 #[inline(always)]
158 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
159 fmt::Pointer::fmt(&self.ptr, fmt)
160 }
161}
162
163impl<T> fmt::Debug for MemoryMap<T> {
164 #[inline(always)]
165 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
166 fmt::Debug::fmt(&self.ptr, fmt)
167 }
168}
169
170unsafe impl<T> Send for MemoryMap<T> {
171}
172
173unsafe impl<T> Sync for MemoryMap<T> {
174}