mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: add tests for cnode address resolving
This commit is contained in:
parent
067a7996b4
commit
18240fec26
@ -20,6 +20,8 @@ impl Default for ObjectType {
|
||||
}
|
||||
|
||||
impl ObjectType {
|
||||
const CNODE_BITS: usize = 6;
|
||||
|
||||
pub const fn size(&self, user_obj_bits: usize) -> usize {
|
||||
1 << self.bits(user_obj_bits)
|
||||
}
|
||||
@ -28,7 +30,7 @@ impl ObjectType {
|
||||
#![rustfmt::skip]
|
||||
match self {
|
||||
ObjectType::Null => 0, // TODO: fill it!
|
||||
ObjectType::CNode => 0, // TODO: fill it!
|
||||
ObjectType::CNode => Self::CNODE_BITS + user_obj_bits,
|
||||
ObjectType::TCB => 0, // TODO: fill it!
|
||||
ObjectType::SchedCtx => 0, // TODO: fill it!
|
||||
ObjectType::Endpoint => 0, // TODO: fill it!
|
||||
|
@ -12,7 +12,7 @@ use vspace::paging::*;
|
||||
#[thread_local]
|
||||
static KERNEL_PAGETABLE: Mutex<Option<&mut Table>> = Mutex::new(None);
|
||||
|
||||
static KERNEL_ALLOCATOR: Mutex<RamBlock<8>> = Mutex::new(RamBlock::new());
|
||||
pub static KERNEL_ALLOCATOR: Mutex<RamBlock<8>> = Mutex::new(RamBlock::new());
|
||||
|
||||
#[inline]
|
||||
fn alloc_page() -> PhysAddr {
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::objects::null::NullCap;
|
||||
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(Copy, Clone, Default)]
|
||||
#[derive(Copy, Clone, Default, PartialEq, Eq)]
|
||||
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,
|
||||
@ -15,6 +16,8 @@ pub struct RawCap {
|
||||
pub ptr: PhysAddr,
|
||||
/// cap_type: every capability links to one specific object
|
||||
pub cap_type: ObjectType,
|
||||
/// _padding: padding to align the size of RawCap to power of 2
|
||||
pub _padding: [usize; 2],
|
||||
}
|
||||
|
||||
impl RawCap {
|
||||
@ -23,6 +26,7 @@ impl RawCap {
|
||||
args: [arg0, arg1],
|
||||
ptr,
|
||||
cap_type,
|
||||
_padding: [0, 0],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,11 +37,14 @@ pub struct Link {
|
||||
pub next: Option<NonNull<CapEntry>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CapEntry {
|
||||
pub cap: Cell<RawCap>,
|
||||
pub link: Cell<Link>,
|
||||
}
|
||||
|
||||
const_assert_eq!(core::mem::size_of::<CapEntry>(), ObjectType::CNode.size(0));
|
||||
|
||||
impl CapEntry {
|
||||
pub fn new(cap: RawCap) -> Self {
|
||||
Self {
|
||||
@ -47,7 +54,7 @@ impl CapEntry {
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.cap = Cell::new(RawCap::default());
|
||||
self.cap = Cell::new(NullCap::mint());
|
||||
self.link = Cell::new(Link::default());
|
||||
}
|
||||
|
||||
@ -67,3 +74,9 @@ impl CapEntry {
|
||||
self.link.get_mut().next = next;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawCap> for CapEntry {
|
||||
fn from(value: RawCap) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
@ -75,21 +75,21 @@ impl<'a> CNodeCap<'a> {
|
||||
1 << self.radix()
|
||||
}
|
||||
|
||||
fn as_object(&self) -> &CNodeObject {
|
||||
pub fn as_object(&self) -> &CNodeObject {
|
||||
unsafe {
|
||||
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
||||
core::slice::from_raw_parts(virt.as_const_ptr(), self.length())
|
||||
}
|
||||
}
|
||||
|
||||
fn as_object_mut(&mut self) -> &mut CNodeObject {
|
||||
pub fn as_object_mut(&mut self) -> &mut CNodeObject {
|
||||
unsafe {
|
||||
let virt = mmap_phys_to_virt(self.cte.cap.get().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<&CapEntry, CapFault> {
|
||||
pub fn resolve_address_bits(&self, cap_ptr: usize, n_bits: usize) -> Result<&CapEntry, CapFault> {
|
||||
let mut bits_remaining = n_bits;
|
||||
let mut slot = self.cte;
|
||||
|
||||
@ -133,3 +133,153 @@ impl<'a> CNodeCap<'a> {
|
||||
Ok(slot)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::arch::vspace::KERNEL_ALLOCATOR;
|
||||
use crate::objects::cap::CapEntry;
|
||||
use crate::objects::null::NullCap;
|
||||
use core::alloc::Layout;
|
||||
use log::info;
|
||||
|
||||
#[test_case]
|
||||
fn test_cnode_resolve() {
|
||||
let create_cnode = |radix: usize, guard_size: usize, guard: usize| {
|
||||
let size = ObjectType::CNode.size(radix);
|
||||
let layout = Layout::from_size_align(size, 1).unwrap();
|
||||
let ptr = KERNEL_ALLOCATOR.lock().alloc(layout).unwrap();
|
||||
let raw = CNodeCap::mint(radix, guard_size, guard, ptr);
|
||||
CapEntry::new(raw)
|
||||
};
|
||||
|
||||
let cte1 = create_cnode(4, 4, 0b1001);
|
||||
let cte2 = create_cnode(3, 4, 0b0110);
|
||||
let cte3 = create_cnode(2, 4, 0b1010);
|
||||
|
||||
let mut cnode1 = CNodeCap::try_from(&cte1).unwrap();
|
||||
let mut cnode2 = CNodeCap::try_from(&cte2).unwrap();
|
||||
let mut cnode3 = CNodeCap::try_from(&cte3).unwrap();
|
||||
|
||||
cnode1.as_object_mut()[6] = cte2.clone();
|
||||
cnode2.as_object_mut()[1] = cte3.clone();
|
||||
cnode3.as_object_mut()[2] = NullCap::mint().into();
|
||||
cnode3.as_object_mut()[2].cap.update(|mut cap| {
|
||||
cap.args[0] = 0xdeadbeef;
|
||||
cap.args[1] = 0xaa55aa55;
|
||||
cap
|
||||
});
|
||||
|
||||
{
|
||||
// cte2.clone() cte3.clone() should not modify cte itself
|
||||
info!("Testing whether RawCap and Cap held the same cap");
|
||||
assert!(cnode2.cte.cap.get() == cte2.cap.get());
|
||||
assert!(cnode3.cte.cap.get() == cte3.cap.get());
|
||||
}
|
||||
|
||||
let root = cnode1;
|
||||
|
||||
/* Layout:
|
||||
* cnode1: 2^4 slots, 4 bits guard, guard value is 0b1001
|
||||
* cnode2: 2^3 slots, 4 bits guard, guard value is 0b0110
|
||||
* cnode3: 2^2 slots, 4 bits guard, guard value is 0b1010
|
||||
*
|
||||
* root -----> | cnode1 |
|
||||
* 0: | ...... | addr = 0b1001_0110
|
||||
* 6: | cnode2 | -----------------> | cnode2 |
|
||||
* 15: | ...... | 0: | ...... | addr = 0b0110_001
|
||||
* guard: | 0b1001 | 1: | cnode3 | ----------------> | cnode3 |
|
||||
* 7: | ...... | 0: | ...... |
|
||||
* guard: | 0b0110 | 2: | target | addr = 0b1010_10
|
||||
* 3: | ...... |
|
||||
* guard: | 0b1010 |
|
||||
*/
|
||||
|
||||
{
|
||||
// resolve to cte2
|
||||
// * cnode2 addr = 0b1001_0110 = 0x96
|
||||
// * cnode2 length = 8
|
||||
info!("Testing resolve to cte2");
|
||||
let target = root.resolve_address_bits(0x96, 8).unwrap();
|
||||
assert!(target.cap.get() == cte2.cap.get());
|
||||
}
|
||||
|
||||
{
|
||||
// resolve to cte3
|
||||
// * cnode3 addr = 0b1001_0110_0110_001 = 0x4b31
|
||||
// * cnode3 length = 15
|
||||
info!("Testing resolve to cte3");
|
||||
let target = root.resolve_address_bits(0x4b31, 15).unwrap();
|
||||
assert!(target.cap.get() == cte3.cap.get());
|
||||
}
|
||||
|
||||
{
|
||||
// resolve to target
|
||||
// * target addr = 0b1001_0110_0110_001_1010_10 = 0x12cc6a
|
||||
// * target length = 21
|
||||
info!("Testing resolve to target");
|
||||
let target = root.resolve_address_bits(0x12cc6a, 21).unwrap();
|
||||
assert!(target.cap.get().args[0] == 0xdeadbeef);
|
||||
assert!(target.cap.get().args[1] == 0xaa55aa55);
|
||||
}
|
||||
|
||||
{
|
||||
// level_bits > bits_remaining
|
||||
info!("Testing invalid depth (1)");
|
||||
let result = root.resolve_address_bits(0x96, 8 - 1);
|
||||
match result {
|
||||
Err(CapFault::DepthMismatch { bits_found, bits_left }) => {
|
||||
assert_eq!(bits_found, 8);
|
||||
assert_eq!(bits_left, 7);
|
||||
},
|
||||
_ => panic!("not returning CapFault::DepthMismatch"),
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// level_bits > bits_remaining
|
||||
info!("Testing invalid depth (2)");
|
||||
let result = root.resolve_address_bits(0x4b31 >> 1, 15 - 1);
|
||||
match result {
|
||||
Err(CapFault::DepthMismatch { bits_found, bits_left }) => {
|
||||
assert_eq!(bits_found, 7);
|
||||
assert_eq!(bits_left, 6);
|
||||
},
|
||||
_ => panic!("not returning CapFault::DepthMismatch"),
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// guard mismatch
|
||||
// orig: 0b1001_0110_0110_001 = 0x4b31
|
||||
// mod: 0b1001_0110_1110_001 = 0x4b71
|
||||
info!("Testing guard mismatch");
|
||||
let result = root.resolve_address_bits(0x4b71, 15);
|
||||
match result {
|
||||
Err(CapFault::GuardMismatch {
|
||||
bits_left,
|
||||
guard_found,
|
||||
guard_size,
|
||||
}) => {
|
||||
assert_eq!(bits_left, 7);
|
||||
assert_eq!(guard_found, 0b0110);
|
||||
assert_eq!(guard_size, 4);
|
||||
},
|
||||
_ => panic!("not returning CapFault::GuardMismatch"),
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// extra bits
|
||||
info!("Testing extra bits");
|
||||
let result = root.resolve_address_bits(0x96 << 1, 8 + 1);
|
||||
match result {
|
||||
Err(CapFault::DepthMismatch { bits_found, bits_left }) => {
|
||||
assert_eq!(bits_found, 7);
|
||||
assert_eq!(bits_left, 1);
|
||||
},
|
||||
_ => panic!("not returning CapFault::DepthMismatch"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user