feat: refactor cap

This commit is contained in:
Paul Pan 2024-04-21 20:22:48 +08:00
parent c371fd543f
commit 5c1e73a4ee
5 changed files with 64 additions and 25 deletions

28
api/src/failure.rs Normal file
View File

@ -0,0 +1,28 @@
use crate::cap::ObjectType;
pub enum Fault {
Ok,
CapFault(CapFault),
}
pub enum CapFault {
// vallina
InvalidRoot,
MissingCapability {
bits_left: usize,
},
DepthMismatch {
bits_found: usize,
bits_left: usize,
},
GuardMismatch {
guard_found: usize,
bits_left: usize,
guard_size: usize,
},
// additional
TypeMismatch {
expected: ObjectType,
found: ObjectType,
},
}

View File

@ -4,3 +4,4 @@
extern crate num_derive;
pub mod cap;
pub mod failure;

View File

@ -1,23 +1,26 @@
use api::cap::ObjectType;
use vspace::addr::PhysAddr;
/// RawCap is the specific implementation of capability which stores in CNode
#[derive(Clone, Copy)]
pub struct RawCap {
/// args: in vanilla seL4 implementation, a cap use two 64-bit words to store all information,
/// but we'll waste some space rather than using bitfield to simplify the implementation
args: [usize; 2],
pub args: [usize; 2],
/// ptr: vanilla seL4 stores the pointer with either higher bits or lower bits cut off,
/// which limits the address space. Use an independent field to store the pointer.
/// Kernel will not manage memory, userspace should pass PhysAddr to kernel
pub ptr: PhysAddr,
/// cap_type: every capability links to one specific object
cap_type: ObjectType,
pub cap_type: ObjectType,
}
impl RawCap {
pub fn new(arg0: usize, arg1: usize, cap_type: ObjectType) -> Self {
pub fn new(arg0: usize, arg1: usize, ptr: PhysAddr, cap_type: ObjectType) -> Self {
Self {
args: [arg0, arg1],
ptr,
cap_type,
}
}
pub fn cap_type(&self) -> ObjectType {
self.cap_type
}
}

View File

@ -14,10 +14,9 @@
*/
use api::cap::ObjectType;
use api::{cap::ObjectType, failure::CapFault};
use cap::RawCap;
use core::cell::Cell;
use core::marker::PhantomData;
use core::{cell::Cell, marker::PhantomData};
pub mod cap;
pub mod null;
@ -25,11 +24,29 @@ pub mod null;
/// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust)
/// 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> {
cap: &'a Cell<RawCap>,
pub struct Cap<'a, T: KernelObject + ?Sized> {
cap: &'a Cell<RawCap>, // use Cell to avoid lifetime issues
cap_type: PhantomData<T>,
}
impl<'a, T: KernelObject + ?Sized> TryFrom<&'a Cell<RawCap>> for Cap<'a, T> {
type Error = CapFault;
fn try_from(new: &'a Cell<RawCap>) -> Result<Self, Self::Error> {
if new.get().cap_type != T::OBJ_TYPE {
Err(CapFault::TypeMismatch {
expected: T::OBJ_TYPE,
found: new.get().cap_type,
})
} else {
Ok(Self {
cap: new,
cap_type: PhantomData,
})
}
}
}
/// KernelObject is the base trait for all kernel objects
pub trait KernelObject {
// this should be optimized by compiler?

View File

@ -1,27 +1,17 @@
use super::cap::RawCap;
use super::{Cap, KernelObject};
use api::cap::ObjectType;
use core::marker::PhantomData;
use vspace::addr::PhysAddr;
/// NullObject is used as empty (capability) slot
pub struct NullObject {}
pub type NullCap<'a> = Cap<'a, NullObject>;
impl KernelObject for NullObject {
const OBJ_TYPE: ObjectType = ObjectType::Null;
}
pub type NullCap<'a> = Cap<'a, NullObject>;
impl<'a> NullCap<'a> {
pub fn mint() -> RawCap {
let cap = RawCap::new(0, 0, ObjectType::Null);
cap
}
pub fn retype<T: KernelObject>(self, new: RawCap) -> Cap<'a, T> {
assert!(T::OBJ_TYPE == new.cap_type());
self.cap.set(new);
Cap {
cap: self.cap,
cap_type: PhantomData,
}
RawCap::new(0, 0, PhysAddr(0), ObjectType::Null)
}
}