cyclone_v/memory/
dev_mem.rs

1#![cfg(feature = "std")]
2use crate::memory::MemoryMapper;
3use std::fmt;
4use std::ops::{Index, RangeBounds};
5use std::os::fd::AsRawFd;
6use std::os::unix::fs::OpenOptionsExt;
7
8/// A memory mapper that maps over the `/dev/mem` physical memory device.
9/// Only available on Linux with `std` feature enabled.
10pub struct DevMemMemoryMapper {
11    region: &'static [u8],
12    physical: (usize, usize),
13}
14
15impl fmt::Debug for DevMemMemoryMapper {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        f.debug_struct("DevMemMemoryMapper")
18            .field(
19                "region",
20                &format_args!("0x{:p}..0x{:p}", self.region.as_ptr(), unsafe {
21                    self.region.as_ptr().add(self.region.len())
22                }),
23            )
24            .field(
25                "physical",
26                &format_args!("{:#X} ({} bytes)", self.physical.0, self.physical.1),
27            )
28            .finish()
29    }
30}
31
32impl MemoryMapper for DevMemMemoryMapper {
33    fn create(address: usize, size: usize) -> Result<Self, &'static str> {
34        unsafe {
35            let file = std::fs::OpenOptions::new()
36                .read(true)
37                .write(true)
38                .custom_flags(libc::O_SYNC | libc::O_CLOEXEC)
39                .open("/dev/mem")
40                .map_err(|_| "Unable to open /dev/mem")?;
41            let fd = file.as_raw_fd();
42
43            let res = libc::mmap(
44                std::ptr::null_mut(),
45                size as libc::size_t,
46                libc::PROT_READ | libc::PROT_WRITE,
47                libc::MAP_SHARED,
48                fd,
49                address as libc::off_t,
50            );
51
52            if res == libc::MAP_FAILED {
53                return Err("Unable to map memory region");
54            }
55
56            Ok(Self {
57                region: core::slice::from_raw_parts_mut(res as *mut u8, size),
58                physical: (address, size),
59            })
60        }
61    }
62
63    fn len(&self) -> usize {
64        self.region.len()
65    }
66
67    fn as_ptr<T>(&self) -> *const T {
68        self.region.as_ptr() as *const T
69    }
70
71    fn as_mut_ptr<T>(&mut self) -> *mut T {
72        self.region.as_ptr() as *mut T
73    }
74}
75
76impl Drop for DevMemMemoryMapper {
77    fn drop(&mut self) {
78        unsafe {
79            // We unfortunately cannot care if this fails, as we are in a drop function.
80            let _ = libc::munmap(self.region.as_ptr() as *mut libc::c_void, self.region.len());
81        }
82    }
83}
84
85impl<R: RangeBounds<usize>> Index<R> for DevMemMemoryMapper {
86    type Output = [u8];
87
88    fn index(&self, index: R) -> &Self::Output {
89        self.as_range(index)
90    }
91}