mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-24 10:26:25 +04:00
add #![deny(missing_docs)] AND #![deny(warnings)] in main.rs, and add more comments
This commit is contained in:
parent
8730000045
commit
716c236f14
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@ easy-fs-fuse/Cargo.lock
|
|||||||
easy-fs-fuse/target/*
|
easy-fs-fuse/target/*
|
||||||
tools/
|
tools/
|
||||||
pushall.sh
|
pushall.sh
|
||||||
|
*.bak
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
//! Constants used in rCore for K210 devel board
|
||||||
|
|
||||||
pub const CLOCK_FREQ: usize = 403000000 / 62;
|
pub const CLOCK_FREQ: usize = 403000000 / 62;
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
//! Constants used in rCore for K210 devel board
|
||||||
|
|
||||||
pub const CLOCK_FREQ: usize = 12500000;
|
pub const CLOCK_FREQ: usize = 12500000;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
pub const USER_STACK_SIZE: usize = 4096 * 2;
|
//! Constants used in rCore
|
||||||
|
|
||||||
|
pub const USER_STACK_SIZE: usize = 4096;
|
||||||
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
||||||
pub const MAX_APP_NUM: usize = 4;
|
pub const MAX_APP_NUM: usize = 4;
|
||||||
pub const APP_BASE_ADDRESS: usize = 0x80400000;
|
pub const APP_BASE_ADDRESS: usize = 0x80400000;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! SBI console driver, for text output
|
||||||
|
|
||||||
use crate::sbi::console_putchar;
|
use crate::sbi::console_putchar;
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ pub fn print(args: fmt::Arguments) {
|
|||||||
Stdout.write_fmt(args).unwrap();
|
Stdout.write_fmt(args).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// print string macro
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||||
@ -23,6 +26,7 @@ macro_rules! print {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// println string macro
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The panic handler
|
||||||
|
|
||||||
use crate::sbi::shutdown;
|
use crate::sbi::shutdown;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
//! Loading user applications into memory
|
||||||
|
//!
|
||||||
|
//! For chapter 3, user applications are simply part of the data included in the
|
||||||
|
//! kernel binary, so we only need to copy them to the space allocated for each
|
||||||
|
//! app to load them. We also allocate fixed spaces for each task's
|
||||||
|
//! [`KernelStack`] and [`UserStack`].
|
||||||
|
|
||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
use crate::trap::TrapContext;
|
use crate::trap::TrapContext;
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
@ -1,3 +1,22 @@
|
|||||||
|
//! 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.
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
@ -25,6 +44,8 @@ mod trap;
|
|||||||
global_asm!(include_str!("entry.asm"));
|
global_asm!(include_str!("entry.asm"));
|
||||||
global_asm!(include_str!("link_app.S"));
|
global_asm!(include_str!("link_app.S"));
|
||||||
|
|
||||||
|
|
||||||
|
/// clear BSS segment
|
||||||
fn clear_bss() {
|
fn clear_bss() {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn sbss();
|
fn sbss();
|
||||||
@ -36,6 +57,7 @@ fn clear_bss() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// the rust entry-point of os
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn rust_main() -> ! {
|
pub fn rust_main() -> ! {
|
||||||
clear_bss();
|
clear_bss();
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
#![allow(unused)]
|
//! SBI call wrappers
|
||||||
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
const SBI_SET_TIMER: usize = 0;
|
const SBI_SET_TIMER: usize = 0;
|
||||||
const SBI_CONSOLE_PUTCHAR: usize = 1;
|
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_SHUTDOWN: usize = 8;
|
||||||
|
// 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)]
|
#[inline(always)]
|
||||||
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
|
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
|
||||||
let mut ret;
|
let mut ret;
|
||||||
@ -38,9 +39,9 @@ pub fn console_putchar(c: usize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// use sbi call to getchar from console (qemu uart handler)
|
/// use sbi call to getchar from console (qemu uart handler)
|
||||||
pub fn console_getchar() -> usize {
|
// pub fn console_getchar() -> usize {
|
||||||
sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
// sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// use sbi call to shutdown the kernel
|
/// use sbi call to shutdown the kernel
|
||||||
pub fn shutdown() -> ! {
|
pub fn shutdown() -> ! {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Synchronization and interior mutability primitives
|
||||||
|
|
||||||
mod up;
|
mod up;
|
||||||
|
|
||||||
pub use up::UPSafeCell;
|
pub use up::UPSafeCell;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Uniprocessor interior mutability primitives
|
||||||
|
|
||||||
use core::cell::{RefCell, RefMut};
|
use core::cell::{RefCell, RefMut};
|
||||||
|
|
||||||
/// Wrap a static data structure inside it so that we are
|
/// Wrap a static data structure inside it so that we are
|
||||||
@ -22,7 +24,7 @@ impl<T> UPSafeCell<T> {
|
|||||||
inner: RefCell::new(value),
|
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> {
|
pub fn exclusive_access(&self) -> RefMut<'_, T> {
|
||||||
self.inner.borrow_mut()
|
self.inner.borrow_mut()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
//! File and filesystem-related syscalls
|
||||||
|
|
||||||
const FD_STDOUT: usize = 1;
|
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 {
|
pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
|
||||||
match fd {
|
match fd {
|
||||||
FD_STDOUT => {
|
FD_STDOUT => {
|
||||||
|
@ -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_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
const SYSCALL_YIELD: usize = 124;
|
const SYSCALL_YIELD: usize = 124;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! Process management syscalls
|
||||||
use crate::task::{exit_current_and_run_next, suspend_current_and_run_next};
|
use crate::task::{exit_current_and_run_next, suspend_current_and_run_next};
|
||||||
use crate::timer::get_time_ms;
|
use crate::timer::get_time_ms;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Implementation of [`TaskContext`]
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TaskContext {
|
pub struct TaskContext {
|
||||||
|
@ -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 context;
|
||||||
mod switch;
|
mod switch;
|
||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
@ -12,6 +23,15 @@ use task::{TaskControlBlock, TaskStatus};
|
|||||||
|
|
||||||
pub use context::TaskContext;
|
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 {
|
pub struct TaskManager {
|
||||||
/// total number of tasks
|
/// total number of tasks
|
||||||
num_app: usize,
|
num_app: usize,
|
||||||
@ -82,7 +102,7 @@ impl TaskManager {
|
|||||||
inner.tasks[current].task_status = TaskStatus::Exited;
|
inner.tasks[current].task_status = TaskStatus::Exited;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find next task to run and return app id.
|
/// Find next task to run and return task id.
|
||||||
///
|
///
|
||||||
/// In this case, we only return the first `Ready` task in task list.
|
/// In this case, we only return the first `Ready` task in task list.
|
||||||
fn find_next_task(&self) -> Option<usize> {
|
fn find_next_task(&self) -> Option<usize> {
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
|
//! 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`.
|
||||||
|
|
||||||
use super::TaskContext;
|
use super::TaskContext;
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
|
|
||||||
global_asm!(include_str!("switch.S"));
|
global_asm!(include_str!("switch.S"));
|
||||||
|
|
||||||
extern "C" {
|
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);
|
pub fn __switch(current_task_cx_ptr: *mut TaskContext, next_task_cx_ptr: *const TaskContext);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
//! Types related to task management
|
||||||
|
|
||||||
use super::TaskContext;
|
use super::TaskContext;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct TaskControlBlock {
|
pub struct TaskControlBlock {
|
||||||
pub task_status: TaskStatus,
|
pub task_status: TaskStatus,
|
||||||
pub task_cx: TaskContext,
|
pub task_cx: TaskContext,
|
||||||
|
// LAB1: Add whatever you need about the Task.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! RISC-V timer-related functionality
|
||||||
|
|
||||||
use crate::config::CLOCK_FREQ;
|
use crate::config::CLOCK_FREQ;
|
||||||
use crate::sbi::set_timer;
|
use crate::sbi::set_timer;
|
||||||
use riscv::register::time;
|
use riscv::register::time;
|
||||||
|
@ -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;
|
mod context;
|
||||||
|
|
||||||
use crate::syscall::syscall;
|
use crate::syscall::syscall;
|
||||||
|
Loading…
Reference in New Issue
Block a user