From 0ee2b996e4a29bde1d42fb676903aa253327a213 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Mon, 6 May 2024 01:13:24 +0800 Subject: [PATCH] feat: add TableCap --- kernel/src/objects/mod.rs | 1 + kernel/src/objects/table.rs | 143 ++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 kernel/src/objects/table.rs diff --git a/kernel/src/objects/mod.rs b/kernel/src/objects/mod.rs index c365f0c..781ce96 100644 --- a/kernel/src/objects/mod.rs +++ b/kernel/src/objects/mod.rs @@ -25,6 +25,7 @@ pub mod cap; pub mod cnode; pub mod frame; pub mod null; +pub mod table; pub mod untyped; /// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust) diff --git a/kernel/src/objects/table.rs b/kernel/src/objects/table.rs new file mode 100644 index 0000000..f02d53c --- /dev/null +++ b/kernel/src/objects/table.rs @@ -0,0 +1,143 @@ +use crate::arch::{layout::mmap_phys_to_virt, vspace::Table}; + +use super::{cap::RawCap, Cap, KernelObject}; +use uapi::{ + cap::ObjectType, + error::{SysError, SysResult}, + vspace::MapAttr, +}; +use utils::MASK; +use vspace::{ + addr::{AddressOps, PhysAddr, VirtAddr}, + paging::{EntryOps, PageError, TableLevel, TableOps}, +}; + +/// TableObject is an object that represents a page table +pub type TableObject = Table; +impl KernelObject for TableObject { + const OBJ_TYPE: ObjectType = ObjectType::PageTable; +} + +/* + * in vanilla seL4, TableCap layout: + * > args[0]: | cap_tag | unused | is_mapped | mapped_addr | + * > | [63:59] | [58:40] | [39] | [38:0] | + * > args[1]: | asid | base_ptr | unused | + * > | [63:48] | [47:9] | [8:0] | + * + * in our implementation, TableCap layout: + * > args[0]: [asid, is_mapped] + * > args[1]: mapped_addr + * > ptr: base_ptr + * > cap_type: cap_tag + */ + +// TODO: we are not using ASID for now, implement ASIDPool or find out a better way to handle ASID + +pub type TableCap<'a> = Cap<'a, TableObject>; + +impl<'a> TableCap<'a> { + const ASID_BITS: usize = 16; + const ASID_MASK: usize = MASK!(Self::ASID_BITS); + const ASID_OFFSET: usize = 32; + const IS_MAPPED_BITS: usize = 1; + const IS_MAPPED_MASK: usize = MASK!(Self::IS_MAPPED_BITS); + const IS_MAPPED_OFFSET: usize = 0; + + pub fn mint(ptr: PhysAddr) -> RawCap { + RawCap::new(0, 0, ptr, ObjectType::PageTable) + } + + pub fn is_mapped(&self) -> bool { + let bits = (self.cte.cap.get().args[0] >> Self::IS_MAPPED_OFFSET) & Self::IS_MAPPED_MASK; + bits != 0 + } + + pub fn set_mapped(&self, mapped: bool) { + self.cte.cap.update(|mut cap| { + let is_mapped = if mapped { 1 } else { 0 }; + let bits = (is_mapped & Self::IS_MAPPED_MASK) << Self::IS_MAPPED_OFFSET; + let arg0 = cap.args[0] & !(Self::IS_MAPPED_MASK << Self::IS_MAPPED_OFFSET); + cap.args[0] = arg0 | bits; + cap + }); + } + + pub fn asid(&self) -> usize { + (self.cte.cap.get().args[0] >> Self::ASID_OFFSET) & Self::ASID_MASK + } + + pub fn set_mapped_asid(&self, asid: usize) { + self.cte.cap.update(|mut cap| { + let bits = (asid & Self::ASID_MASK) << Self::ASID_OFFSET; + let arg0 = cap.args[0] & !(Self::ASID_MASK << Self::ASID_OFFSET); + cap.args[0] = arg0 | bits; + cap + }); + } + + pub fn mapped_vaddr(&self) -> VirtAddr { + VirtAddr(self.cte.cap.get().args[1]) + } + + pub fn set_mapped_vaddr(&self, vaddr: VirtAddr) { + self.cte.cap.update(|mut cap| { + cap.args[1] = vaddr.0; + cap + }); + } + + pub fn as_object(&self) -> &TableObject { + unsafe { + let virt = mmap_phys_to_virt(self.cte.cap.get().ptr); + Table::new(virt) + } + } + + pub fn as_object_mut(&mut self) -> &mut TableObject { + unsafe { + let virt = mmap_phys_to_virt(self.cte.cap.get().ptr); + Table::new(virt) + } + } + + pub fn clear(&self) { + let array: &mut [u8] = unsafe { + let virt = mmap_phys_to_virt(self.cte.cap.get().ptr); + core::slice::from_raw_parts_mut(virt.as_mut_ptr(), Table::TABLE_SIZE) + }; + array.fill(0); + } + + pub fn map_table(&self, root: &mut Table, vaddr: VirtAddr, level: TableLevel) -> SysResult { + root.map(vaddr, self.cte.cap.get().ptr, MapAttr::PAGE_TABLE, level) + .map_err(|e| match e { + PageError::AlreadyMapped(_) => SysError::AlreadyMapped, + PageError::MissingEntry(_) => SysError::MissingEntry, + })?; + + self.set_mapped_asid(0); + self.set_mapped_vaddr(vaddr); + + Ok(()) + } + + pub fn unmap(&self, root: &mut Table) -> SysResult { + let vaddr = self.mapped_vaddr(); + if vaddr.0 == 0 { + return Err(SysError::NotMapped); + } + + match root.lookup_mut(self.mapped_vaddr()) { + Some(entry) if !entry.is_leaf() && entry.addr() == self.cte.cap.get().ptr => { + entry.set_addr(PhysAddr::default()); + entry.set_attr(MapAttr::empty()); + + self.set_mapped_asid(0); + self.set_mapped_vaddr(VirtAddr(0)); + Ok(()) + }, + _ => Err(SysError::MissingEntry), + } + } +}