kata-os-common: add CopyRegion support.

Move the CopyRegion support to kata-os-common. CopyRegion wraps a
CAmkES copyregion virtual memory window to support virtual access to
physical page frames. There is RAII cleanup to clear any virtual mapping.
Embedding a CopyRegion in struct that may be cloned is not recommeded
(at least for now).

Change-Id: I7fd465fafa4a5d1de9a7e565ecb62c38a3b7e81a
GitOrigin-RevId: f58e973b1c47ec05e48bfedcb9cd5e75b71c212a
This commit is contained in:
Sam Leffler 2022-06-22 19:04:36 +00:00
parent f70a9af73f
commit acf7c28eba
6 changed files with 165 additions and 83 deletions

View File

@ -5,8 +5,8 @@
use core::mem::size_of;
use core::ptr;
use crate::sel4bundle::arch;
use crate::sel4bundle::CopyRegion;
use crate::sel4bundle::seL4BundleImpl;
use super::CopyRegion;
use super::sel4_sys;
use arch::PAGE_SIZE;
@ -64,8 +64,10 @@ impl seL4BundleImpl {
// be on a page boundary.
let frame_obj = self.get_stack_frame_obj(sp - size_of::<seL4_Word>());
let mut copy_region =
CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])});
let mut copy_region = CopyRegion::new(
unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])},
PAGE_SIZE
);
copy_region.map(frame_obj.cptr)?;
// Write spillover arguments to the TCB's stack.

View File

@ -16,6 +16,7 @@ use kata_memory_interface::kata_object_free;
use kata_memory_interface::kata_object_free_in_cnode;
use kata_memory_interface::ObjDesc;
use kata_memory_interface::ObjDescBundle;
use kata_os_common::copyregion::CopyRegion;
use kata_os_common::cspace_slot::CSpaceSlot;
use kata_os_common::sel4_sys;
use kata_proc_interface::Bundle;
@ -36,9 +37,7 @@ use sel4_sys::seL4_DomainSet_Set;
use sel4_sys::seL4_EndpointObject;
use sel4_sys::seL4_Error;
use sel4_sys::seL4_MinSchedContextBits;
use sel4_sys::seL4_Page_Map;
use sel4_sys::seL4_PageTableObject;
use sel4_sys::seL4_Page_Unmap;
use sel4_sys::seL4_ReplyObject;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SchedContextObject;
@ -64,8 +63,6 @@ extern "C" {
// Our thread's TCB; used in setting up scheduling of new TCB's.
static SELF_TCB_PROCESS_MANAGER_PROC_CTRL_0000: seL4_CPtr;
static SELF_VSPACE_ROOT: seL4_CPtr;
// Region for mapping data when loading the contents of a BundleImage.
static mut LOAD_APPLICATION: [seL4_Word; PAGE_SIZE / size_of::<seL4_Word>()];
}
@ -136,78 +133,6 @@ fn check_bundle(bundle: &ObjDescBundle) {
}
}
// TODO(sleffler): move to kata-os-common
pub struct CopyRegion {
region: *mut seL4_Word,
cur_frame: Option<seL4_CPtr>,
}
impl CopyRegion {
pub fn new(region: *mut seL4_Word) -> Self {
CopyRegion {
region,
cur_frame: None,
}
}
// Returns the region size in bytes.
pub fn size(&self) -> usize { PAGE_SIZE }
// Returns a mutable [u8] ref to the mapped region.
pub fn as_mut(&mut self) -> &mut [u8] {
assert!(self.cur_frame.is_some());
unsafe {
core::slice::from_raw_parts_mut(
self.region as _, PAGE_SIZE
)
}
}
// Returns a mutable [seL4_Word] ref to the mapped region.
pub fn as_word_mut(&mut self) -> &mut [seL4_Word] {
assert!(self.cur_frame.is_some());
unsafe {
core::slice::from_raw_parts_mut(
self.region, PAGE_SIZE / size_of::<seL4_Word>(),
)
}
}
// Maps the |frame| in the SELF_VSPACE_ROOT for r/w.
pub fn map(&mut self, frame: seL4_CPtr) -> seL4_Result {
let attribs = seL4_Default_VMAttributes;
unsafe {
seL4_Page_Map(
frame,
SELF_VSPACE_ROOT,
self.region as usize,
// seL4_ReadWrite
seL4_CapRights::new(
/*grant_reply=*/ 0, /*grant=*/ 0, /*read=*/ 1, /*write=*/ 1,
),
attribs,
)
}?;
self.cur_frame = Some(frame);
Ok(())
}
// Unmaps the current frame, if any.
pub fn unmap(&mut self) -> seL4_Result {
if let Some(cptr) = self.cur_frame {
#[cfg(target_arch = "arm")]
unsafe { seL4_ARM_Page_Unify_Instruction(cptr, 0, self.size()) }?;
unsafe { seL4_Page_Unmap(cptr) }?;
self.cur_frame = None;
}
Ok(())
}
}
impl Drop for CopyRegion {
fn drop(&mut self) {
self.unmap().expect("CopyRegion");
}
}
const NOCAP: seL4_CPtr = 0;
// Layout of the CNode holding dynamic_objs. All entries are singletons
@ -427,10 +352,10 @@ impl seL4BundleImpl {
// to fill from the |bundle_frames| and/or zero-fill.
let mut image = BundleImage::new(bundle_frames);
let mut copy_region =
CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])});
// Many places assume the copy region is PAGE_SIZE
assert_eq!(copy_region.size(), PAGE_SIZE);
let mut copy_region = CopyRegion::new(
unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])},
PAGE_SIZE
);
let mut vaddr_top = 0;
while let Some(section) = image.next_section() {

View File

@ -13,6 +13,7 @@ camkes_support = []
allocator = { path = "src/allocator" }
camkes = { path = "src/camkes" }
capdl = { path = "src/capdl" }
copyregion = { path = "src/copyregion" }
cspace-slot = { path = "src/cspace-slot" }
logger = { path = "src/logger" }
model = { path = "src/model" }

View File

@ -0,0 +1,11 @@
cargo-features = ["edition2021"]
[package]
name = "copyregion"
version = "0.1.0"
authors = ["Sam Leffler <sleffler@google.com>"]
edition = "2021"
[dependencies]
log = "0.4"
sel4-sys = { path = "../sel4-sys" }

View File

@ -0,0 +1,141 @@
//! RAII wrapper for using a KataOS copyregion object.
#![no_std]
#![allow(non_camel_case_types)]
use core::mem::size_of;
use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Default_VMAttributes;
use sel4_sys::seL4_Page_Map;
use sel4_sys::seL4_Page_Unmap;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_Word;
extern "C" {
static SELF_VSPACE_ROOT: seL4_CPtr;
}
// Sample usage:
// let mut copy_region = CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])}, PAGE_SIZE);
// copy_region.map(frame.cptr)?;
// copy_region.as_mut()[..].fill(0);
// let start = if index > 0 { 0 } else { vaddr - data_range.start };
// let end = cmp::min(data_range.end - vaddr, copy_region.size());
// image.read_exact(&mut copy_region.as_mut()[start..end])
// .map_err(|_| seL4_Error::seL4_NoError)?; // XXX
// copy_region.unmap()?;
// TODO(sleffler): do we need to parameterize VM_Attributes & CapRights?
// TODO(sleffler): Mutex-wrapped & maybe RefCell-wrapped versions?
// Fn from the criterion crate that convinces the optimizer
// a value is used in order to defeat premature optimization.
fn black_box<T>(dummy: T) -> T {
unsafe {
let ret = core::ptr::read_volatile(&dummy);
core::mem::forget(dummy);
ret
}
}
pub struct CopyRegion {
region: *mut seL4_Word,
size: usize,
cur_frame: Option<seL4_CPtr>,
}
impl CopyRegion {
pub fn new(region: *mut seL4_Word, size: usize) -> Self {
CopyRegion {
region,
size,
cur_frame: None,
}
}
// Returns the region size in bytes.
pub fn size(&self) -> usize { self.size }
// Returns the region size if mapped, otherwise 0.
pub fn mapped_bytes(&self) -> usize {
if self.cur_frame.is_some() { self.size } else { 0 }
}
// Returns an immutable [u8] ref to the mapped region.
pub fn as_ref(&mut self) -> &[u8] {
assert!(self.cur_frame.is_some());
unsafe {
core::slice::from_raw_parts(
self.region as _, self.size
)
}
}
// Returns a mutable [u8] ref to the mapped region.
pub fn as_mut(&mut self) -> &mut [u8] {
assert!(self.cur_frame.is_some());
unsafe {
core::slice::from_raw_parts_mut(
self.region as _, self.size
)
}
}
// Returns an immutable [seL4_Word] ref to the mapped region.
pub fn as_word_ref(&mut self) -> &[seL4_Word] {
assert!(self.cur_frame.is_some());
unsafe {
core::slice::from_raw_parts(
self.region, self.size / size_of::<seL4_Word>(),
)
}
}
// Returns a mutable [seL4_Word] ref to the mapped region.
pub fn as_word_mut(&mut self) -> &mut [seL4_Word] {
assert!(self.cur_frame.is_some());
unsafe {
core::slice::from_raw_parts_mut(
self.region, self.size / size_of::<seL4_Word>(),
)
}
}
// Maps the |frame| in the SELF_VSPACE_ROOT for r/w.
// XXX need rights + attribs?
pub fn map(&mut self, frame: seL4_CPtr) -> seL4_Result {
black_box(frame); // NB: compiler WAR for frame clobber
unsafe {
seL4_Page_Map(
frame,
SELF_VSPACE_ROOT,
self.region as seL4_Word,
// seL4_ReadWrite
seL4_CapRights::new(
/*grant_reply=*/ 0, /*grant=*/ 0, /*read=*/ 1, /*write=*/ 1,
),
seL4_Default_VMAttributes,
)
}?;
self.cur_frame = Some(frame);
Ok(())
}
// Unmaps the current frame, if any.
pub fn unmap(&mut self) -> seL4_Result {
if let Some(cptr) = self.cur_frame {
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
unsafe { seL4_ARM_Page_Unify_Instruction(cptr, 0, self.size()) }?;
unsafe { seL4_Page_Unmap(cptr) }?;
self.cur_frame = None;
}
Ok(())
}
}
impl Drop for CopyRegion {
fn drop(&mut self) {
self.unmap().expect("CopyRegion");
}
}

View File

@ -5,6 +5,8 @@ pub extern crate allocator;
pub extern crate camkes;
pub extern crate capdl;
#[cfg(feature = "camkes_support")]
pub extern crate copyregion;
#[cfg(feature = "camkes_support")]
pub extern crate cspace_slot;
pub extern crate logger;
pub extern crate model;