From cadfafca126b02bcf2d97b6acc71fda44bb7853e Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Tue, 23 Apr 2024 00:48:46 +0800 Subject: [PATCH] feat: refactor cap --- kernel/src/main.rs | 1 + kernel/src/objects/cap.rs | 47 ++++++++++++++++++++++++++++++++++- kernel/src/objects/cnode.rs | 40 ++++++++++++++++++----------- kernel/src/objects/mod.rs | 34 +++++++++++++++++++------ kernel/src/objects/untyped.rs | 27 +++++++++++--------- 5 files changed, 114 insertions(+), 35 deletions(-) diff --git a/kernel/src/main.rs b/kernel/src/main.rs index f2a7808..525c3ff 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -3,6 +3,7 @@ #![no_main] // Features #![feature(asm_const)] +#![feature(cell_update)] #![feature(concat_idents)] #![feature(const_mut_refs)] #![feature(extern_types)] diff --git a/kernel/src/objects/cap.rs b/kernel/src/objects/cap.rs index 1b7db6c..21d2549 100644 --- a/kernel/src/objects/cap.rs +++ b/kernel/src/objects/cap.rs @@ -1,8 +1,9 @@ use api::cap::ObjectType; +use core::{cell::Cell, ptr::NonNull}; use vspace::addr::PhysAddr; /// RawCap is the specific implementation of capability which stores in CNode -#[derive(Clone, Copy, Default)] +#[derive(Copy, Clone, Default)] pub struct RawCap { // TODO: this could be an enum, figure out a way to do this /// args: in vanilla seL4 implementation, a cap use two 64-bit words to store all information, @@ -25,3 +26,47 @@ impl RawCap { } } } + +#[derive(Copy, Clone, Default)] +pub struct Link { + pub prev: Option>>, + pub next: Option>>, +} + +#[derive(Clone, Copy, Default)] +pub struct CapEntry { + pub cap: RawCap, + pub link: Link, +} + +pub type CapTableEntry = Cell; + +impl CapEntry { + pub fn new(cap: RawCap) -> Self { + Self { + cap: cap, + link: Link::default(), + } + } + + pub fn init(&mut self) { + self.cap = RawCap::default(); + self.link = Link::default(); + } + + pub fn prev(&self) -> Option>> { + self.link.prev + } + + pub fn next(&self) -> Option>> { + self.link.next + } + + pub fn set_prev(&mut self, prev: Option>>) { + self.link.prev = prev; + } + + pub fn set_next(&mut self, next: Option>>) { + self.link.next = next; + } +} diff --git a/kernel/src/objects/cnode.rs b/kernel/src/objects/cnode.rs index 942d762..0999311 100644 --- a/kernel/src/objects/cnode.rs +++ b/kernel/src/objects/cnode.rs @@ -1,6 +1,9 @@ use core::cell::Cell; -use super::{cap::RawCap, Cap, KernelObject}; +use super::{ + cap::{CapTableEntry, RawCap}, + Cap, KernelObject, +}; use crate::arch::layout::mmap_phys_to_virt; use api::{cap::ObjectType, error::CapFault}; use utils::MASK; @@ -8,7 +11,7 @@ use vspace::addr::{AddressOps, PhysAddr}; /// CNodeObject is a array of Capabilities (`RawCap`) /// The size of the array is stored in CNodeCap -pub type CNodeObject = [Cell]; +pub type CNodeObject = [CapTableEntry]; impl KernelObject for CNodeObject { const OBJ_TYPE: ObjectType = ObjectType::CNode; @@ -41,29 +44,29 @@ impl<'a> CNodeCap<'a> { let arg0 = ((radix & Self::RADIX_MASK) << Self::RADIX_OFFSET) | ((guard_size & Self::GUARD_SIZE_MASK) << Self::GUARD_SIZE_OFFSET); let arg1 = guard; + let cap: RawCap = RawCap::new(arg0, arg1, ptr, ObjectType::CNode); - let cap = RawCap::new(arg0, arg1, ptr, ObjectType::CNode); - CNodeCap::try_from(&Cell::new(cap)) + // init memory + let cte = super::cap::CapEntry::new(cap); + CNodeCap::try_from(&Cell::new(cte)) .unwrap() - .as_object() - .iter() - .for_each(|cell| { - cell.set(RawCap::default()); - }); + .as_object_mut() + .iter_mut() + .for_each(|cap| cap.get_mut().init()); cap } fn radix(&self) -> usize { - (self.cap.get().args[0] >> Self::RADIX_OFFSET) & Self::RADIX_MASK + (self.cte.get().cap.args[0] >> Self::RADIX_OFFSET) & Self::RADIX_MASK } fn guard_size(&self) -> usize { - (self.cap.get().args[0] >> Self::GUARD_SIZE_OFFSET) & Self::GUARD_SIZE_MASK + (self.cte.get().cap.args[0] >> Self::GUARD_SIZE_OFFSET) & Self::GUARD_SIZE_MASK } fn guard(&self) -> usize { - self.cap.get().args[1] + self.cte.get().cap.args[1] } /// CNodeObject length @@ -76,14 +79,21 @@ impl<'a> CNodeCap<'a> { fn as_object(&self) -> &CNodeObject { unsafe { - let virt = mmap_phys_to_virt(self.cap.get().ptr); + let virt = mmap_phys_to_virt(self.cte.get().cap.ptr); core::slice::from_raw_parts(virt.as_const_ptr(), self.length()) } } - fn resolve_address_bits(&self, cap_ptr: usize, n_bits: usize) -> Result<&Cell, CapFault> { + fn as_object_mut(&mut self) -> &mut CNodeObject { + unsafe { + let virt = mmap_phys_to_virt(self.cte.get().cap.ptr); + core::slice::from_raw_parts_mut(virt.as_mut_ptr(), self.length()) + } + } + + fn resolve_address_bits(&self, cap_ptr: usize, n_bits: usize) -> Result<&CapTableEntry, CapFault> { let mut bits_remaining = n_bits; - let mut slot = self.cap; + let mut slot = self.cte; while let Ok(cnode) = CNodeCap::try_from(slot) { let radix_bits = cnode.radix(); diff --git a/kernel/src/objects/mod.rs b/kernel/src/objects/mod.rs index f66ba6c..7f1b279 100644 --- a/kernel/src/objects/mod.rs +++ b/kernel/src/objects/mod.rs @@ -18,8 +18,8 @@ use api::{ cap::ObjectType, error::{SysError, SysResult}, }; -use cap::RawCap; -use core::{cell::Cell, marker::PhantomData}; +use cap::CapTableEntry; +use core::{marker::PhantomData, ptr::NonNull}; pub mod cap; pub mod cnode; @@ -30,25 +30,45 @@ pub mod untyped; /// For the typed objects, we should bound it with an empty traits `KernelObject` /// And for those objects, at least implement `mint` method and `decodeInvocation` (not enforcing in `KernelObject` for complexity) pub struct Cap<'a, T: KernelObject + ?Sized> { - cap: &'a Cell, // use Cell to avoid lifetime issues + cte: &'a CapTableEntry, cap_type: PhantomData, } -impl<'a, T: KernelObject + ?Sized> TryFrom<&'a Cell> for Cap<'a, T> { +impl<'a, T: KernelObject + ?Sized> TryFrom<&'a CapTableEntry> for Cap<'a, T> { type Error = SysError; - fn try_from(new: &'a Cell) -> SysResult { - if new.get().cap_type != T::OBJ_TYPE { + fn try_from(new: &'a CapTableEntry) -> SysResult { + if new.get().cap.cap_type != T::OBJ_TYPE { Err(SysError::CapTypeMismatch) } else { Ok(Self { - cap: new, + cte: new, cap_type: PhantomData, }) } } } +impl<'a, T: KernelObject + ?Sized> Cap<'a, T> { + pub fn append(&mut self, new: &mut CapTableEntry) { + let next = self.cte.get().next(); + + // update new cap's link + new.get_mut().set_prev(Some(NonNull::from(self.cte))); + new.get_mut().set_next(next); + + // record new cap's addr + let new_addr = Some(NonNull::from(new)); + + // update next cap's link.prev + next.map(|mut next| unsafe { next.as_mut().get().set_prev(new_addr) }); + + // update self's link.next + let mut raw = self.cte.get(); + raw.set_next(new_addr); + } +} + /// KernelObject is the base trait for all kernel objects pub trait KernelObject { // this should be optimized by compiler? diff --git a/kernel/src/objects/untyped.rs b/kernel/src/objects/untyped.rs index 1286c31..9b09fb3 100644 --- a/kernel/src/objects/untyped.rs +++ b/kernel/src/objects/untyped.rs @@ -1,4 +1,4 @@ -use super::cap::RawCap; +use super::cap::{CapEntry, RawCap}; use super::cnode::{CNodeCap, CNodeObject}; use super::null::NullCap; use super::{Cap, KernelObject}; @@ -43,26 +43,29 @@ impl UntypedCap<'_> { } fn free_offset(&self) -> usize { - self.cap.get().args[0] + self.cte.get().cap.args[0] } - fn set_free_offset(&self, free_offset: usize) { - self.cap.get().args[0] = free_offset; + fn set_free_offset(&mut self, free_offset: usize) { + self.cte.update(|mut c| { + c.cap.args[0] = free_offset; + c + }); } fn is_device(&self) -> bool { - (self.cap.get().args[1] >> 6) & 1 == 1 + (self.cte.get().cap.args[1] >> 6) & 1 == 1 } fn block_bits(&self) -> usize { - self.cap.get().args[1] & MASK!(6) + self.cte.get().cap.args[1] & MASK!(6) } fn block_size(&self) -> usize { 1 << self.block_bits() } - pub fn retype(&self, obj_type: ObjectType, user_obj_bits: usize, slots: &CNodeObject) -> SysResult<()> { + pub fn retype(&mut self, obj_type: ObjectType, user_obj_bits: usize, slots: &mut CNodeObject) -> SysResult<()> { /* * vallina seL4: `decode_untiped_invocation` * - _service CPTR to an untyped object. @@ -85,7 +88,7 @@ impl UntypedCap<'_> { // Make sure all slots are empty slots .iter() - .any(|cap: &core::cell::Cell| NullCap::try_from(cap).is_err()) + .any(|cte| NullCap::try_from(cte).is_err()) .then_ok((), SysError::CapTypeMismatch)?; // Start allocating from free_offset @@ -108,8 +111,8 @@ impl UntypedCap<'_> { } // Create new capabilities in slot - for (i, slot) in slots.iter().enumerate() { - let addr = self.cap.get().ptr + start_offset + i * obj_size; + for (i, slot) in slots.iter_mut().enumerate() { + let addr = self.cte.get().cap.ptr + start_offset + i * obj_size; let new_cap = match obj_type { ObjectType::Untyped => UntypedCap::mint(0, obj_type.bits(user_obj_bits), self.is_device(), addr), ObjectType::CNode => CNodeCap::mint(user_obj_bits, 0, 0, addr), @@ -117,8 +120,8 @@ impl UntypedCap<'_> { _ => return Err(SysError::InvalidArgument), }; - slot.set(new_cap); - // TODO: insert into linked list + slot.get_mut().cap = new_cap; + self.append(slot); } // Update free_offset