Skip to content

Commit

Permalink
mm/vm: replace Box with GlobalBox
Browse files Browse the repository at this point in the history
Replace uses of Box with the new fallible-allocation-aware GlobalBox
type. Unfortunately, replacing the Box used in the RB tree for
virtual mappings is very involved.

In short, the intrusive_collections crate provides an
intrusive_adapter macro, which generates a new adapter type that
handles the insertion and deletion of any type into an intrusive
collection. Sadly, this macro is only prepared to work with the smart
pointer types in the standard library. This is done by implementing
the PointerOps trait for DefaultPointerOps<T>, where T is one of the
regular smart pointer types (Rc, Arc, Box, etc.). The macro then
generates an implementation of Adapter for the newly generated type,
which uses the selected smart pointer.

We define a substitute for DefaultPointerOps, CustomPointerOps, and
implement PointerOps for CustomPointerOps<GlobalBox>. We then add a
manual implementation of Adapter for VMMAdapter, which uses GlobalBox
under the hood.

Signed-off-by: Carlos López <[email protected]>
  • Loading branch information
00xc committed Feb 1, 2024
1 parent a2dd82a commit 6fffb42
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 14 deletions.
132 changes: 121 additions & 11 deletions src/mm/vm/mapping/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ use crate::error::SvsmError;
use crate::locking::{RWLock, ReadLockGuard, WriteLockGuard};
use crate::mm::pagetable::PTEntryFlags;
use crate::mm::vm::VMR;
use crate::mm::GlobalBox;
use crate::types::{PageSize, PAGE_SHIFT};
use core::fmt;
use core::marker::PhantomData;

use intrusive_collections::rbtree::Link;
use intrusive_collections::{intrusive_adapter, KeyAdapter};
use intrusive_collections::{
container_of, offset_of, Adapter, DefaultLinkOps, KeyAdapter, LinkOps, PointerOps,
};

use core::ops::Range;

Expand All @@ -31,7 +36,7 @@ pub struct VMPageFaultResolution {
pub flags: PTEntryFlags,
}

pub trait VirtualMapping: core::fmt::Debug {
pub trait VirtualMapping: fmt::Debug {
/// Request the size of the virtual memory mapping
///
/// # Returns
Expand Down Expand Up @@ -182,15 +187,6 @@ pub struct VMM {
mapping: Arc<Mapping>,
}

intrusive_adapter!(pub VMMAdapter = Box<VMM>: VMM { link: Link });

impl<'a> KeyAdapter<'a> for VMMAdapter {
type Key = usize;
fn get_key(&self, node: &'a VMM) -> Self::Key {
node.range.start
}
}

impl VMM {
/// Create a new VMM instance with at a given address and backing struct
///
Expand Down Expand Up @@ -248,3 +244,117 @@ impl VMM {
self.mapping.clone()
}
}

/// A simple newtype wrapper around a [`PhantomData`] used as a workaround for
/// Rust's orphan rules, in order to implement [`PointerOps`].
///
/// Does a similar job as [`DefaultPointerOps`](intrusive_collections::DefaultPointerOps).
#[derive(Debug, Clone, Copy, Default)]
pub struct CustomPointerOps<T>(PhantomData<T>);

impl<T> CustomPointerOps<T> {
const NEW: Self = Self(PhantomData);
}

/// An implementation of [`PointerOps`] for [`CustomPointerOps<GlobalBox>`]
/// similar to the one for [`DefaultPointerOps<Box>`](intrusive_collections::DefaultPointerOps).
unsafe impl PointerOps for CustomPointerOps<GlobalBox<VMM>> {
type Value = VMM;
type Pointer = GlobalBox<VMM>;

#[inline]
unsafe fn from_raw(&self, raw: *const Self::Value) -> Self::Pointer {
GlobalBox::from_raw(raw as *mut _)
}

#[inline]
fn into_raw(&self, ptr: Self::Pointer) -> *const Self::Value {
GlobalBox::into_raw(ptr)
}
}

/// An adapter to insert a [`VMM`] in an intrusive collection, similar to the
/// one generated by the [`intrusive_adapter`](intrusive_collections::intrusive_adapter)
/// macro.
pub struct VMMAdapter {
link_ops: <Link as DefaultLinkOps>::Ops,
pointer_ops: CustomPointerOps<GlobalBox<VMM>>,
}

#[allow(dead_code)]
impl VMMAdapter {
pub const NEW: Self = VMMAdapter {
link_ops: <Link as DefaultLinkOps>::NEW,
pointer_ops: CustomPointerOps::NEW,
};

#[inline]
pub fn new() -> Self {
Self::NEW
}
}

impl Default for VMMAdapter {
#[inline]
fn default() -> Self {
Self::NEW
}
}

// Implement this manually because we have `deny(missing_debug_implementations)`
// but `link_ops` does not implement Debug.
impl fmt::Debug for VMMAdapter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("VMMAdapter")
.field("link_ops", &"_")
.field("pointer_ops", &"_")
.finish()
}
}

/// Allows a [`VMM`] to be introduced in an intrusive collection. This is a
/// manual implementation of the code generated by the
/// [`intrusive_adapter`](intrusive_collections::intrusive_adapter) macro.
unsafe impl Adapter for VMMAdapter {
type LinkOps = <Link as DefaultLinkOps>::Ops;
type PointerOps = CustomPointerOps<GlobalBox<VMM>>;

#[inline]
unsafe fn get_value(
&self,
link: <Self::LinkOps as LinkOps>::LinkPtr,
) -> *const <Self::PointerOps as PointerOps>::Value {
container_of!(link.as_ptr(), VMM, link)
}

#[inline]
unsafe fn get_link(
&self,
value: *const <Self::PointerOps as PointerOps>::Value,
) -> <Self::LinkOps as LinkOps>::LinkPtr {
let ptr = (value as *const u8).add(offset_of!(VMM, link));
core::ptr::NonNull::new_unchecked(ptr as *mut _)
}

#[inline]
fn link_ops(&self) -> &Self::LinkOps {
&self.link_ops
}

#[inline]
fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
&mut self.link_ops
}

#[inline]
fn pointer_ops(&self) -> &Self::PointerOps {
&self.pointer_ops
}
}

impl<'a> KeyAdapter<'a> for VMMAdapter {
type Key = usize;
fn get_key(&self, node: &'a VMM) -> Self::Key {
node.range.start
}
}
6 changes: 3 additions & 3 deletions src/mm/vm/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::cpu::flush_tlb_global_sync;
use crate::error::SvsmError;
use crate::locking::RWLock;
use crate::mm::pagetable::{PTEntryFlags, PageTable, PageTablePart, PageTableRef};
use crate::mm::GlobalBox;
use crate::types::{PageSize, PAGE_SHIFT, PAGE_SIZE};
use crate::utils::{align_down, align_up};

Expand All @@ -20,7 +21,6 @@ use intrusive_collections::Bound;
use super::{Mapping, VMMAdapter, VMM};

extern crate alloc;
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;

Expand Down Expand Up @@ -217,7 +217,7 @@ impl VMR {
start_pfn: usize,
cursor: &mut CursorMut<VMMAdapter>,
) -> Result<(), SvsmError> {
let vmm = Box::new(VMM::new(start_pfn, mapping));
let vmm = GlobalBox::try_new(VMM::new(start_pfn, mapping))?;
if let Err(e) = self.map_vmm(&vmm) {
self.unmap_vmm(&vmm);
Err(e)
Expand Down Expand Up @@ -355,7 +355,7 @@ impl VMR {
/// # Returns
///
/// The removed mapping on success, SvsmError::Mem on error
pub fn remove(&self, base: VirtAddr) -> Result<Box<VMM>, SvsmError> {
pub fn remove(&self, base: VirtAddr) -> Result<GlobalBox<VMM>, SvsmError> {
let mut tree = self.tree.lock_write();
let addr = base.pfn();

Expand Down

0 comments on commit 6fffb42

Please sign in to comment.