mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 17:55:20 +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 }}
|
ARCH: ${{ matrix.arch }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Qemu
|
- name: Install Qemu
|
||||||
uses: ConorMacBride/install-package@v1
|
uses: ConorMacBride/install-package@v1
|
||||||
|
19
Cargo.lock
generated
19
Cargo.lock
generated
@ -18,14 +18,6 @@ dependencies = [
|
|||||||
"vspace",
|
"vspace",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "api"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"num-derive",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -105,7 +97,6 @@ name = "kernel"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator",
|
"allocator",
|
||||||
"api",
|
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fdt",
|
"fdt",
|
||||||
@ -116,6 +107,7 @@ dependencies = [
|
|||||||
"sbi-rt",
|
"sbi-rt",
|
||||||
"spin",
|
"spin",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
|
"uapi",
|
||||||
"uart_16550",
|
"uart_16550",
|
||||||
"utils",
|
"utils",
|
||||||
"vspace",
|
"vspace",
|
||||||
@ -256,6 +248,15 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uapi"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"vspace",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uart_16550"
|
name = "uart_16550"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["api", "kernel", "lib/*"]
|
members = ["kernel", "lib/*", "uapi"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
@ -20,8 +20,8 @@ riscv = []
|
|||||||
"riscv.board.virt" = ["riscv.riscv64"]
|
"riscv.board.virt" = ["riscv.riscv64"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
uapi = { path = "../uapi" }
|
||||||
allocator = { path = "../lib/allocator" }
|
allocator = { path = "../lib/allocator" }
|
||||||
api = { path = "../api" }
|
|
||||||
utils = { path = "../lib/utils", default-features = false }
|
utils = { path = "../lib/utils", default-features = false }
|
||||||
vspace = { path = "../lib/vspace", 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
|
// enable timer interrupt and set next tick
|
||||||
unsafe { riscv::register::sie::set_stimer() }
|
unsafe { riscv::register::sie::set_stimer() }
|
||||||
Self::tick();
|
Self::set_next();
|
||||||
info!("[Timer] begin to tick");
|
info!("[Timer] begin to tick");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ impl TimerOps for Timer {
|
|||||||
riscv::register::time::read64()
|
riscv::register::time::read64()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick() {
|
fn set_next() {
|
||||||
sbi_rt::set_timer(Self::read_cycle() + TIMER_TICKS);
|
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() {
|
match scause.cause() {
|
||||||
T::Interrupt(I::SupervisorTimer) => {
|
T::Interrupt(I::SupervisorTimer) => {
|
||||||
|
Timer::do_tick();
|
||||||
|
|
||||||
if !from_kernel {
|
if !from_kernel {
|
||||||
SCHEDULER.schedule()
|
SCHEDULER.schedule()
|
||||||
}
|
}
|
||||||
@ -61,7 +63,7 @@ fn trap_handler(tf: &mut TrapContext, from_kernel: bool) {
|
|||||||
_ => panic_fatal!("Unhandled Trap"),
|
_ => panic_fatal!("Unhandled Trap"),
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::tick();
|
Timer::set_next();
|
||||||
trace!("[Trap] exiting...");
|
trace!("[Trap] exiting...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,4 +3,6 @@ mod table;
|
|||||||
mod traits;
|
mod traits;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub use table::Table;
|
||||||
|
pub use traits::*;
|
||||||
pub use utils::*;
|
pub use utils::*;
|
||||||
|
@ -11,6 +11,7 @@ pub struct Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq_size!(Table, [u8; PAGE_SIZE]);
|
assert_eq_size!(Table, [u8; PAGE_SIZE]);
|
||||||
|
const_assert_eq!(core::mem::size_of::<Table>(), Table::TABLE_SIZE);
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
fn lookup_mut_internal(&mut self, vaddr: VirtAddr) -> (&mut Entry, TableLevel) {
|
fn lookup_mut_internal(&mut self, vaddr: VirtAddr) -> (&mut Entry, TableLevel) {
|
||||||
@ -46,6 +47,7 @@ impl TableOps for Table {
|
|||||||
|
|
||||||
#[cfg(feature = "riscv.pagetable.sv39")]
|
#[cfg(feature = "riscv.pagetable.sv39")]
|
||||||
const MAX_PAGE_SIZE: TableLevel = TableLevel::Level2;
|
const MAX_PAGE_SIZE: TableLevel = TableLevel::Level2;
|
||||||
|
const TABLE_SIZE: usize = PAGE_SIZE;
|
||||||
|
|
||||||
unsafe fn new(location: VirtAddr) -> &'static mut Self {
|
unsafe fn new(location: VirtAddr) -> &'static mut Self {
|
||||||
assert!(location.is_aligned(PAGE_SIZE));
|
assert!(location.is_aligned(PAGE_SIZE));
|
||||||
|
@ -5,13 +5,9 @@
|
|||||||
#![feature(asm_const)]
|
#![feature(asm_const)]
|
||||||
#![feature(cell_update)]
|
#![feature(cell_update)]
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
#![feature(const_mut_refs)]
|
|
||||||
#![feature(extern_types)]
|
|
||||||
#![feature(fn_align)]
|
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(stmt_expr_attributes)]
|
|
||||||
#![feature(thread_local)]
|
#![feature(thread_local)]
|
||||||
// Test Infrastructure
|
// Test Infrastructure
|
||||||
#![feature(custom_test_frameworks)]
|
#![feature(custom_test_frameworks)]
|
||||||
@ -19,6 +15,7 @@
|
|||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
// no noisy dead_code warnings
|
// no noisy dead_code warnings
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
#![allow(clippy::identity_op)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::objects::null::NullCap;
|
use crate::objects::null::NullCap;
|
||||||
use api::cap::ObjectType;
|
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
use uapi::cap::ObjectType;
|
||||||
use utils::{
|
use utils::{
|
||||||
linked_list::{Link, LinkHelper},
|
linked_list::{Link, LinkHelper},
|
||||||
LinkHelperImpl,
|
LinkHelperImpl,
|
||||||
|
@ -3,7 +3,7 @@ use super::{
|
|||||||
Cap, KernelObject,
|
Cap, KernelObject,
|
||||||
};
|
};
|
||||||
use crate::arch::layout::mmap_phys_to_virt;
|
use crate::arch::layout::mmap_phys_to_virt;
|
||||||
use api::{cap::ObjectType, error::CapFault};
|
use uapi::{cap::ObjectType, error::CapFault};
|
||||||
use utils::MASK;
|
use utils::MASK;
|
||||||
use vspace::addr::{AddressOps, PhysAddr};
|
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,
|
cap::ObjectType,
|
||||||
error::{SysError, SysResult},
|
error::{SysError, SysResult},
|
||||||
};
|
};
|
||||||
use cap::CapEntry;
|
|
||||||
use core::{marker::PhantomData, ptr::NonNull};
|
|
||||||
|
|
||||||
pub mod cap;
|
pub mod cap;
|
||||||
pub mod cnode;
|
pub mod cnode;
|
||||||
|
pub mod frame;
|
||||||
pub mod null;
|
pub mod null;
|
||||||
|
pub mod table;
|
||||||
pub mod untyped;
|
pub mod untyped;
|
||||||
|
|
||||||
/// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust)
|
/// 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> {
|
impl<'a, T: KernelObject + ?Sized> Cap<'a, T> {
|
||||||
pub fn append(&mut self, new: &mut CapEntry) {
|
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
|
// update new cap's link
|
||||||
new.link.set_prev(Some(NonNull::from(self.cte)));
|
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
|
/// KernelObject is the base trait for all kernel objects
|
||||||
pub trait KernelObject {
|
pub trait KernelObject {
|
||||||
// this should be optimized by compiler?
|
|
||||||
const OBJ_TYPE: ObjectType;
|
const OBJ_TYPE: ObjectType;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::cap::RawCap;
|
use super::cap::RawCap;
|
||||||
use super::{Cap, KernelObject};
|
use super::{Cap, KernelObject};
|
||||||
use api::cap::ObjectType;
|
use uapi::cap::ObjectType;
|
||||||
use vspace::addr::PhysAddr;
|
use vspace::addr::PhysAddr;
|
||||||
|
|
||||||
/// NullObject is used as empty (capability) slot
|
/// 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::cnode::{CNodeCap, CNodeObject};
|
||||||
use super::null::NullCap;
|
use super::null::NullCap;
|
||||||
use super::{Cap, KernelObject};
|
use super::{Cap, KernelObject};
|
||||||
use api::cap::ObjectType;
|
use uapi::cap::ObjectType;
|
||||||
use api::error::{SysError, SysResult};
|
use uapi::error::{SysError, SysResult};
|
||||||
use utils::then::Then;
|
use utils::then::Then;
|
||||||
use utils::MASK;
|
use utils::MASK;
|
||||||
use vspace::addr::{align_up, PhysAddr};
|
use vspace::addr::{align_up, PhysAddr};
|
||||||
@ -65,7 +65,7 @@ impl UntypedCap<'_> {
|
|||||||
1 << self.block_bits()
|
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`
|
* vallina seL4: `decode_untiped_invocation`
|
||||||
* - _service CPTR to an untyped object.
|
* - _service CPTR to an untyped object.
|
||||||
@ -89,7 +89,7 @@ impl UntypedCap<'_> {
|
|||||||
slots
|
slots
|
||||||
.iter()
|
.iter()
|
||||||
.any(|cte| NullCap::try_from(cte).is_err())
|
.any(|cte| NullCap::try_from(cte).is_err())
|
||||||
.else_ok((), SysError::CapTypeMismatch)?;
|
.else_ok((), SysError::SlotNotEmpty)?;
|
||||||
|
|
||||||
// Start allocating from free_offset
|
// Start allocating from free_offset
|
||||||
// Notice: in vallina seL4, it will check whether there are child nodes,
|
// 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 {
|
pub trait TimerOps {
|
||||||
fn init();
|
fn init();
|
||||||
fn read_cycle() -> u64;
|
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> {
|
impl<T: LinkHelper> Default for Link<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self::new()
|
||||||
prev: Cell::new(None),
|
|
||||||
next: Cell::new(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,20 +41,43 @@ impl<T: LinkHelper> Clone for Link<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: LinkHelper> Link<T> {
|
impl<T: LinkHelper> Link<T> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
prev: Cell::new(None),
|
||||||
|
next: Cell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// LINK_OFFSET must be a valid field offset of T
|
/// LINK_OFFSET must be a valid field offset of T
|
||||||
pub unsafe fn object(&self) -> &T {
|
pub unsafe fn object(&self) -> &T {
|
||||||
&*(container_of_offset!(self, T, T::LINK_OFFSET))
|
&*(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()
|
self.prev.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&self) -> Option<NonNull<T>> {
|
pub fn next_raw(&self) -> Option<NonNull<T>> {
|
||||||
self.next.get()
|
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>>) {
|
pub fn set_prev(&self, prev: Option<NonNull<T>>) {
|
||||||
self.prev.set(prev);
|
self.prev.set(prev);
|
||||||
}
|
}
|
||||||
@ -69,11 +89,11 @@ impl<T: LinkHelper> Link<T> {
|
|||||||
pub fn prepend(&self, new: &T) {
|
pub fn prepend(&self, new: &T) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// setup new's link
|
// 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())));
|
new.get_link().set_next(Some(NonNull::from(self.object())));
|
||||||
|
|
||||||
// setup prev's link
|
// 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)))
|
prev.as_ref().get_link().set_next(Some(NonNull::from(new)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,10 +106,10 @@ impl<T: LinkHelper> Link<T> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
// setup new's link
|
// setup new's link
|
||||||
new.get_link().set_prev(Some(NonNull::from(self.object())));
|
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
|
// 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)))
|
next.as_ref().get_link().set_prev(Some(NonNull::from(new)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,13 +121,13 @@ impl<T: LinkHelper> Link<T> {
|
|||||||
pub fn detach(&self) {
|
pub fn detach(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// setup prev's link
|
// setup prev's link
|
||||||
if let Some(prev) = self.prev() {
|
if let Some(prev) = self.prev_raw() {
|
||||||
prev.as_ref().get_link().set_next(self.next())
|
prev.as_ref().get_link().set_next(self.next_raw())
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup next's link
|
// setup next's link
|
||||||
if let Some(next) = self.next() {
|
if let Some(next) = self.next_raw() {
|
||||||
next.as_ref().get_link().set_prev(self.prev())
|
next.as_ref().get_link().set_prev(self.prev_raw())
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup self's link
|
// setup self's link
|
||||||
@ -174,34 +194,34 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// check next link
|
// check next link
|
||||||
assert!(node1.link.next().is_some());
|
assert!(node1.link.next_raw().is_some());
|
||||||
assert_eq!(node1.link.next().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
assert_eq!(node1.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||||
assert!(node2.link.next().is_some());
|
assert!(node2.link.next_raw().is_some());
|
||||||
assert_eq!(node2.link.next().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
assert_eq!(node2.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||||
assert!(node3.link.next().is_none());
|
assert!(node3.link.next_raw().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// check prev link
|
// check prev link
|
||||||
assert!(node1.link.prev().is_none());
|
assert!(node1.link.prev_raw().is_none());
|
||||||
assert!(node2.link.prev().is_some());
|
assert!(node2.link.prev_raw().is_some());
|
||||||
assert_eq!(node2.link.prev().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
assert_eq!(node2.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||||
assert!(node3.link.prev().is_some());
|
assert!(node3.link.prev_raw().is_some());
|
||||||
assert_eq!(node3.link.prev().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
assert_eq!(node3.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// check detach
|
// check detach
|
||||||
node2.link.detach();
|
node2.link.detach();
|
||||||
|
|
||||||
assert!(node2.link.next().is_none());
|
assert!(node2.link.next_raw().is_none());
|
||||||
assert!(node2.link.prev().is_none());
|
assert!(node2.link.prev_raw().is_none());
|
||||||
|
|
||||||
assert!(node1.link.next().is_some());
|
assert!(node1.link.next_raw().is_some());
|
||||||
assert_eq!(node1.link.next().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
assert_eq!(node1.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||||
|
|
||||||
assert!(node3.link.prev().is_some());
|
assert!(node3.link.prev_raw().is_some());
|
||||||
assert_eq!(node3.link.prev().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
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 {
|
pub trait TableOps: Debug {
|
||||||
type Entry: EntryOps;
|
type Entry: EntryOps;
|
||||||
const MAX_PAGE_SIZE: TableLevel;
|
const MAX_PAGE_SIZE: TableLevel;
|
||||||
|
const TABLE_SIZE: usize;
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `location` must be a page-aligned virtual address and will not be dropped.
|
/// `location` must be a page-aligned virtual address and will not be dropped.
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "api"
|
name = "uapi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
vspace = { path = "../lib/vspace" }
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
@ -18,10 +18,13 @@ pub enum CapFault {
|
|||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
pub enum SysError {
|
pub enum SysError {
|
||||||
Ok,
|
Ok,
|
||||||
CapTypeMismatch, // InvalidCapability
|
|
||||||
SlotNotEmpty, // DeleteFirst
|
|
||||||
InvalidArgument,
|
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 cap;
|
||||||
pub mod error;
|
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