diff --git a/os/src/loader.rs b/os/src/loader.rs index 0f08a174..f2ed4f04 100644 --- a/os/src/loader.rs +++ b/os/src/loader.rs @@ -41,10 +41,12 @@ impl UserStack { } } +/// Get base address of app i. fn get_base_i(app_id: usize) -> usize { APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT } +/// Get the total number of applications. pub fn get_num_app() -> usize { extern "C" { fn _num_app(); @@ -52,6 +54,8 @@ pub fn get_num_app() -> usize { unsafe { (_num_app as usize as *const usize).read_volatile() } } +/// Load nth user app at +/// [APP_BASE_ADDRESS + n * APP_SIZE_LIMIT, APP_BASE_ADDRESS + (n+1) * APP_SIZE_LIMIT). pub fn load_apps() { extern "C" { fn _num_app(); @@ -78,6 +82,7 @@ pub fn load_apps() { } } +/// get app info with entry and sp and save `TrapContext` in kernel stack pub fn init_app_cx(app_id: usize) -> usize { KERNEL_STACK[app_id].push_context(TrapContext::app_init_context( get_base_i(app_id), diff --git a/os/src/sbi.rs b/os/src/sbi.rs index 2e2804b2..37efee33 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -27,18 +27,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); } +/// 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/syscall/mod.rs b/os/src/syscall/mod.rs index 572b081a..17d17b73 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -9,6 +9,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..85314ea2 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,17 +1,20 @@ use crate::task::{exit_current_and_run_next, suspend_current_and_run_next}; use crate::timer::get_time_ms; +/// task exits and submit an exit code pub fn sys_exit(exit_code: i32) -> ! { println!("[kernel] Application exited with code {}", exit_code); exit_current_and_run_next(); panic!("Unreachable in sys_exit!"); } +/// current task gives up resources for other tasks pub fn sys_yield() -> isize { suspend_current_and_run_next(); 0 } +/// get time in milliseconds pub fn sys_get_time() -> isize { get_time_ms() as isize } diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index ca3ca2f6..453d6a7d 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -13,12 +13,16 @@ use task::{TaskControlBlock, TaskStatus}; pub use context::TaskContext; pub struct TaskManager { + /// total number of tasks num_app: usize, + /// use inner value to get mutable access inner: UPSafeCell, } struct TaskManagerInner { + /// task list tasks: [TaskControlBlock; MAX_APP_NUM], + /// id of current `Running` task current_task: usize, } @@ -46,6 +50,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 ch3, 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 task0 = &mut inner.tasks[0]; @@ -60,18 +68,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 current = inner.current_task; inner.tasks[current].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 current = inner.current_task; inner.tasks[current].task_status = TaskStatus::Exited; } + /// Find next task to run and return app 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; @@ -80,6 +93,8 @@ impl TaskManager { .find(|id| inner.tasks[*id].task_status == TaskStatus::Ready) } + /// 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(); diff --git a/os/src/timer.rs b/os/src/timer.rs index 048aa3b7..1d101d43 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -5,14 +5,17 @@ use riscv::register::time; const TICKS_PER_SEC: usize = 100; const MSEC_PER_SEC: usize = 1000; +/// read the `mtime` register pub fn get_time() -> usize { time::read() } +/// get current time in milliseconds 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/mod.rs b/os/src/trap/mod.rs index 527d6b4b..dcb4c2bb 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -12,6 +12,7 @@ use riscv::register::{ global_asm!(include_str!("trap.S")); +/// initialize CSR `stvec` as the entry of `__alltraps` pub fn init() { extern "C" { fn __alltraps(); @@ -21,6 +22,7 @@ pub fn init() { } } +/// timer interrupt enabled pub fn enable_timer_interrupt() { unsafe { sie::set_stimer(); @@ -28,9 +30,10 @@ pub fn enable_timer_interrupt() { } #[no_mangle] +/// handle an interrupt, exception, or system call from user space pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext { - let scause = scause::read(); - let stval = stval::read(); + let scause = scause::read(); // get trap cause + let stval = stval::read(); // get extra value match scause.cause() { Trap::Exception(Exception::UserEnvCall) => { cx.sepc += 4;