pub mod options;
pub mod segment;
use core::mem::ManuallyDrop;
pub use segment::Segment;
use super::{
page::{
meta::{FrameMeta, MetaSlot, PageMeta, PageUsage},
DynPage, Page,
},
Infallible,
};
use crate::{
mm::{
io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter},
paddr_to_vaddr, HasPaddr, Paddr, PAGE_SIZE,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct Frame {
page: Page<FrameMeta>,
}
impl Frame {
pub fn start_paddr(&self) -> Paddr {
self.page.paddr()
}
pub fn end_paddr(&self) -> Paddr {
self.start_paddr() + PAGE_SIZE
}
pub const fn size(&self) -> usize {
self.page.size()
}
pub fn as_ptr(&self) -> *const u8 {
paddr_to_vaddr(self.start_paddr()) as *const u8
}
pub fn as_mut_ptr(&self) -> *mut u8 {
paddr_to_vaddr(self.start_paddr()) as *mut u8
}
pub fn copy_from(&self, src: &Frame) {
if self.paddr() == src.paddr() {
return;
}
unsafe {
core::ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.size());
}
}
pub fn reference_count(&self) -> u32 {
self.page.reference_count()
}
}
impl From<Page<FrameMeta>> for Frame {
fn from(page: Page<FrameMeta>) -> Self {
Self { page }
}
}
impl TryFrom<DynPage> for Frame {
type Error = DynPage;
fn try_from(page: DynPage) -> core::result::Result<Self, Self::Error> {
page.try_into().map(|p: Page<FrameMeta>| p.into())
}
}
impl From<Frame> for Page<FrameMeta> {
fn from(frame: Frame) -> Self {
frame.page
}
}
impl HasPaddr for Frame {
fn paddr(&self) -> Paddr {
self.start_paddr()
}
}
impl<'a> Frame {
pub fn reader(&'a self) -> VmReader<'a, Infallible> {
unsafe { VmReader::from_kernel_space(self.as_ptr(), self.size()) }
}
pub fn writer(&'a self) -> VmWriter<'a, Infallible> {
unsafe { VmWriter::from_kernel_space(self.as_mut_ptr(), self.size()) }
}
}
impl VmIo for Frame {
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
let read_len = writer.avail().min(self.size().saturating_sub(offset));
let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?;
if max_offset > self.size() {
return Err(Error::InvalidArgs);
}
let len = self
.reader()
.skip(offset)
.read_fallible(writer)
.map_err(|(e, _)| e)?;
debug_assert!(len == read_len);
Ok(())
}
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
let write_len = reader.remain().min(self.size().saturating_sub(offset));
let max_offset = offset.checked_add(write_len).ok_or(Error::Overflow)?;
if max_offset > self.size() {
return Err(Error::InvalidArgs);
}
let len = self
.writer()
.skip(offset)
.write_fallible(reader)
.map_err(|(e, _)| e)?;
debug_assert!(len == write_len);
Ok(())
}
}
impl VmIo for alloc::vec::Vec<Frame> {
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
let max_offset = offset.checked_add(writer.avail()).ok_or(Error::Overflow)?;
if max_offset > self.len() * PAGE_SIZE {
return Err(Error::InvalidArgs);
}
let num_skip_pages = offset / PAGE_SIZE;
let mut start = offset % PAGE_SIZE;
for frame in self.iter().skip(num_skip_pages) {
let read_len = frame
.reader()
.skip(start)
.read_fallible(writer)
.map_err(|(e, _)| e)?;
if read_len == 0 {
break;
}
start = 0;
}
Ok(())
}
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?;
if max_offset > self.len() * PAGE_SIZE {
return Err(Error::InvalidArgs);
}
let num_skip_pages = offset / PAGE_SIZE;
let mut start = offset % PAGE_SIZE;
for frame in self.iter().skip(num_skip_pages) {
let write_len = frame
.writer()
.skip(start)
.write_fallible(reader)
.map_err(|(e, _)| e)?;
if write_len == 0 {
break;
}
start = 0;
}
Ok(())
}
}
impl PageMeta for FrameMeta {
const USAGE: PageUsage = PageUsage::Frame;
fn on_drop(_page: &mut Page<Self>) {
}
}
use core::{marker::PhantomData, ops::Deref};
pub struct FrameRef<'a> {
inner: ManuallyDrop<Frame>,
_marker: PhantomData<&'a Frame>,
}
impl<'a> Deref for FrameRef<'a> {
type Target = Frame;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
unsafe impl xarray::ItemEntry for Frame {
type Ref<'a> = FrameRef<'a> where Self: 'a;
fn into_raw(self) -> *const () {
let ptr = self.page.ptr;
core::mem::forget(self);
ptr as *const ()
}
unsafe fn from_raw(raw: *const ()) -> Self {
Self {
page: Page::<FrameMeta> {
ptr: raw as *mut MetaSlot,
_marker: PhantomData,
},
}
}
unsafe fn raw_as_ref<'a>(raw: *const ()) -> Self::Ref<'a> {
Self::Ref {
inner: ManuallyDrop::new(Frame::from_raw(raw)),
_marker: PhantomData,
}
}
}