starina_api/folio.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
//! A contiguous page-aliged memory block.
use starina_types::address::PAddr;
use starina_types::address::VAddr;
use starina_types::error::FtlError;
use starina_types::vmspace::PageProtect;
use starina_utils::alignment::align_down;
use starina_utils::alignment::align_up;
use crate::handle::OwnedHandle;
use crate::start::app_vmspace_handle;
use crate::syscall;
/// The ownership of a contiguous page-aliged memory region.
///
/// To summarize:
///
/// - The memory block address is page-aligned (typically 4KB).
/// - The memory block size is also page-aligned.
/// - The memory block is *physically* contiguous.
///
/// # When to use
///
/// Use folio when you need a *physically contiguous* memory region. The common
/// case is when you need to allocate a DMA buffer in a device driver (strictly
/// speaking, when IOMMU is not available).
///
/// # Prefer [`Box<T>`](crate::prelude::Box) over folio
///
/// Unless you need low-level control over memory allocation, use containers
/// like [`Vec<T>`](crate::prelude::Vec) or [`Box<T>`](crate::prelude::Box)
/// memory regions directly, such as DMA buffers, MMIO regions, and shared
/// instead of folio. Folio is intended for OS services that need to manage
/// memory between processes.
///
/// # You may want [`MappedFolio`] instead
///
/// If you want to access the memory region, use [`MappedFolio`] instead.
///
/// # Why "folio"?
///
/// Because it's *a sheet of paper (pages)*.
pub struct Folio {
handle: OwnedHandle,
}
impl Folio {
pub fn create(len: usize) -> Result<Folio, FtlError> {
let handle = syscall::folio_create(len)?;
Ok(Folio {
handle: OwnedHandle::from_raw(handle),
})
}
pub fn handle(&self) -> &OwnedHandle {
&self.handle
}
pub fn paddr(&self) -> Result<PAddr, FtlError> {
let paddr = syscall::folio_paddr(self.handle.id())?;
let paddr = PAddr::new(paddr);
Ok(paddr)
}
}
/// A folio mapped to the current process's address space.
pub struct MappedFolio {
_folio: Folio,
paddr: PAddr,
vaddr: VAddr,
}
impl MappedFolio {
/// Allocates a folio at an arbitrary physical address, and maps it to the
/// current process's address space.
pub fn create(len: usize) -> Result<MappedFolio, FtlError> {
let handle = syscall::folio_create(len)?;
let vaddr = syscall::vmspace_map(
app_vmspace_handle(),
len,
handle,
PageProtect::READABLE | PageProtect::WRITABLE,
)?;
let paddr = syscall::folio_paddr(handle)?;
Ok(MappedFolio {
_folio: Folio {
handle: OwnedHandle::from_raw(handle),
},
paddr: PAddr::new(paddr),
vaddr,
})
}
/// Allocates a folio at a specific physical address (`paddr`), and maps it to the
/// current process's address space.
pub fn create_pinned(paddr: PAddr, len: usize) -> Result<MappedFolio, FtlError> {
let offset = paddr.as_usize() % 4096; // FIXME:
let map_paddr = PAddr::new(align_down(paddr.as_usize(), 4096));
let map_len = align_up(len, 4096);
let handle = syscall::folio_create_fixed(map_paddr, map_len)?;
let vaddr = syscall::vmspace_map(
app_vmspace_handle(),
map_len,
handle,
PageProtect::READABLE | PageProtect::WRITABLE,
)?;
Ok(MappedFolio {
_folio: Folio {
handle: OwnedHandle::from_raw(handle),
},
paddr,
vaddr: vaddr.add(offset),
})
}
/// Returns the start address of the folio in the current process's address space.
pub fn vaddr(&self) -> VAddr {
self.vaddr
}
/// Returns the start address of the folio in physical memory space.
pub fn paddr(&self) -> PAddr {
self.paddr
}
}