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>, } #[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, } pub struct PwMemMap { pub _mem: Rc, pub range: Range, pub map: Mmapped, } pub struct PwMemTyped { mem: Rc, offset: usize, _phantom: PhantomData, } #[expect(dead_code)] pub struct PwMemSlice { mem: Rc, range: Range, } impl PwMemPool { pub fn map(&self, memid: u32, offset: u32, size: u32) -> Result, PwMemError> { match self.mems.get(&memid) { Some(m) => m.map(offset, size), _ => Err(PwMemError::MemidDoesNotExist(memid)), } } } impl PwMem { pub fn map(self: &Rc, offset: u32, size: u32) -> Result, 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(&self) -> &T { self.check::(0); unsafe { (self.map.ptr.cast::().add(self.range.start) as *const T).deref() } } #[expect(dead_code)] pub unsafe fn write(&self) -> &mut T { self.check::(0); unsafe { (self.map.ptr.cast::().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::().add(self.range.start) as _, self.range.len(), ) } } fn check(&self, offset: usize) { assert!(offset <= self.range.len()); assert!(size_of::() <= self.range.len() - offset); assert_eq!((align_of::() - 1) & (self.range.start + offset), 0); } pub fn typed(self: &Rc) -> Rc> { self.typed_at(0) } pub fn typed_at(self: &Rc, offset: usize) -> Rc> { self.check::(offset); Rc::new(PwMemTyped { mem: self.clone(), offset: self.range.start + offset, _phantom: Default::default(), }) } pub fn slice(self: &Rc, range: Range) -> Rc { 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 PwMemTyped { pub unsafe fn read(&self) -> &T { unsafe { (self.mem.map.ptr.cast::().add(self.offset) as *const T).deref() } } pub unsafe fn write(&self) -> &mut T { unsafe { (self.mem.map.ptr.cast::().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), }