mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: add TableCap
This commit is contained in:
parent
8f312909c0
commit
0ee2b996e4
@ -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)
|
||||
|
143
kernel/src/objects/table.rs
Normal file
143
kernel/src/objects/table.rs
Normal file
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user