Skip to content
1 change: 1 addition & 0 deletions litebox_common_linux/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::signal::SigSet;
pub mod errno;
pub mod loader;
pub mod mm;
pub mod physical_pointers;
pub mod signal;
pub mod vmap;

Expand Down
500 changes: 500 additions & 0 deletions litebox_common_linux/src/physical_pointers.rs

Large diffs are not rendered by default.

104 changes: 83 additions & 21 deletions litebox_common_linux/src/vmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,59 @@ use thiserror::Error;
///
/// `ALIGN`: The page frame size.
///
/// This provider exists to service `litebox_shim_optee::ptr::PhysMutPtr` and
/// `litebox_shim_optee::ptr::PhysConstPtr`. It can benefit other modules which need
/// This provider exists to service [`crate::physical_pointers::PhysMutPtr`] and
/// [`crate::physical_pointers::PhysConstPtr`]. It can benefit other modules which need
/// Linux kernel's `vmap()` and `vunmap()` functionalities (e.g., HVCI/HEKI, drivers).
pub trait VmapManager<const ALIGN: usize> {
///
/// # Safety
///
/// Implementors must uphold each unsafe method's contract and keep [`Self::MapInfo`] tied to the
/// mapping it identifies.
pub unsafe trait VmapManager<const ALIGN: usize> {
/// Implementors use this to carry the virtual mapping and any platform-specific bookkeeping
/// needed for unmapping.
type MapInfo: PhysPageMapInfo;

/// Map the given `PhysPageAddrArray` into virtually contiguous addresses with the given
/// [`PhysPageMapPermissions`] while returning [`PhysPageMapInfo`].
/// [`PhysPageMapPermissions`] while returning [`Self::MapInfo`].
///
/// This function is analogous to Linux kernel's `vmap()`.
///
/// # Safety
///
/// The caller should ensure that `pages` are not in active use by other entities
/// (especially, there should be no read/write or write/write conflicts).
/// Unfortunately, LiteBox itself cannot fully guarantee this and it needs some helps
/// from the caller, hypervisor, or hardware.
/// Multiple LiteBox threads might concurrently call this function with overlapping
/// physical pages, so the implementation should safely handle such cases.
/// The returned pointer is a raw address; creating or holding it does not access memory or
/// create a Rust reference. Any later use of that pointer must satisfy the platform's access
/// requirements for the mapped physical pages. Even when access is logically exclusive, callers
/// must treat the mapped memory like DMA/shared physical memory rather than ordinary Rust-owned
/// RAM.
unsafe fn vmap(
&self,
_pages: &PhysPageAddrArray<ALIGN>,
_perms: PhysPageMapPermissions,
) -> Result<PhysPageMapInfo<ALIGN>, PhysPointerError> {
) -> Result<Self::MapInfo, PhysPointerError> {
Err(PhysPointerError::UnsupportedOperation)
}

/// Unmap the previously mapped virtually contiguous addresses ([`PhysPageMapInfo`]).
/// Unmap the previously mapped virtually contiguous addresses ([`Self::MapInfo`]).
///
/// This function is analogous to Linux kernel's `vunmap()`.
///
/// On failure, the unchanged `vmap_info` is returned alongside the error so the caller can
/// retry or otherwise preserve the mapping state. Dropping returned map info is not guaranteed
/// to release platform resources; each implementation owns the retention policy for resources
/// that cannot be safely reclaimed after a failed unmap.
///
/// # Safety
///
/// The caller should ensure that the virtual addresses in `vmap_info` are not in active
/// use by other entities.
unsafe fn vunmap(&self, _vmap_info: PhysPageMapInfo<ALIGN>) -> Result<(), PhysPointerError> {
Err(PhysPointerError::UnsupportedOperation)
/// The caller must ensure there are no outstanding raw-pointer uses or Rust references derived
/// from `PhysPageMapInfo::base()`. After a successful call, the virtual mapping is invalid and
/// any platform resources tied to the mapping lifetime have been released or otherwise handled
/// by the implementation.
unsafe fn vunmap(
&self,
vmap_info: Self::MapInfo,
) -> Result<(), (PhysPointerError, Self::MapInfo)> {
Err((PhysPointerError::UnsupportedOperation, vmap_info))
}

/// Validate that the given physical pages are not owned by LiteBox.
Expand Down Expand Up @@ -79,6 +97,22 @@ pub trait VmapManager<const ALIGN: usize> {
}
}

/// A type-level handle to a platform-global [`VmapManager`].
///
/// `PhysMutPtr` and `PhysConstPtr` carry their provider as a type parameter
/// (`PhantomData<P>`), so they cannot hold a live `&VmapManager`. This trait
/// is the minimum surface that lets such a `PhantomData`-only carrier reach
/// the live manager: each platform implements this on a small unit struct
/// (e.g., `Vmap`) and points `manager()` at its global
/// platform singleton.
pub trait GlobalVmapManager<const ALIGN: usize>: 'static {
/// The concrete `VmapManager` this marker resolves to.
type Manager: VmapManager<ALIGN> + 'static;

/// Return the global manager instance for this platform.
fn manager() -> &'static Self::Manager;
}

/// Data structure representing a physical address with page alignment.
///
/// Currently, this is an alias to `crate::mm::linux::NonZeroAddress`. This might change if
Expand All @@ -90,13 +124,39 @@ pub type PhysPageAddr<const ALIGN: usize> = litebox::mm::linux::NonZeroAddress<A
/// Data structure for an array of physical page addresses which are virtually contiguous.
pub type PhysPageAddrArray<const ALIGN: usize> = [PhysPageAddr<ALIGN>];

/// Data structure to maintain the mapping information returned by `vmap()`.
#[derive(Clone)]
pub struct PhysPageMapInfo<const ALIGN: usize> {
/// Mapping information returned by `vmap()`.
///
/// Implementors use this value to track the virtual mapping and any platform-specific resources
/// tied to it. Callers must pass it back to the same platform's `vunmap()` to explicitly unmap;
/// drop behavior is implementation-specific.
pub trait PhysPageMapInfo {
/// Virtual address of the mapped region which is page aligned.
pub base: *mut u8,
fn base(&self) -> *mut u8;
/// The size of the mapped region in bytes.
pub size: usize,
fn size(&self) -> usize;
}

/// A no-op [`PhysPageMapInfo`] for platforms that do not support `vmap()`/`vunmap()`.
#[derive(Debug)]
pub struct NoopPhysPageMapInfo {
base: *mut u8,
size: usize,
}

impl NoopPhysPageMapInfo {
pub fn new(base: *mut u8, size: usize) -> Self {
Self { base, size }
}
}

impl PhysPageMapInfo for NoopPhysPageMapInfo {
fn base(&self) -> *mut u8 {
self.base
}

fn size(&self) -> usize {
self.size
}
}

bitflags::bitflags! {
Expand Down Expand Up @@ -156,6 +216,8 @@ pub enum PhysPointerError {
"The total size of the given pages ({0} bytes) is insufficient for the requested type ({1} bytes)"
)]
InsufficientPhysicalPages(usize, usize),
#[error("Zero-sized types are unsupported for physical pointers")]
UnsupportedZeroSizedType,
#[error("Index {0} is out of bounds (count: {1})")]
IndexOutOfBounds(usize, usize),
#[error("Physical address {0:#x} is already mapped")]
Expand Down
2 changes: 1 addition & 1 deletion litebox_common_optee/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2058,7 +2058,7 @@ impl From<&OpteeSmcArgsPage> for OpteeSmcArgs {
}

/// OP-TEE SMC call arguments.
#[derive(Clone, Copy, Default, FromBytes)]
#[derive(Clone, Copy, Default, FromBytes, IntoBytes, Immutable)]
pub struct OpteeSmcArgs {
args: [usize; Self::NUM_OPTEE_SMC_ARGS],
}
Expand Down
4 changes: 3 additions & 1 deletion litebox_platform_linux_userland/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2373,7 +2373,9 @@ impl litebox::platform::DerivedKeyProvider for LinuxUserland {
/// In general, userland platforms do not support `vmap` and `vunmap` (which are kernel functions).
/// We might need to emulate these functions' behaviors using virtual addresses for development or
/// testing, or use a kernel module to provide this functionality (if needed).
impl<const ALIGN: usize> VmapManager<ALIGN> for LinuxUserland {}
unsafe impl<const ALIGN: usize> VmapManager<ALIGN> for LinuxUserland {
type MapInfo = litebox_common_linux::vmap::NoopPhysPageMapInfo;
}

/// Dummy `VmemPageFaultHandler`.
///
Expand Down
3 changes: 1 addition & 2 deletions litebox_platform_lvbs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ x86_64 = { version = "0.15.2", default-features = false, features = ["instructio
libc = "0.2.177"

[features]
default = ["optee_syscall"]
optee_syscall = []
default = []
linux_syscall = []
devbox = []

Expand Down
2 changes: 0 additions & 2 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,6 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
/// # Behavior
/// - Any existing mapping is treated as an error
/// - On error, all pages mapped by this call are unmapped (atomic)
#[cfg(feature = "optee_syscall")]
pub(crate) fn map_non_contiguous_phys_frames(
&self,
frames: &[PhysFrame<Size4KiB>],
Expand Down Expand Up @@ -725,7 +724,6 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
///
/// Note: The caller must already hold the page table lock (`self.inner`).
/// This function accepts the locked `MappedPageTable` directly.
#[cfg(feature = "optee_syscall")]
fn rollback_mapped_pages(
inner: &mut MappedPageTable<'_, FrameMapping<M>>,
pages: x86_64::structures::paging::page::PageRangeInclusive<Size4KiB>,
Expand Down
Loading