Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,6 @@ jobs:
# - `litebox_platform_lvbs` has a custom target (`no_std`), so it does
# not work with the current no_std checker.
#
# - `litebox_platform_multiplex` is allowed to have `std` access (in
# its default feature set) because `litebox_platform_linux_userland`
# has access, and this is just a multiplexer. Ideally, we'd do a
# more precise check, but as long as we are tracking the underlying
# platforms, we are unlikely to hit any significant issues here.
#
# - `litebox_runner_linux_on_windows_userland` is allowed to have `std`
# access since it needs to actually access the file-system, pull in
# relevant files, and then actually trigger LiteBox itself.
Expand Down Expand Up @@ -303,7 +297,6 @@ jobs:
-not -path './litebox_platform_windows_userland/Cargo.toml' \
-not -path './litebox_runner_linux_on_windows_userland/Cargo.toml' \
-not -path './litebox_platform_lvbs/Cargo.toml' \
-not -path './litebox_platform_multiplex/Cargo.toml' \
-not -path './litebox_runner_linux_userland/Cargo.toml' \
-not -path './litebox_runner_lvbs/Cargo.toml' \
-not -path './litebox_runner_optee_on_linux_userland/Cargo.toml' \
Expand Down
20 changes: 2 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ members = [
"litebox_platform_linux_userland",
"litebox_platform_windows_userland",
"litebox_platform_lvbs",
"litebox_platform_multiplex",
"litebox_runner_linux_userland",
"litebox_runner_linux_on_windows_userland",
"litebox_runner_lvbs",
Expand All @@ -35,7 +34,6 @@ default-members = [
"litebox_platform_linux_userland",
"litebox_platform_windows_userland",
"litebox_platform_lvbs",
"litebox_platform_multiplex",
"litebox_runner_linux_userland",
"litebox_runner_linux_on_windows_userland",
"litebox_shim_linux",
Expand Down
5 changes: 2 additions & 3 deletions dev_tests/src/ratchet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@ fn ratchet_globals() -> Result<()> {
("litebox/", 9),
("litebox_platform_linux_kernel/", 6),
("litebox_platform_linux_userland/", 5),
("litebox_platform_lvbs/", 23),
("litebox_platform_multiplex/", 1),
("litebox_platform_lvbs/", 22),
("litebox_platform_windows_userland/", 8),
("litebox_runner_lvbs/", 6),
("litebox_runner_lvbs/", 8),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
Expand Down
103 changes: 57 additions & 46 deletions litebox_common_linux/src/physical_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,11 @@
//! mapping cannot alias any Rust reference.

use crate::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageMapInfo, PhysPageMapPermissions, PhysPointerError,
VmapManager,
PhysPageAddr, PhysPageMapInfo, PhysPageMapPermissions, PhysPointerError, VmapManager,
};
use core::marker::PhantomData;
use zerocopy::{FromBytes, IntoBytes};

/// The concrete [`PhysPageMapInfo`] produced by the `VmapManager` behind a [`GlobalVmapManager`].
type MapInfoOf<V, const ALIGN: usize> =
<<V as GlobalVmapManager<ALIGN>>::Manager as VmapManager<ALIGN>>::MapInfo;

/// Allocate a zeroed `Box<T>` on the heap.
///
/// # Panics
Expand Down Expand Up @@ -80,24 +75,24 @@ fn align_down(address: usize, align: usize) -> usize {
/// Write methods require `T: IntoBytes` because values are written by copying their byte
/// representation.
///
/// - `vmgr`: A *borrowed* [`VmapManager`] used to map and unmap `pages`.
/// - `pages`: An array of page-aligned physical addresses. We expect physical addresses in this array are
/// virtually contiguous.
/// - `offset`: The offset within `pages[0]` where the object starts. It should be smaller than `ALIGN`.
/// - `count`: The number of objects of type `T` that can be accessed from this pointer.
/// - `T`: The type of the object being pointed to. `pages` with respect to `offset` should cover enough
/// memory for an object of type `T`.
#[repr(C)]
pub struct PhysMutPtr<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> {
pub struct PhysMutPtr<'v, V: VmapManager<ALIGN>, T, const ALIGN: usize> {
vmgr: &'v V,
pages: alloc::boxed::Box<[PhysPageAddr<ALIGN>]>,
offset: usize,
count: usize,
_type: PhantomData<T>,
_vmap: PhantomData<V>,
}

impl<T, const ALIGN: usize, V> PhysMutPtr<T, ALIGN, V>
impl<'v, V, T, const ALIGN: usize> PhysMutPtr<'v, V, T, ALIGN>
where
V: GlobalVmapManager<ALIGN>,
V: VmapManager<ALIGN>,
{
/// Compile-time guard rejecting zero-sized types.
///
Expand All @@ -119,12 +114,17 @@ where
/// memory. This is sound because the foreign `T` is never dereferenced as a Rust reference or
/// via a typed load/store: all access goes through `copy_in`/`copy_out`, which cast the
/// mapped pointer to `*mut u8` and perform a byte-granular, unaligned-safe `memcpy_fallible`.
pub fn new(pages: &[PhysPageAddr<ALIGN>], offset: usize) -> Result<Self, PhysPointerError> {
Self::from_boxed(pages.into(), offset)
pub fn new(
vmgr: &'v V,
pages: &[PhysPageAddr<ALIGN>],
offset: usize,
) -> Result<Self, PhysPointerError> {
Self::from_boxed(vmgr, pages.into(), offset)
}

/// Create a new `PhysMutPtr` from an owned page list, consuming it without copying.
fn from_boxed(
vmgr: &'v V,
pages: alloc::boxed::Box<[PhysPageAddr<ALIGN>]>,
offset: usize,
) -> Result<Self, PhysPointerError> {
Expand All @@ -148,21 +148,25 @@ where
core::mem::size_of::<T>(),
));
}
V::manager().validate_unowned(&pages)?;
vmgr.validate_unowned(&pages)?;
Ok(Self {
vmgr,
offset,
count: size / core::mem::size_of::<T>(),
pages,
_type: PhantomData,
_vmap: PhantomData,
})
}

/// Create a new `PhysMutPtr` from the given contiguous physical address and length.
///
/// This is a shortcut for
/// `PhysMutPtr::new([align_down(pa), align_down(pa) + ALIGN, ..., align_up(pa + bytes) - ALIGN], pa % ALIGN)`.
pub fn with_contiguous_pages(pa: usize, bytes: usize) -> Result<Self, PhysPointerError> {
pub fn with_contiguous_pages(
vmgr: &'v V,
pa: usize,
bytes: usize,
) -> Result<Self, PhysPointerError> {
if bytes < core::mem::size_of::<T>() {
return Err(PhysPointerError::InsufficientPhysicalPages(
bytes,
Expand All @@ -189,16 +193,16 @@ where
.ok_or(PhysPointerError::Overflow)?;
}
// reuse the allocation
Self::from_boxed(pages.into_boxed_slice(), pa - start_page)
Self::from_boxed(vmgr, pages.into_boxed_slice(), pa - start_page)
}

/// Create a new `PhysMutPtr` from the given physical address for a single object.
///
/// This is a shortcut for `PhysMutPtr::with_contiguous_pages(pa, size_of::<T>())`.
///
/// Note: This module doesn't provide `as_usize` because LiteBox should not dereference physical addresses directly.
pub fn with_usize(pa: usize) -> Result<Self, PhysPointerError> {
Self::with_contiguous_pages(pa, core::mem::size_of::<T>())
pub fn with_usize(vmgr: &'v V, pa: usize) -> Result<Self, PhysPointerError> {
Self::with_contiguous_pages(vmgr, pa, core::mem::size_of::<T>())
}

/// Read the value at the given offset from the physical pointer.
Expand Down Expand Up @@ -327,7 +331,7 @@ where
count: usize,
size: usize,
perms: PhysPageMapPermissions,
) -> Result<MappedGuard<'_, T, ALIGN, V>, PhysPointerError> {
) -> Result<MappedGuard<'_, V, T, ALIGN>, PhysPointerError> {
let skip = self
.offset
.checked_add(
Expand All @@ -344,10 +348,10 @@ where
let map_info = self.map_range(start, end, perms)?;
let ptr = map_info.base().wrapping_add(skip % ALIGN).cast::<T>();
Ok(MappedGuard {
vmgr: self.vmgr,
map_info: Some(map_info),
ptr,
size,
_owner: PhantomData,
})
}

Expand All @@ -357,7 +361,7 @@ where
start: usize,
end: usize,
perms: PhysPageMapPermissions,
) -> Result<MapInfoOf<V, ALIGN>, PhysPointerError> {
) -> Result<V::MapInfo, PhysPointerError> {
if start >= end || end > self.pages.len() {
return Err(PhysPointerError::IndexOutOfBounds(end, self.pages.len()));
}
Expand All @@ -370,29 +374,29 @@ where
// The platform `VmapManager` must map them only in a foreign-memory VA range, disjoint
// from LiteBox-owned Rust objects. This caller never creates Rust references from the
// returned pointer; `MappedGuard` uses it only for fault-tolerant raw byte copies.
unsafe { V::manager().vmap(sub_pages, perms) }
unsafe { self.vmgr.vmap(sub_pages, perms) }
}
}

/// RAII guard that unmaps physical pages when dropped.
///
/// Created by `map_and_get_ptr_guard`. Its lifetime is tied to the parent
/// `PhysMutPtr`, and it owns the map info for the duration of the temporary mapping.
/// Created by `map_and_get_ptr_guard`. Its lifetime is tied to the guard to a borrow of
/// the parent `PhysMutPtr`.
///
/// # Invariant
///
/// `ptr` points into the live mapping owned by `map_info`, and the `size` bytes starting
/// at `ptr` lie within that mapping. The mapping refers to foreign (non-Rust) physical
/// memory that another core may unmap concurrently, so `ptr` must only ever be accessed
/// through [`Self::copy_in`]/[`Self::copy_out`], which perform fault-tolerant copies.
struct MappedGuard<'a, T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> {
map_info: Option<MapInfoOf<V, ALIGN>>,
struct MappedGuard<'v, V: VmapManager<ALIGN>, T, const ALIGN: usize> {
vmgr: &'v V,
map_info: Option<V::MapInfo>,
ptr: *mut T,
size: usize,
_owner: PhantomData<&'a PhysMutPtr<T, ALIGN, V>>,
}

impl<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> MappedGuard<'_, T, ALIGN, V> {
impl<V: VmapManager<ALIGN>, T, const ALIGN: usize> MappedGuard<'_, V, T, ALIGN> {
/// Copy the `self.size` mapped bytes out into `dst`.
///
/// This is the only path through which the raw mapped pointer is dereferenced.
Expand Down Expand Up @@ -426,20 +430,20 @@ impl<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> MappedGuard<'_, T, ALIG
}
}

impl<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> Drop for MappedGuard<'_, T, ALIGN, V> {
impl<V: VmapManager<ALIGN>, T, const ALIGN: usize> Drop for MappedGuard<'_, V, T, ALIGN> {
fn drop(&mut self) {
// SAFETY: The platform is expected to handle unmapping safely. Drop cannot
// report errors. If unmapping fails, drop the returned private map_info;
// platform-specific resources that cannot be reclaimed are handled by the
// platform `vunmap` implementation.
if let Some(map_info) = self.map_info.take() {
let _ = unsafe { V::manager().vunmap(map_info) };
let _ = unsafe { self.vmgr.vunmap(map_info) };
}
}
}

impl<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> core::fmt::Debug
for PhysMutPtr<T, ALIGN, V>
impl<V: VmapManager<ALIGN>, T, const ALIGN: usize> core::fmt::Debug
for PhysMutPtr<'_, V, T, ALIGN>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PhysMutPtr")
Expand All @@ -451,34 +455,41 @@ impl<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> core::fmt::Debug

/// Represent a physical pointer to a read-only object. This wraps around [`PhysMutPtr`] and
/// exposes only copy-out access.
#[repr(C)]
pub struct PhysConstPtr<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> {
inner: PhysMutPtr<T, ALIGN, V>,
pub struct PhysConstPtr<'v, V: VmapManager<ALIGN>, T, const ALIGN: usize> {
inner: PhysMutPtr<'v, V, T, ALIGN>,
}

impl<T: FromBytes, const ALIGN: usize, V> PhysConstPtr<T, ALIGN, V>
impl<'v, V, T: FromBytes, const ALIGN: usize> PhysConstPtr<'v, V, T, ALIGN>
where
V: GlobalVmapManager<ALIGN>,
V: VmapManager<ALIGN>,
{
/// Create a new `PhysConstPtr` from the given physical page array and offset.
///
/// All addresses in `pages` should be valid and aligned to `ALIGN`, and `offset` should be smaller
/// than `ALIGN`. Also, `pages` should contain enough pages to cover at least one object of
/// type `T` starting from `offset`. If these conditions are not met, this function returns
/// `Err(PhysPointerError)`.
pub fn new(pages: &[PhysPageAddr<ALIGN>], offset: usize) -> Result<Self, PhysPointerError> {
pub fn new(
vmgr: &'v V,
pages: &[PhysPageAddr<ALIGN>],
offset: usize,
) -> Result<Self, PhysPointerError> {
Ok(Self {
inner: PhysMutPtr::new(pages, offset)?,
inner: PhysMutPtr::new(vmgr, pages, offset)?,
})
}

/// Create a new `PhysConstPtr` from the given contiguous physical address and length.
///
/// This is a shortcut for
/// `PhysConstPtr::new([align_down(pa), align_down(pa) + ALIGN, ..., align_up(pa + bytes) - ALIGN], pa % ALIGN)`.
pub fn with_contiguous_pages(pa: usize, bytes: usize) -> Result<Self, PhysPointerError> {
pub fn with_contiguous_pages(
vmgr: &'v V,
pa: usize,
bytes: usize,
) -> Result<Self, PhysPointerError> {
Ok(Self {
inner: PhysMutPtr::with_contiguous_pages(pa, bytes)?,
inner: PhysMutPtr::with_contiguous_pages(vmgr, pa, bytes)?,
})
}

Expand All @@ -487,9 +498,9 @@ where
/// This is a shortcut for `PhysConstPtr::with_contiguous_pages(pa, size_of::<T>())`.
///
/// Note: This module doesn't provide `as_usize` because LiteBox should not dereference physical addresses directly.
pub fn with_usize(pa: usize) -> Result<Self, PhysPointerError> {
pub fn with_usize(vmgr: &'v V, pa: usize) -> Result<Self, PhysPointerError> {
Ok(Self {
inner: PhysMutPtr::with_usize(pa)?,
inner: PhysMutPtr::with_usize(vmgr, pa)?,
})
}

Expand Down Expand Up @@ -518,8 +529,8 @@ where
}
}

impl<T, const ALIGN: usize, V: GlobalVmapManager<ALIGN>> core::fmt::Debug
for PhysConstPtr<T, ALIGN, V>
impl<V: VmapManager<ALIGN>, T, const ALIGN: usize> core::fmt::Debug
for PhysConstPtr<'_, V, T, ALIGN>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PhysConstPtr")
Expand Down
Loading