use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr;
pub struct Mapping {
map_base: *mut libc::c_void,
len: libc::size_t,
slice_base: *mut u8,
slice_max_len: libc::size_t,
}
impl Mapping {
pub unsafe fn new(physical_addr: usize, len: usize) -> std::io::Result<Mapping> {
assert!(len > 0, "The mapping length must be greater than 0");
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as usize;
let frame_offset = physical_addr % page_size;
let frame_addr = physical_addr - frame_offset;
let devmem_file = OpenOptions::new()
.write(true)
.read(true)
.custom_flags(libc::O_RDWR | libc::O_SYNC)
.open("/dev/mem")?;
let devmem_fd = devmem_file.as_raw_fd();
let map_base = libc::mmap(
ptr::null_mut(),
len + frame_offset,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
devmem_fd,
frame_addr as libc::off_t,
);
let slice_base = (map_base as *mut u8).add(frame_offset);
Ok(Mapping {
map_base,
len: len + frame_offset,
slice_base,
slice_max_len: len,
})
}
pub fn copy_into_slice(&self, dst: &mut [u8]) {
assert!(self.slice_max_len >= dst.len());
let mapped_slice = self.as_slice(dst.len());
dst.copy_from_slice(mapped_slice);
}
pub fn copy_from_slice(&mut self, src: &[u8]) {
assert!(self.slice_max_len >= src.len());
let mapped_slice = self.as_mut_slice(src.len());
mapped_slice.copy_from_slice(src);
}
fn as_slice(&self, slice_len: usize) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.slice_base, slice_len) }
}
fn as_mut_slice(&mut self, slice_len: usize) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.slice_base, slice_len) }
}
}
impl Drop for Mapping {
fn drop(&mut self) {
let _ = unsafe { libc::munmap(self.map_base, self.len) };
}
}
pub unsafe fn read_into_slice(physical_addr: usize, dst: &mut [u8]) -> std::io::Result<()> {
let map = Mapping::new(physical_addr, dst.len())?;
map.copy_into_slice(dst);
Ok(())
}
pub unsafe fn write_from_slice(physical_addr: usize, src: &[u8]) -> std::io::Result<()> {
let mut map = Mapping::new(physical_addr, src.len())?;
map.copy_from_slice(src);
Ok(())
}