diff --git a/.gitignore b/.gitignore index 770aba77..9fc90c58 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ easy-fs-fuse/Cargo.lock easy-fs-fuse/target/* tools/ pushall.sh +*.bak diff --git a/os/src/console.rs b/os/src/console.rs index dda4911a..cc6a91bf 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}; @@ -16,6 +18,7 @@ pub fn print(args: fmt::Arguments) { Stdout.write_fmt(args).unwrap(); } +/// print string macro #[macro_export] macro_rules! print { ($fmt: literal $(, $($arg: tt)+)?) => { @@ -23,6 +26,7 @@ macro_rules! print { } } +/// println string macro #[macro_export] macro_rules! println { ($fmt: literal $(, $($arg: tt)+)?) => { diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index af3e5152..db902c35 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -1,3 +1,5 @@ +//! The panic handler + use crate::sbi::shutdown; use core::panic::PanicInfo; diff --git a/os/src/main.rs b/os/src/main.rs index 7c661b43..cdeced1a 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,3 +1,21 @@ +//! 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 +//! - [`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 [`batch::run_next_app()`] and for the first time go to +//! userspace. + +#![deny(missing_docs)] +#![deny(warnings)] #![no_std] #![no_main] #![feature(panic_info_message)] @@ -16,6 +34,8 @@ mod trap; global_asm!(include_str!("entry.asm")); global_asm!(include_str!("link_app.S")); + +/// clear BSS segment fn clear_bss() { extern "C" { fn sbss(); @@ -27,6 +47,7 @@ fn clear_bss() { } } +/// the rust entry-point of os #[no_mangle] pub fn rust_main() -> ! { clear_bss(); diff --git a/os/src/sbi.rs b/os/src/sbi.rs index f66d9751..c8537366 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -1,17 +1,18 @@ -#![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_SHUTDOWN: usize = 8; +// const SBI_SET_TIMER: usize = 0; +// 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; +/// handle SBI call with `which` SBI_id and other arguments #[inline(always)] fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { let mut ret; @@ -33,9 +34,9 @@ pub fn console_putchar(c: usize) { } /// use sbi call to getchar from console (qemu uart handler) -pub fn console_getchar() -> usize { - sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) -} +// pub fn console_getchar() -> usize { +// sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) +// } /// use sbi call to shutdown the kernel pub fn 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..e8ba20c8 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 @@ -22,7 +24,7 @@ impl UPSafeCell { inner: RefCell::new(value), } } - /// Panic if the data has been borrowed. + /// Exclusive access inner data in UPSafeCell. Panic if the data has been borrowed. pub fn exclusive_access(&self) -> RefMut<'_, T> { self.inner.borrow_mut() } diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 3e38eae7..2174f26e 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -1,5 +1,8 @@ +//! File and filesystem-related syscalls + const FD_STDOUT: usize = 1; +/// write buf of length `len` to a file with `fd` pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { match fd { FD_STDOUT => { diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 5b409e98..42e339fa 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; diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 79a2522c..c63265d4 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,3 +1,4 @@ +//! App management syscalls use crate::batch::run_next_app; /// task exits and submit an exit code diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index b6fdabab..86519985 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -1,3 +1,17 @@ +//! 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::batch::run_next_app;