diff --git a/abi/src/lib.rs b/abi/src/lib.rs index 3d8b3a1..c72406a 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -2,7 +2,9 @@ #![feature(asm)] #![no_std] +/// A trait that allows setting a struct back to its default value. pub trait SetDefault { + /// Set this struct back to its default value. fn set_default(&mut self); } @@ -59,6 +61,7 @@ pub enum SystemCall { }, } +/// Represents a task buffer used for system calls. #[derive(Debug)] pub struct TaskBuffer { pub call: Option diff --git a/kernel/src/cap/channel.rs b/kernel/src/cap/channel.rs index 9185bc8..1d05025 100644 --- a/kernel/src/cap/channel.rs +++ b/kernel/src/cap/channel.rs @@ -5,14 +5,21 @@ use util::managed_arc::{ManagedArc, ManagedArcAny, ManagedWeakPool3Arc}; use super::{UntypedDescriptor}; +/// Channel descriptor. #[derive(Debug)] pub struct ChannelDescriptor { value: Option, next: Option, } +/// Channel capability. Reference-counted smart pointer to channel +/// descriptor. +/// +/// Channels are used for inter-process communication of different +/// tasks. pub type ChannelCap = ManagedArc>; impl ChannelCap { + /// Create a channel capability from an untyped capability. pub fn retype_from(untyped: &mut UntypedDescriptor) -> Self { let mut arc: Option = None; @@ -32,10 +39,13 @@ impl ChannelCap { } impl ChannelDescriptor { + /// Put a value to the channel. pub fn put(&mut self, value: u64) { self.value = Some(value); } + /// Take a value from the channel. If there's no value in the + /// channel, `None` is returned. pub fn take(&mut self) -> Option { self.value.take() } diff --git a/kernel/src/cap/cpool.rs b/kernel/src/cap/cpool.rs index 0465c90..7e6e09f 100644 --- a/kernel/src/cap/cpool.rs +++ b/kernel/src/cap/cpool.rs @@ -6,39 +6,57 @@ use util::managed_arc::{ManagedArc, ManagedArcAny, ManagedWeakPool256Arc}; use super::{UntypedDescriptor}; +/// Capability pool descriptor. #[derive(Debug)] pub struct CPoolDescriptor { weak_pool: ManagedWeakPool256Arc, next: Option, } +/// Capability pool capability. Reference-counted smart pointer to +/// capability pool descriptor. Capability pool itself is a +/// `ManagedWeakPool` with 256 entries. +/// +/// Capability pool capability is used to hold multiple capabilities +/// together so as to be addressable in user-space programs. pub type CPoolCap = ManagedArc>; impl CPoolDescriptor { + /// Create a new pointer to a capability descriptor using the + /// index. If nothing is in the entry, `None` is returned. pub fn upgrade_any(&self, index: usize) -> Option { unsafe { self.weak_pool.read().upgrade_any(index, |ptr, type_id| { super::upgrade_any(ptr, type_id) }) } } + /// Like `upgrade_any`, but returns a value with the specified + /// type. pub fn upgrade(&self, index: usize) -> Option> where ManagedArc: Any { self.weak_pool.read().upgrade(index) } + /// Downgrade a capability into the capability pool (weak pool) at + /// a specified index. pub fn downgrade_at(&self, arc: &ManagedArc, index: usize) where ManagedArc: Any { self.weak_pool.read().downgrade_at(arc, index) } + /// Downgrade a capability into the capability pool (weak pool) at + /// a free index. pub fn downgrade_free(&self, arc: &ManagedArc) -> Option where ManagedArc: Any { self.weak_pool.read().downgrade_free(arc) } + /// Size of the capability pool. pub fn size(&self) -> usize { 256 } } impl CPoolCap { + /// Create a capability pool capability from an untyped + /// capability. pub fn retype_from(untyped: &mut UntypedDescriptor) -> Self { let mut arc: Option = None; diff --git a/kernel/src/cap/mod.rs b/kernel/src/cap/mod.rs index deb6634..64b6ebf 100644 --- a/kernel/src/cap/mod.rs +++ b/kernel/src/cap/mod.rs @@ -1,6 +1,10 @@ +/// Untyped capability implementation. mod untyped; +/// Capability pool capability implementation. mod cpool; +/// Task capability implementation. mod task; +/// Channel capability implementation. mod channel; pub use self::untyped::{UntypedDescriptor, UntypedCap}; @@ -15,8 +19,11 @@ use core::any::{TypeId}; use util::managed_arc::{ManagedWeakPool256Arc, ManagedArcAny, ManagedArc}; pub use abi::{SetDefault, TaskBuffer}; +/// Raw page struct representing a whole page. pub struct RawPage(pub [u8; PAGE_LENGTH]); +/// Raw page capability. Represents a page with no other information. pub type RawPageCap = PageCap; +/// Task buffer page capability. Represents a page of task buffer. pub type TaskBufferPageCap = PageCap; impl SetDefault for RawPage { @@ -27,6 +34,16 @@ impl SetDefault for RawPage { } } +/// Create a managed Arc (capability) from an address of an kernel +/// object (architecture-specific or general). The `type_id` should be +/// a [TypeId](https://doc.rust-lang.org/std/any/struct.TypeId.html) +/// of a capability. If the `type_id` is not recognized, `None` is +/// returned. +/// +/// # Safety +/// +/// `ptr` must be a physical address pointing to a valid kernel object +/// of type `type_id`. pub unsafe fn upgrade_any(ptr: PAddr, type_id: TypeId) -> Option { if type_id == TypeId::of::() { Some(unsafe { ManagedArc::from_ptr(ptr): CPoolCap }.into()) @@ -45,6 +62,9 @@ pub unsafe fn upgrade_any(ptr: PAddr, type_id: TypeId) -> Option } } +/// Drop an architecture-specific `any` capability. `ManagedArcAny` is +/// not itself droppable. It must be converted to its real type before +/// dropping. pub fn drop_any(any: ManagedArcAny) { if any.is::() { any.into(): CPoolCap; diff --git a/kernel/src/cap/task.rs b/kernel/src/cap/task.rs index 4d2d5a0..937b240 100644 --- a/kernel/src/cap/task.rs +++ b/kernel/src/cap/task.rs @@ -7,6 +7,9 @@ use arch::{TaskRuntime, Exception}; use super::{UntypedDescriptor, TopPageTableCap, CPoolCap, TaskBufferPageCap, ChannelCap}; +/// Switch to an idle task that runs in kernel-mode. This is used when +/// no other tasks is runnable. Like normal context switching, this +/// returns only when exceptions (interrupts) happen. pub fn idle() -> Exception { #[naked] unsafe fn idle_task() -> ! { @@ -22,6 +25,7 @@ pub fn idle() -> Exception { } } +/// Represent a task status. #[derive(Debug, Clone)] pub enum TaskStatus { Active, @@ -29,6 +33,7 @@ pub enum TaskStatus { Inactive, } +/// Task descriptor. #[derive(Debug)] pub struct TaskDescriptor { weak_pool: ManagedWeakPool3Arc, @@ -37,9 +42,14 @@ pub struct TaskDescriptor { next_task: Option, status: TaskStatus } +/// Task capability. Reference-counted smart pointer to task +/// descriptor. +/// +/// Tasks represents isolated processes running. pub type TaskCap = ManagedArc>; impl TaskCap { + /// Create a task capability from an untyped capability. pub fn retype_from(untyped: &mut UntypedDescriptor) -> Self { let mut arc: Option = None; @@ -68,46 +78,58 @@ impl TaskCap { } impl TaskDescriptor { + /// Set the task's instruction pointer. pub fn set_instruction_pointer(&mut self, instruction_pointer: VAddr) { self.runtime.set_instruction_pointer(instruction_pointer) } + /// Set the task's stack pointer. pub fn set_stack_pointer(&mut self, stack_pointer: VAddr) { self.runtime.set_stack_pointer(stack_pointer) } + /// Set the task's root capability pool. pub fn downgrade_cpool(&self, cpool: &CPoolCap) { self.weak_pool.read().downgrade_at(cpool, 0) } + /// Read from the task's root capability pool. pub fn upgrade_cpool(&self) -> Option { self.weak_pool.read().upgrade(0) } + /// Set the task's top page table. pub fn downgrade_top_page_table(&self, pml4: &TopPageTableCap) { self.weak_pool.read().downgrade_at(pml4, 1) } + /// Read from the task's top page table. pub fn upgrade_top_page_table(&self) -> Option { self.weak_pool.read().upgrade(1) } + /// Set the task's buffer. pub fn downgrade_buffer(&self, buffer: &TaskBufferPageCap) { self.weak_pool.read().downgrade_at(buffer, 2) } + /// Read from the task's buffer. pub fn upgrade_buffer(&self) -> Option { self.weak_pool.read().upgrade(2) } + /// Current task status. pub fn status(&self) -> TaskStatus { self.status.clone() } + /// Set the current task status. pub fn set_status(&mut self, status: TaskStatus) { self.status = status; } + /// Switch to the task. The function is returned when exception + /// happens. pub fn switch_to(&mut self) -> Exception { if let Some(pml4) = self.upgrade_top_page_table() { pml4.write().switch_to(); @@ -116,8 +138,12 @@ impl TaskDescriptor { } } +/// The first task initialized by the kernel. static FIRST_TASK: Mutex> = Mutex::new(None); +/// Register a new task. Using `FIRST_TASK` static, this forms a +/// linked-list that allows an iterator to iterate over all created +/// tasks. fn register_task(cap: TaskCap) { let mut first_task = FIRST_TASK.lock(); if first_task.is_none() { @@ -132,6 +158,7 @@ fn register_task(cap: TaskCap) { } } +/// A task iterator. pub struct TaskIterator { next: Option, } @@ -152,6 +179,7 @@ impl Iterator for TaskIterator { } } +/// Return a task iterator using `FIRST_TASK`. pub fn task_iter() -> TaskIterator { TaskIterator { next: FIRST_TASK.lock().clone(), diff --git a/kernel/src/cap/untyped.rs b/kernel/src/cap/untyped.rs index 11d9820..0cb421e 100644 --- a/kernel/src/cap/untyped.rs +++ b/kernel/src/cap/untyped.rs @@ -2,6 +2,7 @@ use common::*; use util::{RwLock, align_up}; use util::managed_arc::{ManagedArc, ManagedArcAny}; +/// Untyped descriptor. #[derive(Debug)] pub struct UntypedDescriptor { start_paddr: PAddr, @@ -9,9 +10,20 @@ pub struct UntypedDescriptor { watermark: PAddr, first_child: Option } +/// Untyped capability. Reference-counted smart pointer to untyped +/// descriptor. +/// +/// Untyped capability represents free memory that can be retyped to +/// different useful capabilities. pub type UntypedCap = ManagedArc>; impl UntypedCap { + /// Bootstrap an untyped capability using a memory region information. + /// + /// # Safety + /// + /// Can only be used for free memory regions returned from + /// `InitInfo`. pub unsafe fn bootstrap(start_paddr: PAddr, length: usize) -> Self { let des_paddr = align_up(start_paddr, UntypedCap::inner_alignment()); assert!(des_paddr + UntypedCap::inner_length() <= start_paddr + length); @@ -28,14 +40,19 @@ impl UntypedCap { } impl UntypedDescriptor { + /// Length of the untyped region. pub fn length(&self) -> usize { self.length } + /// Start physical address of the untyped region. pub fn start_paddr(&self) -> PAddr { self.start_paddr } + /// Allocate a memory region using the given length and + /// alignment. Shift the watermark of the current descriptor + /// passing over the allocated region. pub unsafe fn allocate(&mut self, length: usize, alignment: usize) -> PAddr { let paddr = align_up(self.watermark, alignment); assert!(paddr + length <= self.start_paddr + self.length); @@ -44,6 +61,8 @@ impl UntypedDescriptor { paddr } + /// Derive and allocate a memory region to a capability that + /// requires memory region. pub unsafe fn derive(&mut self, length: usize, alignment: usize, f: F) where F: FnOnce(PAddr, Option) -> ManagedArcAny { let paddr = self.allocate(length, alignment); self.first_child = Some(f(paddr, self.first_child.take()));