mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
12 Commits
d2155ed7cf
...
0ee2b996e4
Author | SHA1 | Date | |
---|---|---|---|
0ee2b996e4 | |||
8f312909c0 | |||
c710cdcd15 | |||
f0891ff87d | |||
e46ca5a288 | |||
2db111e730 | |||
aaf9cfc5a0 | |||
5dfe3888e9 | |||
f577370ee7 | |||
a65176bc57 | |||
ea98eb5c61 | |||
36b409444d |
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Qemu
|
||||
uses: ConorMacBride/install-package@v1
|
||||
|
19
Cargo.lock
generated
19
Cargo.lock
generated
@ -18,14 +18,6 @@ dependencies = [
|
||||
"vspace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.2.0"
|
||||
@ -105,7 +97,6 @@ name = "kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"allocator",
|
||||
"api",
|
||||
"bitflags 2.5.0",
|
||||
"cfg-if",
|
||||
"fdt",
|
||||
@ -116,6 +107,7 @@ dependencies = [
|
||||
"sbi-rt",
|
||||
"spin",
|
||||
"static_assertions",
|
||||
"uapi",
|
||||
"uart_16550",
|
||||
"utils",
|
||||
"vspace",
|
||||
@ -256,6 +248,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uapi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"vspace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uart_16550"
|
||||
version = "0.3.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["api", "kernel", "lib/*"]
|
||||
members = ["kernel", "lib/*", "uapi"]
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
@ -20,8 +20,8 @@ riscv = []
|
||||
"riscv.board.virt" = ["riscv.riscv64"]
|
||||
|
||||
[dependencies]
|
||||
uapi = { path = "../uapi" }
|
||||
allocator = { path = "../lib/allocator" }
|
||||
api = { path = "../api" }
|
||||
utils = { path = "../lib/utils", default-features = false }
|
||||
vspace = { path = "../lib/vspace", default-features = false }
|
||||
|
||||
|
@ -13,7 +13,7 @@ impl TimerOps for Timer {
|
||||
|
||||
// enable timer interrupt and set next tick
|
||||
unsafe { riscv::register::sie::set_stimer() }
|
||||
Self::tick();
|
||||
Self::set_next();
|
||||
info!("[Timer] begin to tick");
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ impl TimerOps for Timer {
|
||||
riscv::register::time::read64()
|
||||
}
|
||||
|
||||
fn tick() {
|
||||
fn set_next() {
|
||||
sbi_rt::set_timer(Self::read_cycle() + TIMER_TICKS);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ fn trap_handler(tf: &mut TrapContext, from_kernel: bool) {
|
||||
|
||||
match scause.cause() {
|
||||
T::Interrupt(I::SupervisorTimer) => {
|
||||
Timer::do_tick();
|
||||
|
||||
if !from_kernel {
|
||||
SCHEDULER.schedule()
|
||||
}
|
||||
@ -61,7 +63,7 @@ fn trap_handler(tf: &mut TrapContext, from_kernel: bool) {
|
||||
_ => panic_fatal!("Unhandled Trap"),
|
||||
}
|
||||
|
||||
Timer::tick();
|
||||
Timer::set_next();
|
||||
trace!("[Trap] exiting...");
|
||||
}
|
||||
|
||||
|
@ -3,4 +3,6 @@ mod table;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
pub use table::Table;
|
||||
pub use traits::*;
|
||||
pub use utils::*;
|
||||
|
@ -11,6 +11,7 @@ pub struct Table {
|
||||
}
|
||||
|
||||
assert_eq_size!(Table, [u8; PAGE_SIZE]);
|
||||
const_assert_eq!(core::mem::size_of::<Table>(), Table::TABLE_SIZE);
|
||||
|
||||
impl Table {
|
||||
fn lookup_mut_internal(&mut self, vaddr: VirtAddr) -> (&mut Entry, TableLevel) {
|
||||
@ -46,6 +47,7 @@ impl TableOps for Table {
|
||||
|
||||
#[cfg(feature = "riscv.pagetable.sv39")]
|
||||
const MAX_PAGE_SIZE: TableLevel = TableLevel::Level2;
|
||||
const TABLE_SIZE: usize = PAGE_SIZE;
|
||||
|
||||
unsafe fn new(location: VirtAddr) -> &'static mut Self {
|
||||
assert!(location.is_aligned(PAGE_SIZE));
|
||||
|
@ -5,13 +5,9 @@
|
||||
#![feature(asm_const)]
|
||||
#![feature(cell_update)]
|
||||
#![feature(concat_idents)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(fn_align)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(thread_local)]
|
||||
// Test Infrastructure
|
||||
#![feature(custom_test_frameworks)]
|
||||
@ -19,6 +15,7 @@
|
||||
#![reexport_test_harness_main = "test_main"]
|
||||
// no noisy dead_code warnings
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::identity_op)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::objects::null::NullCap;
|
||||
use api::cap::ObjectType;
|
||||
use core::cell::Cell;
|
||||
use uapi::cap::ObjectType;
|
||||
use utils::{
|
||||
linked_list::{Link, LinkHelper},
|
||||
LinkHelperImpl,
|
||||
|
@ -3,7 +3,7 @@ use super::{
|
||||
Cap, KernelObject,
|
||||
};
|
||||
use crate::arch::layout::mmap_phys_to_virt;
|
||||
use api::{cap::ObjectType, error::CapFault};
|
||||
use uapi::{cap::ObjectType, error::CapFault};
|
||||
use utils::MASK;
|
||||
use vspace::addr::{AddressOps, PhysAddr};
|
||||
|
||||
|
174
kernel/src/objects/frame.rs
Normal file
174
kernel/src/objects/frame.rs
Normal file
@ -0,0 +1,174 @@
|
||||
use super::{cap::RawCap, Cap, KernelObject};
|
||||
use crate::{
|
||||
arch::{
|
||||
layout::mmap_phys_to_virt,
|
||||
vspace::{Table, TableLevelSize},
|
||||
},
|
||||
objects::cap::CapEntry,
|
||||
};
|
||||
use uapi::{
|
||||
cap::ObjectType,
|
||||
error::{SysError, SysResult},
|
||||
};
|
||||
use utils::MASK;
|
||||
use vspace::{
|
||||
addr::{AddressOps, PhysAddr, VirtAddr},
|
||||
paging::{EntryOps, MapAttr, PageError, TableLevel, TableOps},
|
||||
};
|
||||
|
||||
/// FrameObject refers to a region of physical memory, aka leaf PTE in pagetable
|
||||
pub type FrameObject = [u8];
|
||||
impl KernelObject for FrameObject {
|
||||
const OBJ_TYPE: ObjectType = ObjectType::Frame;
|
||||
}
|
||||
|
||||
/*
|
||||
* in vanilla seL4, FrameCap layout:
|
||||
* > args[0]: | cap_tag | frame_size | vm_right | is_device | mapped_addr |
|
||||
* > | [63:59] | [58:57] | [56:55] | [54] | [53:0] |
|
||||
* > args[1]: | asid | base_ptr | unused |
|
||||
* > | [63:48] | [47:9] | [8:0] |
|
||||
*
|
||||
* in our implementation, FrameCap layout:
|
||||
* > args[0]: [asid, frame_size, is_device, vm_right]
|
||||
* > 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 FrameCap<'a> = Cap<'a, FrameObject>;
|
||||
|
||||
const_assert!(FrameCap::ASID_OFFSET >= FrameCap::FRAME_SIZE_BITS + FrameCap::FRAME_SIZE_OFFSET);
|
||||
const_assert!((1 << FrameCap::VM_RIGHT_BITS) >= MapAttr::all().bits());
|
||||
|
||||
impl<'a> FrameCap<'a> {
|
||||
const ASID_BITS: usize = 16;
|
||||
const ASID_MASK: usize = MASK!(Self::ASID_BITS);
|
||||
const ASID_OFFSET: usize = 32;
|
||||
const FRAME_SIZE_BITS: usize = 6;
|
||||
const FRAME_SIZE_MASK: usize = MASK!(Self::FRAME_SIZE_BITS);
|
||||
const FRAME_SIZE_OFFSET: usize = Self::IS_DEVICE_BITS + Self::IS_DEVICE_OFFSET;
|
||||
const IS_DEVICE_BITS: usize = 1;
|
||||
const IS_DEVICE_MASK: usize = MASK!(Self::IS_DEVICE_BITS);
|
||||
const IS_DEVICE_OFFSET: usize = Self::VM_RIGHT_BITS + Self::VM_RIGHT_OFFSET;
|
||||
const VM_RIGHT_BITS: usize = 5;
|
||||
const VM_RIGHT_MASK: usize = MASK!(Self::VM_RIGHT_BITS);
|
||||
const VM_RIGHT_OFFSET: usize = 0;
|
||||
|
||||
pub fn mint(ptr: PhysAddr, size: TableLevel, attr: MapAttr, is_device: bool) -> RawCap {
|
||||
let size_bits = size.level_size().ilog2() as usize;
|
||||
debug_assert!(size_bits <= FrameCap::FRAME_SIZE_BITS);
|
||||
|
||||
// TODO: support huge page
|
||||
assert!(size == TableLevel::Level0, "only support leaf page for now");
|
||||
|
||||
let arg0 = 0
|
||||
| ((attr.bits() & Self::VM_RIGHT_MASK) << Self::VM_RIGHT_OFFSET)
|
||||
| ((is_device as usize & Self::IS_DEVICE_MASK) << Self::IS_DEVICE_OFFSET)
|
||||
| ((size_bits & Self::FRAME_SIZE_MASK) << Self::FRAME_SIZE_OFFSET);
|
||||
let cap = RawCap::new(arg0, 0, ptr, ObjectType::Frame);
|
||||
|
||||
// clear memory
|
||||
let cte = CapEntry::new(cap);
|
||||
FrameCap::try_from(&cte).unwrap().clear(None);
|
||||
|
||||
cap
|
||||
}
|
||||
|
||||
pub fn attr(&self) -> MapAttr {
|
||||
let bits = (self.cte.cap.get().args[0] >> Self::VM_RIGHT_OFFSET) & Self::VM_RIGHT_MASK;
|
||||
MapAttr::from_bits_truncate(bits)
|
||||
}
|
||||
|
||||
pub fn is_device(&self) -> bool {
|
||||
let bits = (self.cte.cap.get().args[0] >> Self::IS_DEVICE_OFFSET) & Self::IS_DEVICE_MASK;
|
||||
bits != 0
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
let bits = (self.cte.cap.get().args[0] >> Self::FRAME_SIZE_OFFSET) & Self::FRAME_SIZE_MASK;
|
||||
1 << bits
|
||||
}
|
||||
|
||||
pub fn mapped_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 asid = (asid & Self::ASID_MASK) << Self::ASID_OFFSET;
|
||||
let arg0 = cap.args[0] & !(Self::ASID_MASK << Self::ASID_OFFSET);
|
||||
cap.args[0] = arg0 | asid;
|
||||
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) -> &FrameObject {
|
||||
unsafe {
|
||||
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
||||
core::slice::from_raw_parts(virt.as_const_ptr(), self.size())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_object_mut(&mut self) -> &mut FrameObject {
|
||||
unsafe {
|
||||
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
||||
core::slice::from_raw_parts_mut(virt.as_mut_ptr(), self.size())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, fill: Option<u8>) {
|
||||
if self.is_device() {
|
||||
return;
|
||||
}
|
||||
self.as_object_mut().fill(fill.unwrap_or(0));
|
||||
}
|
||||
|
||||
pub fn map_page(&self, root: &mut Table, vaddr: VirtAddr, attr: MapAttr) -> SysResult {
|
||||
let masked_attr = attr & self.attr();
|
||||
|
||||
// TODO: support huge page
|
||||
root.map(vaddr, self.cte.cap.get().ptr, masked_attr, TableLevel::Level0)
|
||||
.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),
|
||||
}
|
||||
}
|
||||
}
|
@ -14,16 +14,18 @@
|
||||
|
||||
*/
|
||||
|
||||
use api::{
|
||||
use cap::CapEntry;
|
||||
use core::{marker::PhantomData, ptr::NonNull};
|
||||
use uapi::{
|
||||
cap::ObjectType,
|
||||
error::{SysError, SysResult},
|
||||
};
|
||||
use cap::CapEntry;
|
||||
use core::{marker::PhantomData, ptr::NonNull};
|
||||
|
||||
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)
|
||||
@ -51,7 +53,7 @@ impl<'a, T: KernelObject + ?Sized> TryFrom<&'a CapEntry> for Cap<'a, T> {
|
||||
|
||||
impl<'a, T: KernelObject + ?Sized> Cap<'a, T> {
|
||||
pub fn append(&mut self, new: &mut CapEntry) {
|
||||
let next = self.cte.link.next();
|
||||
let next = self.cte.link.next_raw();
|
||||
|
||||
// update new cap's link
|
||||
new.link.set_prev(Some(NonNull::from(self.cte)));
|
||||
@ -72,6 +74,5 @@ impl<'a, T: KernelObject + ?Sized> Cap<'a, T> {
|
||||
|
||||
/// KernelObject is the base trait for all kernel objects
|
||||
pub trait KernelObject {
|
||||
// this should be optimized by compiler?
|
||||
const OBJ_TYPE: ObjectType;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::cap::RawCap;
|
||||
use super::{Cap, KernelObject};
|
||||
use api::cap::ObjectType;
|
||||
use uapi::cap::ObjectType;
|
||||
use vspace::addr::PhysAddr;
|
||||
|
||||
/// NullObject is used as empty (capability) slot
|
||||
|
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),
|
||||
}
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ use super::cap::RawCap;
|
||||
use super::cnode::{CNodeCap, CNodeObject};
|
||||
use super::null::NullCap;
|
||||
use super::{Cap, KernelObject};
|
||||
use api::cap::ObjectType;
|
||||
use api::error::{SysError, SysResult};
|
||||
use uapi::cap::ObjectType;
|
||||
use uapi::error::{SysError, SysResult};
|
||||
use utils::then::Then;
|
||||
use utils::MASK;
|
||||
use vspace::addr::{align_up, PhysAddr};
|
||||
@ -65,7 +65,7 @@ impl UntypedCap<'_> {
|
||||
1 << self.block_bits()
|
||||
}
|
||||
|
||||
pub fn retype(&mut self, obj_type: ObjectType, user_obj_bits: usize, slots: &mut CNodeObject) -> SysResult<()> {
|
||||
pub fn retype(&mut self, obj_type: ObjectType, user_obj_bits: usize, slots: &mut CNodeObject) -> SysResult {
|
||||
/*
|
||||
* vallina seL4: `decode_untiped_invocation`
|
||||
* - _service CPTR to an untyped object.
|
||||
@ -89,7 +89,7 @@ impl UntypedCap<'_> {
|
||||
slots
|
||||
.iter()
|
||||
.any(|cte| NullCap::try_from(cte).is_err())
|
||||
.else_ok((), SysError::CapTypeMismatch)?;
|
||||
.else_ok((), SysError::SlotNotEmpty)?;
|
||||
|
||||
// Start allocating from free_offset
|
||||
// Notice: in vallina seL4, it will check whether there are child nodes,
|
||||
|
@ -1,7 +1,16 @@
|
||||
pub struct Timer;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
#[thread_local]
|
||||
pub static CURRENT_TICK: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
pub struct Timer
|
||||
where Self: TimerOps;
|
||||
|
||||
pub trait TimerOps {
|
||||
fn init();
|
||||
fn read_cycle() -> u64;
|
||||
fn tick();
|
||||
fn set_next();
|
||||
fn do_tick() {
|
||||
CURRENT_TICK.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,7 @@ pub struct Link<T: LinkHelper> {
|
||||
|
||||
impl<T: LinkHelper> Default for Link<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
prev: Cell::new(None),
|
||||
next: Cell::new(None),
|
||||
}
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,20 +41,43 @@ impl<T: LinkHelper> Clone for Link<T> {
|
||||
}
|
||||
|
||||
impl<T: LinkHelper> Link<T> {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
prev: Cell::new(None),
|
||||
next: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// LINK_OFFSET must be a valid field offset of T
|
||||
pub unsafe fn object(&self) -> &T {
|
||||
&*(container_of_offset!(self, T, T::LINK_OFFSET))
|
||||
}
|
||||
|
||||
pub fn prev(&self) -> Option<NonNull<T>> {
|
||||
pub fn prev_raw(&self) -> Option<NonNull<T>> {
|
||||
self.prev.get()
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Option<NonNull<T>> {
|
||||
pub fn next_raw(&self) -> Option<NonNull<T>> {
|
||||
self.next.get()
|
||||
}
|
||||
|
||||
pub fn prev(&self) -> Option<&T> {
|
||||
self.prev_raw().map(|p| unsafe { &*p.as_ptr() })
|
||||
}
|
||||
|
||||
pub fn prev_mut(&self) -> Option<&mut T> {
|
||||
self.prev_raw().map(|p| unsafe { &mut *p.as_ptr() })
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Option<&T> {
|
||||
self.next_raw().map(|n| unsafe { &*n.as_ptr() })
|
||||
}
|
||||
|
||||
pub fn next_mut(&self) -> Option<&mut T> {
|
||||
self.next_raw().map(|n| unsafe { &mut *n.as_ptr() })
|
||||
}
|
||||
|
||||
pub fn set_prev(&self, prev: Option<NonNull<T>>) {
|
||||
self.prev.set(prev);
|
||||
}
|
||||
@ -69,11 +89,11 @@ impl<T: LinkHelper> Link<T> {
|
||||
pub fn prepend(&self, new: &T) {
|
||||
unsafe {
|
||||
// setup new's link
|
||||
new.get_link().set_prev(self.prev());
|
||||
new.get_link().set_prev(self.prev_raw());
|
||||
new.get_link().set_next(Some(NonNull::from(self.object())));
|
||||
|
||||
// setup prev's link
|
||||
if let Some(prev) = self.prev() {
|
||||
if let Some(prev) = self.prev_raw() {
|
||||
prev.as_ref().get_link().set_next(Some(NonNull::from(new)))
|
||||
}
|
||||
|
||||
@ -86,10 +106,10 @@ impl<T: LinkHelper> Link<T> {
|
||||
unsafe {
|
||||
// setup new's link
|
||||
new.get_link().set_prev(Some(NonNull::from(self.object())));
|
||||
new.get_link().set_next(self.next());
|
||||
new.get_link().set_next(self.next_raw());
|
||||
|
||||
// setup next's link
|
||||
if let Some(next) = self.next() {
|
||||
if let Some(next) = self.next_raw() {
|
||||
next.as_ref().get_link().set_prev(Some(NonNull::from(new)))
|
||||
}
|
||||
|
||||
@ -101,13 +121,13 @@ impl<T: LinkHelper> Link<T> {
|
||||
pub fn detach(&self) {
|
||||
unsafe {
|
||||
// setup prev's link
|
||||
if let Some(prev) = self.prev() {
|
||||
prev.as_ref().get_link().set_next(self.next())
|
||||
if let Some(prev) = self.prev_raw() {
|
||||
prev.as_ref().get_link().set_next(self.next_raw())
|
||||
}
|
||||
|
||||
// setup next's link
|
||||
if let Some(next) = self.next() {
|
||||
next.as_ref().get_link().set_prev(self.prev())
|
||||
if let Some(next) = self.next_raw() {
|
||||
next.as_ref().get_link().set_prev(self.prev_raw())
|
||||
}
|
||||
|
||||
// setup self's link
|
||||
@ -174,34 +194,34 @@ mod tests {
|
||||
|
||||
{
|
||||
// check next link
|
||||
assert!(node1.link.next().is_some());
|
||||
assert_eq!(node1.link.next().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||
assert!(node2.link.next().is_some());
|
||||
assert_eq!(node2.link.next().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||
assert!(node3.link.next().is_none());
|
||||
assert!(node1.link.next_raw().is_some());
|
||||
assert_eq!(node1.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||
assert!(node2.link.next_raw().is_some());
|
||||
assert_eq!(node2.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||
assert!(node3.link.next_raw().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
// check prev link
|
||||
assert!(node1.link.prev().is_none());
|
||||
assert!(node2.link.prev().is_some());
|
||||
assert_eq!(node2.link.prev().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||
assert!(node3.link.prev().is_some());
|
||||
assert_eq!(node3.link.prev().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||
assert!(node1.link.prev_raw().is_none());
|
||||
assert!(node2.link.prev_raw().is_some());
|
||||
assert_eq!(node2.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||
assert!(node3.link.prev_raw().is_some());
|
||||
assert_eq!(node3.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||
}
|
||||
|
||||
{
|
||||
// check detach
|
||||
node2.link.detach();
|
||||
|
||||
assert!(node2.link.next().is_none());
|
||||
assert!(node2.link.prev().is_none());
|
||||
assert!(node2.link.next_raw().is_none());
|
||||
assert!(node2.link.prev_raw().is_none());
|
||||
|
||||
assert!(node1.link.next().is_some());
|
||||
assert_eq!(node1.link.next().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||
assert!(node1.link.next_raw().is_some());
|
||||
assert_eq!(node1.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||
|
||||
assert!(node3.link.prev().is_some());
|
||||
assert_eq!(node3.link.prev().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||
assert!(node3.link.prev_raw().is_some());
|
||||
assert_eq!(node3.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ pub type PageResult<T = ()> = Result<T, PageError>;
|
||||
pub trait TableOps: Debug {
|
||||
type Entry: EntryOps;
|
||||
const MAX_PAGE_SIZE: TableLevel;
|
||||
const TABLE_SIZE: usize;
|
||||
|
||||
/// # Safety
|
||||
/// `location` must be a page-aligned virtual address and will not be dropped.
|
||||
|
@ -1,8 +1,9 @@
|
||||
[package]
|
||||
name = "api"
|
||||
name = "uapi"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vspace = { path = "../lib/vspace" }
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
num-derive = "0.4"
|
@ -18,10 +18,13 @@ pub enum CapFault {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||
pub enum SysError {
|
||||
Ok,
|
||||
CapTypeMismatch, // InvalidCapability
|
||||
SlotNotEmpty, // DeleteFirst
|
||||
InvalidArgument,
|
||||
RangeError,
|
||||
CapTypeMismatch, // Cap, Untyped
|
||||
SlotNotEmpty, // Untyped
|
||||
RangeError, // Untyped
|
||||
NotMapped, // Frame
|
||||
AlreadyMapped, // Frame
|
||||
MissingEntry, // Frame
|
||||
}
|
||||
|
||||
pub type SysResult<T> = Result<T, SysError>;
|
||||
pub type SysResult<T = ()> = Result<T, SysError>;
|
@ -6,3 +6,4 @@ extern crate num_derive;
|
||||
|
||||
pub mod cap;
|
||||
pub mod error;
|
||||
pub mod vspace;
|
5
uapi/src/vspace.rs
Normal file
5
uapi/src/vspace.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub use vspace::paging::MapAttr;
|
||||
|
||||
// TODO: Only support leaf page for now, no huge page support!
|
||||
|
||||
pub const FRAME_SIZE: usize = 4096;
|
Loading…
Reference in New Issue
Block a user