155 lines
4 KiB
Rust
155 lines
4 KiB
Rust
use {
|
|
crate::utils::{
|
|
copyhashmap::CopyHashMap,
|
|
mmap::{Mmapped, mmap},
|
|
oserror::OsError,
|
|
page_size::page_size,
|
|
ptr_ext::{MutPtrExt, PtrExt},
|
|
},
|
|
std::{marker::PhantomData, ops::Range, rc::Rc},
|
|
thiserror::Error,
|
|
uapi::{OwnedFd, Pod, c},
|
|
};
|
|
|
|
#[derive(Default)]
|
|
pub struct PwMemPool {
|
|
pub mems: CopyHashMap<u32, Rc<PwMem>>,
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
pub enum PwMemType {
|
|
MemFd,
|
|
DmaBuf,
|
|
}
|
|
|
|
pub struct PwMem {
|
|
pub _ty: PwMemType,
|
|
pub read: bool,
|
|
pub write: bool,
|
|
pub fd: Rc<OwnedFd>,
|
|
}
|
|
|
|
pub struct PwMemMap {
|
|
pub _mem: Rc<PwMem>,
|
|
pub range: Range<usize>,
|
|
pub map: Mmapped,
|
|
}
|
|
|
|
pub struct PwMemTyped<T> {
|
|
mem: Rc<PwMemMap>,
|
|
offset: usize,
|
|
_phantom: PhantomData<T>,
|
|
}
|
|
|
|
#[expect(dead_code)]
|
|
pub struct PwMemSlice {
|
|
mem: Rc<PwMemMap>,
|
|
range: Range<usize>,
|
|
}
|
|
|
|
impl PwMemPool {
|
|
pub fn map(&self, memid: u32, offset: u32, size: u32) -> Result<Rc<PwMemMap>, PwMemError> {
|
|
match self.mems.get(&memid) {
|
|
Some(m) => m.map(offset, size),
|
|
_ => Err(PwMemError::MemidDoesNotExist(memid)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PwMem {
|
|
pub fn map(self: &Rc<Self>, offset: u32, size: u32) -> Result<Rc<PwMemMap>, PwMemError> {
|
|
let mask = page_size() - 1;
|
|
let offset = offset as usize;
|
|
let size = size as usize;
|
|
let start = offset & !mask;
|
|
let dist = offset - start;
|
|
let len = (size + dist + mask) & !mask;
|
|
let range = dist..dist + size;
|
|
let mut prot = 0;
|
|
if self.read {
|
|
prot |= c::PROT_READ;
|
|
}
|
|
if self.write {
|
|
prot |= c::PROT_WRITE;
|
|
}
|
|
let map = match mmap(len as _, prot, c::MAP_SHARED, self.fd.raw(), start as _) {
|
|
Ok(m) => m,
|
|
Err(e) => return Err(PwMemError::MmapFailed(e)),
|
|
};
|
|
Ok(Rc::new(PwMemMap {
|
|
_mem: self.clone(),
|
|
range,
|
|
map,
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl PwMemMap {
|
|
#[expect(dead_code)]
|
|
pub unsafe fn read<T: Pod>(&self) -> &T {
|
|
self.check::<T>(0);
|
|
unsafe { (self.map.ptr.cast::<u8>().add(self.range.start) as *const T).deref() }
|
|
}
|
|
|
|
#[expect(dead_code)]
|
|
pub unsafe fn write<T: Pod>(&self) -> &mut T {
|
|
self.check::<T>(0);
|
|
unsafe { (self.map.ptr.cast::<u8>().add(self.range.start) as *mut T).deref_mut() }
|
|
}
|
|
|
|
#[expect(dead_code)]
|
|
pub unsafe fn bytes_mut(&self) -> &mut [u8] {
|
|
unsafe {
|
|
std::slice::from_raw_parts_mut(
|
|
self.map.ptr.cast::<u8>().add(self.range.start) as _,
|
|
self.range.len(),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn check<T>(&self, offset: usize) {
|
|
assert!(offset <= self.range.len());
|
|
assert!(size_of::<T>() <= self.range.len() - offset);
|
|
assert_eq!((align_of::<T>() - 1) & (self.range.start + offset), 0);
|
|
}
|
|
|
|
pub fn typed<T: Pod>(self: &Rc<Self>) -> Rc<PwMemTyped<T>> {
|
|
self.typed_at(0)
|
|
}
|
|
|
|
pub fn typed_at<T: Pod>(self: &Rc<Self>, offset: usize) -> Rc<PwMemTyped<T>> {
|
|
self.check::<T>(offset);
|
|
Rc::new(PwMemTyped {
|
|
mem: self.clone(),
|
|
offset: self.range.start + offset,
|
|
_phantom: Default::default(),
|
|
})
|
|
}
|
|
|
|
pub fn slice(self: &Rc<Self>, range: Range<usize>) -> Rc<PwMemSlice> {
|
|
assert!(range.start <= self.range.len());
|
|
assert!(range.len() <= self.range.len() - range.start);
|
|
Rc::new(PwMemSlice {
|
|
mem: self.clone(),
|
|
range: self.range.start + range.start..self.range.start + range.end,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<T: Pod> PwMemTyped<T> {
|
|
pub unsafe fn read(&self) -> &T {
|
|
unsafe { (self.mem.map.ptr.cast::<u8>().add(self.offset) as *const T).deref() }
|
|
}
|
|
|
|
pub unsafe fn write(&self) -> &mut T {
|
|
unsafe { (self.mem.map.ptr.cast::<u8>().add(self.offset) as *mut T).deref_mut() }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum PwMemError {
|
|
#[error("mmap failed")]
|
|
MmapFailed(#[source] OsError),
|
|
#[error("memid {0} does not exist")]
|
|
MemidDoesNotExist(u32),
|
|
}
|