Compare commits

..

12 Commits

24 changed files with 430 additions and 68 deletions

View File

@ -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
View File

@ -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"

View File

@ -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"

View File

@ -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 }

View File

@ -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);
} }
} }

View File

@ -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...");
} }

View File

@ -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::*;

View File

@ -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));

View File

@ -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;

View File

@ -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,

View File

@ -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
View 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),
}
}
}

View File

@ -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;
} }

View File

@ -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
View 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),
}
}
}

View File

@ -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,

View File

@ -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);
}
} }

View File

@ -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));
} }
} }
} }

View File

@ -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.

View File

@ -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"

View File

@ -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>;

View File

@ -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
View 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;