From acf7c28ebadaf152f01642eb47a0c23bd26a4ba8 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Wed, 22 Jun 2022 19:04:36 +0000 Subject: [PATCH] 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 --- .../src/sel4bundle/feature/spill_tcb_args.rs | 8 +- .../kata-proc-manager/src/sel4bundle/mod.rs | 85 +---------- .../components/kata-os-common/Cargo.toml | 1 + .../kata-os-common/src/copyregion/Cargo.toml | 11 ++ .../kata-os-common/src/copyregion/src/lib.rs | 141 ++++++++++++++++++ .../components/kata-os-common/src/lib.rs | 2 + 6 files changed, 165 insertions(+), 83 deletions(-) create mode 100644 apps/system/components/kata-os-common/src/copyregion/Cargo.toml create mode 100644 apps/system/components/kata-os-common/src/copyregion/src/lib.rs diff --git a/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/feature/spill_tcb_args.rs b/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/feature/spill_tcb_args.rs index 3f9706d..2baa0b0 100644 --- a/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/feature/spill_tcb_args.rs +++ b/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/feature/spill_tcb_args.rs @@ -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::()); - 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. diff --git a/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/mod.rs b/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/mod.rs index 0cf1b9b..a375995 100644 --- a/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/mod.rs +++ b/apps/system/components/ProcessManager/kata-proc-manager/src/sel4bundle/mod.rs @@ -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::()]; } @@ -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, -} -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::(), - ) - } - } - - // 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() { diff --git a/apps/system/components/kata-os-common/Cargo.toml b/apps/system/components/kata-os-common/Cargo.toml index 7b58e55..fe02755 100644 --- a/apps/system/components/kata-os-common/Cargo.toml +++ b/apps/system/components/kata-os-common/Cargo.toml @@ -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" } diff --git a/apps/system/components/kata-os-common/src/copyregion/Cargo.toml b/apps/system/components/kata-os-common/src/copyregion/Cargo.toml new file mode 100644 index 0000000..8009c33 --- /dev/null +++ b/apps/system/components/kata-os-common/src/copyregion/Cargo.toml @@ -0,0 +1,11 @@ +cargo-features = ["edition2021"] + +[package] +name = "copyregion" +version = "0.1.0" +authors = ["Sam Leffler "] +edition = "2021" + +[dependencies] +log = "0.4" +sel4-sys = { path = "../sel4-sys" } diff --git a/apps/system/components/kata-os-common/src/copyregion/src/lib.rs b/apps/system/components/kata-os-common/src/copyregion/src/lib.rs new file mode 100644 index 0000000..c616e26 --- /dev/null +++ b/apps/system/components/kata-os-common/src/copyregion/src/lib.rs @@ -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(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, +} +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::(), + ) + } + } + + // 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::(), + ) + } + } + + // 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"); + } +} diff --git a/apps/system/components/kata-os-common/src/lib.rs b/apps/system/components/kata-os-common/src/lib.rs index 3fd2634..be1f716 100644 --- a/apps/system/components/kata-os-common/src/lib.rs +++ b/apps/system/components/kata-os-common/src/lib.rs @@ -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;