mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 17:36:25 +04:00
Merge remote-tracking branch 'wrk/ch3-coop_doc' into ch3-coop
This commit is contained in:
commit
25e2e1cac4
@ -41,10 +41,12 @@ impl UserStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get base address of app i.
|
||||||
fn get_base_i(app_id: usize) -> usize {
|
fn get_base_i(app_id: usize) -> usize {
|
||||||
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
|
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the total number of applications.
|
||||||
pub fn get_num_app() -> usize {
|
pub fn get_num_app() -> usize {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn _num_app();
|
fn _num_app();
|
||||||
@ -52,6 +54,8 @@ pub fn get_num_app() -> usize {
|
|||||||
unsafe { (_num_app as usize as *const usize).read_volatile() }
|
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() {
|
pub fn load_apps() {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn _num_app();
|
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 {
|
pub fn init_app_cx(app_id: usize) -> usize {
|
||||||
KERNEL_STACK[app_id].push_context(TrapContext::app_init_context(
|
KERNEL_STACK[app_id].push_context(TrapContext::app_init_context(
|
||||||
get_base_i(app_id),
|
get_base_i(app_id),
|
||||||
|
@ -27,14 +27,17 @@ fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// use sbi call to putchar in console (qemu uart handler)
|
||||||
pub fn console_putchar(c: usize) {
|
pub fn console_putchar(c: usize) {
|
||||||
sbi_call(SBI_CONSOLE_PUTCHAR, c, 0, 0);
|
sbi_call(SBI_CONSOLE_PUTCHAR, c, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
pub fn shutdown() -> ! {
|
pub fn shutdown() -> ! {
|
||||||
sbi_call(SBI_SHUTDOWN, 0, 0, 0);
|
sbi_call(SBI_SHUTDOWN, 0, 0, 0);
|
||||||
panic!("It should shutdown!");
|
panic!("It should shutdown!");
|
||||||
|
@ -9,6 +9,7 @@ mod process;
|
|||||||
use fs::*;
|
use fs::*;
|
||||||
use process::*;
|
use process::*;
|
||||||
|
|
||||||
|
/// handle syscall exception with `syscall_id` and other arguments
|
||||||
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
match syscall_id {
|
match syscall_id {
|
||||||
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
|
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
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};
|
||||||
|
|
||||||
|
/// task exits and submit an exit code
|
||||||
pub fn sys_exit(exit_code: i32) -> ! {
|
pub fn sys_exit(exit_code: i32) -> ! {
|
||||||
println!("[kernel] Application exited with code {}", exit_code);
|
println!("[kernel] Application exited with code {}", exit_code);
|
||||||
exit_current_and_run_next();
|
exit_current_and_run_next();
|
||||||
panic!("Unreachable in sys_exit!");
|
panic!("Unreachable in sys_exit!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// current task gives up resources for other tasks
|
||||||
pub fn sys_yield() -> isize {
|
pub fn sys_yield() -> isize {
|
||||||
suspend_current_and_run_next();
|
suspend_current_and_run_next();
|
||||||
0
|
0
|
||||||
|
@ -14,12 +14,16 @@ use task::{TaskControlBlock, TaskStatus};
|
|||||||
pub use context::TaskContext;
|
pub use context::TaskContext;
|
||||||
|
|
||||||
pub struct TaskManager {
|
pub struct TaskManager {
|
||||||
|
/// total number of tasks
|
||||||
num_app: usize,
|
num_app: usize,
|
||||||
|
/// use inner value to get mutable access
|
||||||
inner: UPSafeCell<TaskManagerInner>,
|
inner: UPSafeCell<TaskManagerInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TaskManagerInner {
|
struct TaskManagerInner {
|
||||||
|
/// task list
|
||||||
tasks: [TaskControlBlock; MAX_APP_NUM],
|
tasks: [TaskControlBlock; MAX_APP_NUM],
|
||||||
|
/// id of current `Running` task
|
||||||
current_task: usize,
|
current_task: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +51,10 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TaskManager {
|
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) -> ! {
|
fn run_first_task(&self) -> ! {
|
||||||
let mut inner = self.inner.exclusive_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
let task0 = &mut inner.tasks[0];
|
let task0 = &mut inner.tasks[0];
|
||||||
@ -61,18 +69,23 @@ impl TaskManager {
|
|||||||
panic!("unreachable in run_first_task!");
|
panic!("unreachable in run_first_task!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the status of current `Running` task into `Ready`.
|
||||||
fn mark_current_suspended(&self) {
|
fn mark_current_suspended(&self) {
|
||||||
let mut inner = self.inner.exclusive_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
let current = inner.current_task;
|
let current = inner.current_task;
|
||||||
inner.tasks[current].task_status = TaskStatus::Ready;
|
inner.tasks[current].task_status = TaskStatus::Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the status of current `Running` task into `Exited`.
|
||||||
fn mark_current_exited(&self) {
|
fn mark_current_exited(&self) {
|
||||||
let mut inner = self.inner.exclusive_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
let current = inner.current_task;
|
let current = inner.current_task;
|
||||||
inner.tasks[current].task_status = TaskStatus::Exited;
|
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<usize> {
|
fn find_next_task(&self) -> Option<usize> {
|
||||||
let inner = self.inner.exclusive_access();
|
let inner = self.inner.exclusive_access();
|
||||||
let current = inner.current_task;
|
let current = inner.current_task;
|
||||||
@ -81,6 +94,8 @@ impl TaskManager {
|
|||||||
.find(|id| inner.tasks[*id].task_status == TaskStatus::Ready)
|
.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) {
|
fn run_next_task(&self) {
|
||||||
if let Some(next) = self.find_next_task() {
|
if let Some(next) = self.find_next_task() {
|
||||||
let mut inner = self.inner.exclusive_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
|
@ -10,6 +10,7 @@ use riscv::register::{
|
|||||||
|
|
||||||
global_asm!(include_str!("trap.S"));
|
global_asm!(include_str!("trap.S"));
|
||||||
|
|
||||||
|
/// initialize CSR `stvec` as the entry of `__alltraps`
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn __alltraps();
|
fn __alltraps();
|
||||||
@ -20,9 +21,10 @@ pub fn init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
/// handle an interrupt, exception, or system call from user space
|
||||||
pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
|
pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
|
||||||
let scause = scause::read();
|
let scause = scause::read(); // get trap cause
|
||||||
let stval = stval::read();
|
let stval = stval::read(); // get extra value
|
||||||
match scause.cause() {
|
match scause.cause() {
|
||||||
Trap::Exception(Exception::UserEnvCall) => {
|
Trap::Exception(Exception::UserEnvCall) => {
|
||||||
cx.sepc += 4;
|
cx.sepc += 4;
|
||||||
|
Loading…
Reference in New Issue
Block a user