feat: refactor cap

This commit is contained in:
Paul Pan 2024-04-23 00:48:46 +08:00
parent 7d34dfc2cd
commit cadfafca12
5 changed files with 114 additions and 35 deletions

View File

@ -3,6 +3,7 @@
#![no_main] #![no_main]
// Features // Features
#![feature(asm_const)] #![feature(asm_const)]
#![feature(cell_update)]
#![feature(concat_idents)] #![feature(concat_idents)]
#![feature(const_mut_refs)] #![feature(const_mut_refs)]
#![feature(extern_types)] #![feature(extern_types)]

View File

@ -1,8 +1,9 @@
use api::cap::ObjectType; use api::cap::ObjectType;
use core::{cell::Cell, ptr::NonNull};
use vspace::addr::PhysAddr; use vspace::addr::PhysAddr;
/// RawCap is the specific implementation of capability which stores in CNode /// RawCap is the specific implementation of capability which stores in CNode
#[derive(Clone, Copy, Default)] #[derive(Copy, Clone, Default)]
pub struct RawCap { pub struct RawCap {
// TODO: this could be an enum, figure out a way to do this // 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, /// 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<NonNull<Cell<CapEntry>>>,
pub next: Option<NonNull<Cell<CapEntry>>>,
}
#[derive(Clone, Copy, Default)]
pub struct CapEntry {
pub cap: RawCap,
pub link: Link,
}
pub type CapTableEntry = Cell<CapEntry>;
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<NonNull<Cell<CapEntry>>> {
self.link.prev
}
pub fn next(&self) -> Option<NonNull<Cell<CapEntry>>> {
self.link.next
}
pub fn set_prev(&mut self, prev: Option<NonNull<Cell<CapEntry>>>) {
self.link.prev = prev;
}
pub fn set_next(&mut self, next: Option<NonNull<Cell<CapEntry>>>) {
self.link.next = next;
}
}

View File

@ -1,6 +1,9 @@
use core::cell::Cell; 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 crate::arch::layout::mmap_phys_to_virt;
use api::{cap::ObjectType, error::CapFault}; use api::{cap::ObjectType, error::CapFault};
use utils::MASK; use utils::MASK;
@ -8,7 +11,7 @@ use vspace::addr::{AddressOps, PhysAddr};
/// CNodeObject is a array of Capabilities (`RawCap`) /// CNodeObject is a array of Capabilities (`RawCap`)
/// The size of the array is stored in CNodeCap /// The size of the array is stored in CNodeCap
pub type CNodeObject = [Cell<RawCap>]; pub type CNodeObject = [CapTableEntry];
impl KernelObject for CNodeObject { impl KernelObject for CNodeObject {
const OBJ_TYPE: ObjectType = ObjectType::CNode; const OBJ_TYPE: ObjectType = ObjectType::CNode;
@ -41,29 +44,29 @@ impl<'a> CNodeCap<'a> {
let arg0 = ((radix & Self::RADIX_MASK) << Self::RADIX_OFFSET) let arg0 = ((radix & Self::RADIX_MASK) << Self::RADIX_OFFSET)
| ((guard_size & Self::GUARD_SIZE_MASK) << Self::GUARD_SIZE_OFFSET); | ((guard_size & Self::GUARD_SIZE_MASK) << Self::GUARD_SIZE_OFFSET);
let arg1 = guard; let arg1 = guard;
let cap: RawCap = RawCap::new(arg0, arg1, ptr, ObjectType::CNode);
let cap = RawCap::new(arg0, arg1, ptr, ObjectType::CNode); // init memory
CNodeCap::try_from(&Cell::new(cap)) let cte = super::cap::CapEntry::new(cap);
CNodeCap::try_from(&Cell::new(cte))
.unwrap() .unwrap()
.as_object() .as_object_mut()
.iter() .iter_mut()
.for_each(|cell| { .for_each(|cap| cap.get_mut().init());
cell.set(RawCap::default());
});
cap cap
} }
fn radix(&self) -> usize { 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 { 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 { fn guard(&self) -> usize {
self.cap.get().args[1] self.cte.get().cap.args[1]
} }
/// CNodeObject length /// CNodeObject length
@ -76,14 +79,21 @@ impl<'a> CNodeCap<'a> {
fn as_object(&self) -> &CNodeObject { fn as_object(&self) -> &CNodeObject {
unsafe { 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()) core::slice::from_raw_parts(virt.as_const_ptr(), self.length())
} }
} }
fn resolve_address_bits(&self, cap_ptr: usize, n_bits: usize) -> Result<&Cell<RawCap>, 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 bits_remaining = n_bits;
let mut slot = self.cap; let mut slot = self.cte;
while let Ok(cnode) = CNodeCap::try_from(slot) { while let Ok(cnode) = CNodeCap::try_from(slot) {
let radix_bits = cnode.radix(); let radix_bits = cnode.radix();

View File

@ -18,8 +18,8 @@ use api::{
cap::ObjectType, cap::ObjectType,
error::{SysError, SysResult}, error::{SysError, SysResult},
}; };
use cap::RawCap; use cap::CapTableEntry;
use core::{cell::Cell, marker::PhantomData}; use core::{marker::PhantomData, ptr::NonNull};
pub mod cap; pub mod cap;
pub mod cnode; pub mod cnode;
@ -30,25 +30,45 @@ pub mod untyped;
/// For the typed objects, we should bound it with an empty traits `KernelObject` /// 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) /// And for those objects, at least implement `mint` method and `decodeInvocation` (not enforcing in `KernelObject` for complexity)
pub struct Cap<'a, T: KernelObject + ?Sized> { pub struct Cap<'a, T: KernelObject + ?Sized> {
cap: &'a Cell<RawCap>, // use Cell to avoid lifetime issues cte: &'a CapTableEntry,
cap_type: PhantomData<T>, cap_type: PhantomData<T>,
} }
impl<'a, T: KernelObject + ?Sized> TryFrom<&'a Cell<RawCap>> for Cap<'a, T> { impl<'a, T: KernelObject + ?Sized> TryFrom<&'a CapTableEntry> for Cap<'a, T> {
type Error = SysError; type Error = SysError;
fn try_from(new: &'a Cell<RawCap>) -> SysResult<Self> { fn try_from(new: &'a CapTableEntry) -> SysResult<Self> {
if new.get().cap_type != T::OBJ_TYPE { if new.get().cap.cap_type != T::OBJ_TYPE {
Err(SysError::CapTypeMismatch) Err(SysError::CapTypeMismatch)
} else { } else {
Ok(Self { Ok(Self {
cap: new, cte: new,
cap_type: PhantomData, 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 /// KernelObject is the base trait for all kernel objects
pub trait KernelObject { pub trait KernelObject {
// this should be optimized by compiler? // this should be optimized by compiler?

View File

@ -1,4 +1,4 @@
use super::cap::RawCap; use super::cap::{CapEntry, RawCap};
use super::cnode::{CNodeCap, CNodeObject}; use super::cnode::{CNodeCap, CNodeObject};
use super::null::NullCap; use super::null::NullCap;
use super::{Cap, KernelObject}; use super::{Cap, KernelObject};
@ -43,26 +43,29 @@ impl UntypedCap<'_> {
} }
fn free_offset(&self) -> usize { fn free_offset(&self) -> usize {
self.cap.get().args[0] self.cte.get().cap.args[0]
} }
fn set_free_offset(&self, free_offset: usize) { fn set_free_offset(&mut self, free_offset: usize) {
self.cap.get().args[0] = free_offset; self.cte.update(|mut c| {
c.cap.args[0] = free_offset;
c
});
} }
fn is_device(&self) -> bool { 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 { 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 { fn block_size(&self) -> usize {
1 << self.block_bits() 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` * vallina seL4: `decode_untiped_invocation`
* - _service CPTR to an untyped object. * - _service CPTR to an untyped object.
@ -85,7 +88,7 @@ impl UntypedCap<'_> {
// Make sure all slots are empty // Make sure all slots are empty
slots slots
.iter() .iter()
.any(|cap: &core::cell::Cell<RawCap>| NullCap::try_from(cap).is_err()) .any(|cte| NullCap::try_from(cte).is_err())
.then_ok((), SysError::CapTypeMismatch)?; .then_ok((), SysError::CapTypeMismatch)?;
// Start allocating from free_offset // Start allocating from free_offset
@ -108,8 +111,8 @@ impl UntypedCap<'_> {
} }
// Create new capabilities in slot // Create new capabilities in slot
for (i, slot) in slots.iter().enumerate() { for (i, slot) in slots.iter_mut().enumerate() {
let addr = self.cap.get().ptr + start_offset + i * obj_size; let addr = self.cte.get().cap.ptr + start_offset + i * obj_size;
let new_cap = match obj_type { let new_cap = match obj_type {
ObjectType::Untyped => UntypedCap::mint(0, obj_type.bits(user_obj_bits), self.is_device(), addr), 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), ObjectType::CNode => CNodeCap::mint(user_obj_bits, 0, 0, addr),
@ -117,8 +120,8 @@ impl UntypedCap<'_> {
_ => return Err(SysError::InvalidArgument), _ => return Err(SysError::InvalidArgument),
}; };
slot.set(new_cap); slot.get_mut().cap = new_cap;
// TODO: insert into linked list self.append(slot);
} }
// Update free_offset // Update free_offset