diff --git a/os/src/config.rs b/os/src/config.rs index 1fb18e23..eeda71ce 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -1,3 +1,5 @@ +//! Constants used in rCore + pub const USER_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_HEAP_SIZE: usize = 0x30_0000; diff --git a/os/src/console.rs b/os/src/console.rs index dda4911a..7e44bb20 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -1,3 +1,5 @@ +//! SBI console driver, for text output + use crate::sbi::console_putchar; use core::fmt::{self, Write}; @@ -17,6 +19,7 @@ pub fn print(args: fmt::Arguments) { } #[macro_export] +/// print string macro macro_rules! print { ($fmt: literal $(, $($arg: tt)+)?) => { $crate::console::print(format_args!($fmt $(, $($arg)+)?)); @@ -24,6 +27,7 @@ macro_rules! print { } #[macro_export] +/// println string macro macro_rules! println { ($fmt: literal $(, $($arg: tt)+)?) => { $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index af3e5152..e8cf681a 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -1,7 +1,10 @@ +//! The panic handler + use crate::sbi::shutdown; use core::panic::PanicInfo; #[panic_handler] +/// panic handler fn panic(info: &PanicInfo) -> ! { if let Some(location) = info.location() { println!( diff --git a/os/src/loader.rs b/os/src/loader.rs index 1358c464..855187df 100644 --- a/os/src/loader.rs +++ b/os/src/loader.rs @@ -1,3 +1,6 @@ +//! Loading user applications into memory + +/// Get the total number of applications. pub fn get_num_app() -> usize { extern "C" { fn _num_app(); @@ -5,6 +8,7 @@ pub fn get_num_app() -> usize { unsafe { (_num_app as usize as *const usize).read_volatile() } } +/// get applications data pub fn get_app_data(app_id: usize) -> &'static [u8] { extern "C" { fn _num_app(); diff --git a/os/src/main.rs b/os/src/main.rs index 261122c1..5ad63749 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,3 +1,20 @@ +//! The main module and entrypoint +//! +//! Various facilities of the kernels are implemented as submodules. The most +//! important ones are: +//! +//! - [`trap`]: Handles all cases of switching from userspace to the kernel +//! - [`task`]: Task management +//! - [`syscall`]: System call handling and implementation +//! +//! The operating system also starts in this module. Kernel code starts +//! executing from `entry.asm`, after which [`rust_main()`] is called to +//! initialize various pieces of functionality. (See its source code for +//! details.) +//! +//! We then call [`task::run_first_task()`] and for the first time go to +//! userspace. + #![no_std] #![no_main] #![feature(panic_info_message)] @@ -23,16 +40,15 @@ mod loader; mod mm; mod sbi; mod sync; -mod syscall; -mod task; +pub mod syscall; +pub mod task; mod timer; -mod trap; +pub mod trap; -use core::arch::global_asm; - -global_asm!(include_str!("entry.asm")); -global_asm!(include_str!("link_app.S")); +core::arch::global_asm!(include_str!("entry.asm")); +core::arch::global_asm!(include_str!("link_app.S")); +/// clear BSS segment fn clear_bss() { extern "C" { fn sbss(); @@ -45,6 +61,7 @@ fn clear_bss() { } #[no_mangle] +/// the rust entry-point of os pub fn rust_main() -> ! { clear_bss(); println!("[kernel] Hello, world!"); diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index bcddac5d..e0e88e5f 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -1,7 +1,10 @@ +//! Implementation of physical and virtual address and page number. + use super::PageTableEntry; use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; use core::fmt::{self, Debug, Formatter}; +/// physical address const PA_WIDTH_SV39: usize = 56; const VA_WIDTH_SV39: usize = 39; const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS; @@ -11,12 +14,15 @@ const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysAddr(pub usize); +/// virtual address #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtAddr(pub usize); +/// physical page number #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysPageNum(pub usize); +/// virtual page number #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtPageNum(pub usize); @@ -176,6 +182,7 @@ impl StepByOne for VirtPageNum { } #[derive(Copy, Clone)] +/// a simple range structure for type T pub struct SimpleRange where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, @@ -208,6 +215,7 @@ where SimpleRangeIterator::new(self.l, self.r) } } +/// iterator for the simple range structure pub struct SimpleRangeIterator where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, @@ -238,4 +246,6 @@ where } } } + +/// a simple range structure for virtual page number pub type VPNRange = SimpleRange; diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index b7c909b1..d4320da0 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -1,3 +1,6 @@ +//! Implementation of [`FrameAllocator`] which +//! controls all the frames in the operating system. + use super::{PhysAddr, PhysPageNum}; use crate::config::MEMORY_END; use crate::sync::UPSafeCell; @@ -5,6 +8,7 @@ use alloc::vec::Vec; use core::fmt::{self, Debug, Formatter}; use lazy_static::*; +/// manage a frame which has the same lifecycle as the tracker pub struct FrameTracker { pub ppn: PhysPageNum, } @@ -38,6 +42,7 @@ trait FrameAllocator { fn dealloc(&mut self, ppn: PhysPageNum); } +/// an implementation for frame allocator pub struct StackFrameAllocator { current: usize, end: usize, @@ -82,10 +87,12 @@ impl FrameAllocator for StackFrameAllocator { type FrameAllocatorImpl = StackFrameAllocator; lazy_static! { + /// frame allocator instance through lazy_static! pub static ref FRAME_ALLOCATOR: UPSafeCell = unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) }; } +/// initiate the frame allocator using `ekernel` and `MEMORY_END` pub fn init_frame_allocator() { extern "C" { fn ekernel(); @@ -96,6 +103,7 @@ pub fn init_frame_allocator() { ); } +/// allocate a frame pub fn frame_alloc() -> Option { FRAME_ALLOCATOR .exclusive_access() @@ -103,11 +111,13 @@ pub fn frame_alloc() -> Option { .map(FrameTracker::new) } +/// deallocate a frame fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } #[allow(unused)] +/// a simple test for frame allocator pub fn frame_allocator_test() { let mut v: Vec = Vec::new(); for i in 0..5 { diff --git a/os/src/mm/heap_allocator.rs b/os/src/mm/heap_allocator.rs index 42a6d769..07a53f7c 100644 --- a/os/src/mm/heap_allocator.rs +++ b/os/src/mm/heap_allocator.rs @@ -1,16 +1,22 @@ +//! The global allocator + use crate::config::KERNEL_HEAP_SIZE; use buddy_system_allocator::LockedHeap; #[global_allocator] +/// heap allocator instance static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); #[alloc_error_handler] +/// panic when heap allocation error occurs pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { panic!("Heap allocation error, layout = {:?}", layout); } +/// heap space ([u8; KERNEL_HEAP_SIZE]) static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; +/// initiate heap allocator pub fn init_heap() { unsafe { HEAP_ALLOCATOR diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 3ad2ac55..32c91ed3 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,3 +1,5 @@ +//! Implementation of [`MapArea`] and [`MemorySet`]. + use super::{frame_alloc, FrameTracker}; use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; @@ -25,10 +27,12 @@ extern "C" { } lazy_static! { + /// a memory set instance through lazy_static! managing kernel space pub static ref KERNEL_SPACE: Arc> = Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) }); } +/// memory set structure, controls virtual-memory space pub struct MemorySet { page_table: PageTable, areas: Vec, @@ -216,6 +220,7 @@ impl MemorySet { } } +/// map area structure, controls a contiguous piece of virtual memory pub struct MapArea { vpn_range: VPNRange, data_frames: BTreeMap, @@ -297,12 +302,14 @@ impl MapArea { } #[derive(Copy, Clone, PartialEq, Debug)] +/// map type for memory set: identical or framed pub enum MapType { Identical, Framed, } bitflags! { + /// map permission corresponding to that in pte: `R W X U` pub struct MapPermission: u8 { const R = 1 << 1; const W = 1 << 2; diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index bbf8bef4..cafdbac0 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -1,3 +1,12 @@ +//! Memory management implementation +//! +//! SV39 page-based virtual-memory architecture for RV64 systems, and +//! everything about memory management, like frame allocator, page table, +//! map area and memory set, is implemented here. +//! +//! Every task or process has a memory_set to control its virtual memory. + + mod address; mod frame_allocator; mod heap_allocator; @@ -12,6 +21,7 @@ pub use memory_set::{MapPermission, MemorySet, KERNEL_SPACE}; pub use page_table::{translated_byte_buffer, PageTableEntry}; use page_table::{PTEFlags, PageTable}; +/// initiate heap allocator, frame allocator and kernel space pub fn init() { heap_allocator::init_heap(); frame_allocator::init_frame_allocator(); diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs index bd09caef..eb37634b 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -1,9 +1,12 @@ +//! Implementation of [`PageTableEntry`] and [`PageTable`]. + use super::{frame_alloc, FrameTracker, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; use alloc::vec; use alloc::vec::Vec; use bitflags::*; bitflags! { + /// page table entry flags pub struct PTEFlags: u8 { const V = 1 << 0; const R = 1 << 1; @@ -18,6 +21,7 @@ bitflags! { #[derive(Copy, Clone)] #[repr(C)] +/// page table entry structure pub struct PageTableEntry { pub bits: usize, } @@ -51,6 +55,7 @@ impl PageTableEntry { } } +/// page table structure pub struct PageTable { root_ppn: PhysPageNum, frames: Vec, @@ -128,6 +133,7 @@ impl PageTable { } } +/// translate a pointer to a mutable u8 Vec through page table pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> { let page_table = PageTable::from_token(token); let mut start = ptr as usize; diff --git a/os/src/sbi.rs b/os/src/sbi.rs index 2e2804b2..35243d9a 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -1,18 +1,19 @@ -#![allow(unused)] +//! SBI call wrappers use core::arch::asm; const SBI_SET_TIMER: usize = 0; const SBI_CONSOLE_PUTCHAR: usize = 1; -const SBI_CONSOLE_GETCHAR: usize = 2; -const SBI_CLEAR_IPI: usize = 3; -const SBI_SEND_IPI: usize = 4; -const SBI_REMOTE_FENCE_I: usize = 5; -const SBI_REMOTE_SFENCE_VMA: usize = 6; -const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; +// const SBI_CONSOLE_GETCHAR: usize = 2; +// const SBI_CLEAR_IPI: usize = 3; +// const SBI_SEND_IPI: usize = 4; +// const SBI_REMOTE_FENCE_I: usize = 5; +// const SBI_REMOTE_SFENCE_VMA: usize = 6; +// const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; const SBI_SHUTDOWN: usize = 8; #[inline(always)] +/// general sbi call fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { let mut ret; unsafe { @@ -27,18 +28,22 @@ fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { ret } +/// use sbi call to set timer pub fn set_timer(timer: usize) { sbi_call(SBI_SET_TIMER, timer, 0, 0); } +/// use sbi call to putchar in console (qemu uart handler) pub fn console_putchar(c: usize) { sbi_call(SBI_CONSOLE_PUTCHAR, c, 0, 0); } -pub fn console_getchar() -> usize { - sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) -} +/// use sbi call to getchar from console (qemu uart handler) +// pub fn console_getchar() -> usize { +// sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) +// } +/// use sbi call to shutdown the kernel pub fn shutdown() -> ! { sbi_call(SBI_SHUTDOWN, 0, 0, 0); panic!("It should shutdown!"); diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index d1ce5bcf..4743e31e 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,3 +1,5 @@ +//! Synchronization and interior mutability primitives + mod up; pub use up::UPSafeCell; diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs index c7b2c9ee..039b0397 100644 --- a/os/src/sync/up.rs +++ b/os/src/sync/up.rs @@ -1,3 +1,5 @@ +//! Uniprocessor interior mutability primitives + use core::cell::{RefCell, RefMut}; /// Wrap a static data structure inside it so that we are diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 5dfff5e3..0cbd0ca0 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -1,3 +1,5 @@ +//! File and filesystem-related syscalls + use crate::mm::translated_byte_buffer; use crate::task::current_user_token; diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 572b081a..ee52f5b4 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,3 +1,15 @@ +//! Implementation of syscalls +//! +//! The single entry point to all system calls, [`syscall()`], is called +//! whenever userspace wishes to perform a system call using the `ecall` +//! instruction. In this case, the processor raises an 'Environment call from +//! U-mode' exception, which is handled as one of the cases in +//! [`crate::trap::trap_handler`]. +//! +//! For clarity, each single syscall is implemented as its own function, named +//! `sys_` then the name of the syscall. You can find functions like this in +//! submodules, and you should also implement syscalls this way. + const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; const SYSCALL_YIELD: usize = 124; @@ -9,6 +21,7 @@ mod process; use fs::*; use process::*; +/// handle syscall exception with `syscall_id` and other arguments pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 55856e70..a26fb3fe 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,3 +1,5 @@ +//! Process management syscalls + use crate::task::{exit_current_and_run_next, suspend_current_and_run_next}; use crate::timer::get_time_ms; diff --git a/os/src/task/context.rs b/os/src/task/context.rs index e4f59d8a..8e4f5473 100644 --- a/os/src/task/context.rs +++ b/os/src/task/context.rs @@ -1,6 +1,8 @@ +//! Implementation of [`TaskContext`] use crate::trap::trap_return; #[repr(C)] +/// task context structure containing some registers pub struct TaskContext { ra: usize, sp: usize, diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 453ac916..ee36241b 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -1,3 +1,14 @@ +//! Task management implementation +//! +//! Everything about task management, like starting and switching tasks is +//! implemented here. +//! +//! A single global instance of [`TaskManager`] called `TASK_MANAGER` controls +//! all the tasks in the operating system. +//! +//! Be careful when you see [`__switch`]. Control flow around this function +//! might not be what you expect. + mod context; mod switch; #[allow(clippy::module_inception)] @@ -13,17 +24,32 @@ use task::{TaskControlBlock, TaskStatus}; pub use context::TaskContext; +/// The task manager, where all the tasks are managed. +/// +/// Functions implemented on `TaskManager` deals with all task state transitions +/// and task context switching. For convenience, you can find wrappers around it +/// in the module level. +/// +/// Most of `TaskManager` are hidden behind the field `inner`, to defer +/// borrowing checks to runtime. You can see examples on how to use `inner` in +/// existing functions on `TaskManager`. pub struct TaskManager { + /// total number of tasks num_app: usize, + /// use inner value to get mutable access inner: UPSafeCell, } +/// The task manager inner in 'UPSafeCell' struct TaskManagerInner { + /// task list tasks: Vec, + /// id of current `Running` task current_task: usize, } lazy_static! { + /// a `TaskManager` instance through lazy_static! pub static ref TASK_MANAGER: TaskManager = { println!("init TASK_MANAGER"); let num_app = get_num_app(); @@ -45,6 +71,10 @@ lazy_static! { } impl TaskManager { + /// Run the first task in task list. + /// + /// Generally, the first task in task list is an idle task (we call it zero process later). + /// But in ch4, we load apps statically, so the first task is a real app. fn run_first_task(&self) -> ! { let mut inner = self.inner.exclusive_access(); let next_task = &mut inner.tasks[0]; @@ -59,18 +89,23 @@ impl TaskManager { panic!("unreachable in run_first_task!"); } + /// Change the status of current `Running` task into `Ready`. fn mark_current_suspended(&self) { let mut inner = self.inner.exclusive_access(); let cur = inner.current_task; inner.tasks[cur].task_status = TaskStatus::Ready; } + /// Change the status of current `Running` task into `Exited`. fn mark_current_exited(&self) { let mut inner = self.inner.exclusive_access(); let cur = inner.current_task; inner.tasks[cur].task_status = TaskStatus::Exited; } + /// Find next task to run and return task id. + /// + /// In this case, we only return the first `Ready` task in task list. fn find_next_task(&self) -> Option { let inner = self.inner.exclusive_access(); let current = inner.current_task; @@ -79,16 +114,20 @@ impl TaskManager { .find(|id| inner.tasks[*id].task_status == TaskStatus::Ready) } + /// Get the current 'Running' task's token. fn get_current_token(&self) -> usize { let inner = self.inner.exclusive_access(); inner.tasks[inner.current_task].get_user_token() } + /// Get the current 'Running' task's trap contexts. fn get_current_trap_cx(&self) -> &'static mut TrapContext { let inner = self.inner.exclusive_access(); inner.tasks[inner.current_task].get_trap_cx() } + /// Switch current `Running` task to the task we have found, + /// or there is no `Ready` task and we can exit with all applications completed fn run_next_task(&self) { if let Some(next) = self.find_next_task() { let mut inner = self.inner.exclusive_access(); @@ -109,36 +148,45 @@ impl TaskManager { } } +/// Run the first task in task list. pub fn run_first_task() { TASK_MANAGER.run_first_task(); } +/// Switch current `Running` task to the task we have found, +/// or there is no `Ready` task and we can exit with all applications completed fn run_next_task() { TASK_MANAGER.run_next_task(); } +/// Change the status of current `Running` task into `Ready`. fn mark_current_suspended() { TASK_MANAGER.mark_current_suspended(); } +/// Change the status of current `Running` task into `Exited`. fn mark_current_exited() { TASK_MANAGER.mark_current_exited(); } +/// Suspend the current 'Running' task and run the next task in task list. pub fn suspend_current_and_run_next() { mark_current_suspended(); run_next_task(); } +/// Exit the current 'Running' task and run the next task in task list. pub fn exit_current_and_run_next() { mark_current_exited(); run_next_task(); } +/// Get the current 'Running' task's token. pub fn current_user_token() -> usize { TASK_MANAGER.get_current_token() } +/// Get the current 'Running' task's trap contexts. pub fn current_trap_cx() -> &'static mut TrapContext { TASK_MANAGER.get_current_trap_cx() } diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs index 59f8b1a0..960b0b34 100644 --- a/os/src/task/switch.rs +++ b/os/src/task/switch.rs @@ -1,8 +1,15 @@ -use super::TaskContext; -use core::arch::global_asm; +//! Rust wrapper around `__switch`. +//! +//! Switching to a different task's context happens here. The actual +//! implementation must not be in Rust and (essentially) has to be in assembly +//! language (Do you know why?), so this module really is just a wrapper around +//! `switch.S`. -global_asm!(include_str!("switch.S")); +core::arch::global_asm!(include_str!("switch.S")); +use super::TaskContext; extern "C" { + /// Switch to the context of `next_task_cx_ptr`, saving the current context + /// in `current_task_cx_ptr`. pub fn __switch(current_task_cx_ptr: *mut TaskContext, next_task_cx_ptr: *const TaskContext); } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 036018bc..6588ad84 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,8 +1,10 @@ +//! Types related to task management use super::TaskContext; use crate::config::{kernel_stack_position, TRAP_CONTEXT}; use crate::mm::{MapPermission, MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE}; use crate::trap::{trap_handler, TrapContext}; +/// task control block structure pub struct TaskControlBlock { pub task_status: TaskStatus, pub task_cx: TaskContext, @@ -54,6 +56,7 @@ impl TaskControlBlock { } #[derive(Copy, Clone, PartialEq)] +/// task status: UnInit, Ready, Running, Exited pub enum TaskStatus { Ready, Running, diff --git a/os/src/timer.rs b/os/src/timer.rs index 048aa3b7..1948c6a1 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -1,3 +1,5 @@ +//! RISC-V timer-related functionality + use crate::config::CLOCK_FREQ; use crate::sbi::set_timer; use riscv::register::time; @@ -9,10 +11,12 @@ pub fn get_time() -> usize { time::read() } +/// get current time in microseconds pub fn get_time_ms() -> usize { time::read() / (CLOCK_FREQ / MSEC_PER_SEC) } +/// set the next timer interrupt pub fn set_next_trigger() { set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC); } diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs index d0734515..420c016b 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,6 +1,9 @@ +//! Implementation of [`TrapContext`] + use riscv::register::sstatus::{self, Sstatus, SPP}; #[repr(C)] +/// trap context structure containing sstatus, sepc and registers pub struct TrapContext { pub x: [usize; 32], pub sstatus: Sstatus, diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 022f3adb..56aec31a 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -1,3 +1,16 @@ +//! Trap handling functionality +//! +//! For rCore, we have a single trap entry point, namely `__alltraps`. At +//! initialization in [`init()`], we set the `stvec` CSR to point to it. +//! +//! All traps go through `__alltraps`, which is defined in `trap.S`. The +//! assembly language code does just enough work restore the kernel space +//! context, ensuring that Rust code safely runs, and transfers control to +//! [`trap_handler()`]. +//! +//! It then calls different functionality based on what exactly the exception +//! was. For example, timer interrupts trigger task preemption, and syscalls go +//! to [`syscall()`]. mod context; use crate::config::{TRAMPOLINE, TRAP_CONTEXT};