添加了任务管理TaskManager的子功能, 修改了sys_exit为使用 switch进行切换

ch3
zhangxinyu 2 years ago
parent feebb265d1
commit 8b3ae72470

@ -1,111 +1,111 @@
use core::arch::asm; // use core::arch::asm;
use lazy_static::*; // use lazy_static::*;
use riscv::register::mcause::Trap; // use riscv::register::mcause::Trap;
use crate::println; // use crate::println;
use crate::sbi::shutdown; // use crate::sbi::shutdown;
use crate::sync::UPSafeCell; // use crate::sync::UPSafeCell;
use crate::trap::TrapContext; // use crate::trap::TrapContext;
//
const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb // const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb
const KERNEL_STACK_SIZE: usize = 4096 * 2; // const KERNEL_STACK_SIZE: usize = 4096 * 2;
//
const MAX_APP_NUM: usize = 16; // 系统最大支持的运行程序数量 // const MAX_APP_NUM: usize = 16; // 系统最大支持的运行程序数量
//
const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址 // const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址
const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 // const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小
//
// 在此之后 应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用(首次运行run_next_app时被接管了 mv sp, a0) // // 在此之后 应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用(首次运行run_next_app时被接管了 mv sp, a0)
// KERNEL_STACK 保存的是 Trap Context // // KERNEL_STACK 保存的是 Trap Context
//
static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE]; // static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE];
static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE]; // static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE];
//
lazy_static! { // lazy_static! {
static ref APP_MANAGER: UPSafeCell<AppManager> = unsafe { // static ref APP_MANAGER: UPSafeCell<AppManager> = unsafe {
UPSafeCell::new({ // UPSafeCell::new({
extern "C" { // extern "C" {
fn _num_app(); // fn _num_app();
} // }
let num_app_ptr = _num_app as usize as *const usize; // let num_app_ptr = _num_app as usize as *const usize;
let num_app = num_app_ptr.read_volatile(); // 用户app的总数量 // let num_app = num_app_ptr.read_volatile(); // 用户app的总数量
//
let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; // 创建一个数组, 用来保存每个app的起始位置 // let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; // 创建一个数组, 用来保存每个app的起始位置
//
// 得到每个app的起始地址 // // 得到每个app的起始地址
let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; // let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1];
let app_start_raw: &[usize] = // let app_start_raw: &[usize] =
core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1); // core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1);
app_start_lis[..=num_app].copy_from_slice(app_start_raw); // app_start_lis[..=num_app].copy_from_slice(app_start_raw);
//
AppManager{ // AppManager{
num_app, // num_app,
current_app: 0, // current_app: 0,
app_start_lis // app_start_lis
} // }
}) // })
}; // };
} // }
//
// 由build.rs 生成的link_app.S, 根据里面的信息生成的结构体 // // 由build.rs 生成的link_app.S, 根据里面的信息生成的结构体
struct AppManager { // struct AppManager {
num_app: usize, // 用户app数量 // num_app: usize, // 用户app数量
current_app: usize, // 当前需要执行的第几个app // current_app: usize, // 当前需要执行的第几个app
app_start_lis: [usize; MAX_APP_NUM + 1], // 保存了每个app的起始位置, 后面会跳到这里, +1 是因为end的位置也占了一个usize, 需要知道end的位置 // app_start_lis: [usize; MAX_APP_NUM + 1], // 保存了每个app的起始位置, 后面会跳到这里, +1 是因为end的位置也占了一个usize, 需要知道end的位置
} // }
//
impl AppManager{ // impl AppManager{
fn show_app_info(&self){ // fn show_app_info(&self){
println!("[kernel] num_app = {}", self.num_app); // println!("[kernel] num_app = {}", self.num_app);
for i in 0..self.num_app { // for i in 0..self.num_app {
println!( // println!(
"[kernel] app_{} ({:#x}, {:#x})", // "[kernel] app_{} ({:#x}, {:#x})",
i, // i,
self.app_start_lis[i], // self.app_start_lis[i],
self.app_start_lis[i + 1] // self.app_start_lis[i + 1]
); // );
} // }
} // }
} // }
//
//
pub fn init() { // pub fn init() {
APP_MANAGER.exclusive_access().show_app_info(); // APP_MANAGER.exclusive_access().show_app_info();
} // }
//
pub fn run_next_app() -> ! { // pub fn run_next_app() -> ! {
// 得到下一个需要运行的app的入口地址 // // 得到下一个需要运行的app的入口地址
let mut app_manager = APP_MANAGER.exclusive_access(); // let mut app_manager = APP_MANAGER.exclusive_access();
let current_app = app_manager.current_app; // let current_app = app_manager.current_app;
if current_app >= app_manager.num_app { // if current_app >= app_manager.num_app {
shutdown(); // shutdown();
} // }
let app_entry_ptr = app_manager.app_start_lis[current_app]; // let app_entry_ptr = app_manager.app_start_lis[current_app];
println!("------------- run_next_app load app {}, {:x}", current_app, app_entry_ptr); // println!("------------- run_next_app load app {}, {:x}", current_app, app_entry_ptr);
app_manager.current_app += 1; // app_manager.current_app += 1;
drop(app_manager); // drop(app_manager);
//
//
extern "C" { // extern "C" {
fn __restore(trap_context_ptr: usize); // fn __restore(trap_context_ptr: usize);
} // }
//
unsafe { // unsafe {
// 得到用户栈的栈顶 // // 得到用户栈的栈顶
let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE; // let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE;
// 得到用户trap的上下文以及寄存器状态 // // 得到用户trap的上下文以及寄存器状态
let user_trap_context = TrapContext::from(app_entry_ptr, user_stack_top); // let user_trap_context = TrapContext::from(app_entry_ptr, user_stack_top);
//
// 把用户trap copy到内核栈 // // 把用户trap copy到内核栈
let kernel_stack_top = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE; // 现在栈顶和栈底都在一个内存位置 // let kernel_stack_top = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE; // 现在栈顶和栈底都在一个内存位置
// 为trap context 分配栈空间 // // 为trap context 分配栈空间
let kernel_trap_context_ptr = (kernel_stack_top - core::mem::size_of::<TrapContext>()) as * mut TrapContext; // let kernel_trap_context_ptr = (kernel_stack_top - core::mem::size_of::<TrapContext>()) as * mut TrapContext;
//
unsafe { // unsafe {
// 把user_trap_context copy到内核栈顶 // // 把user_trap_context copy到内核栈顶
*kernel_trap_context_ptr = user_trap_context; // *kernel_trap_context_ptr = user_trap_context;
// 返回现在的内核栈顶 // // 返回现在的内核栈顶
__restore(kernel_trap_context_ptr as *const _ as usize); // __restore(kernel_trap_context_ptr as *const _ as usize);
} // }
} // }
panic!("Unreachable in batch::run_current_app!"); // panic!("Unreachable in batch::run_current_app!");
} // }

@ -3,7 +3,7 @@ use core::arch::asm;
use crate::config::*; use crate::config::*;
use crate::trap::TrapContext; use crate::trap::TrapContext;
static KERNEL_STACK: [[u8; KERNEL_STACK_SIZE]; MAX_APP_NUM] = [[0; KERNEL_STACK_SIZE]; MAX_APP_NUM]; // 这一章, 每个用户应用对应一个内核栈 [内核栈; 总应用数] static KERNEL_STACK: [[u8; KERNEL_STACK_SIZE]; MAX_APP_NUM] = [[0; KERNEL_STACK_SIZE]; MAX_APP_NUM]; // 这一章, 每个用户应用对应一个内核栈 [每个应用自己的内核栈; 总应用数]
static USER_STACK: [[u8; USER_STACK_SIZE]; MAX_APP_NUM] = [[0; USER_STACK_SIZE]; MAX_APP_NUM]; // 这一行每个用户应用对应一个应用栈 static USER_STACK: [[u8; USER_STACK_SIZE]; MAX_APP_NUM] = [[0; USER_STACK_SIZE]; MAX_APP_NUM]; // 这一行每个用户应用对应一个应用栈
extern "C" { extern "C" {

@ -8,7 +8,7 @@ use lang_items::console;
pub mod lang_items; pub mod lang_items;
pub mod sbi; pub mod sbi;
pub mod batch; // pub mod batch;
pub mod sync; pub mod sync;
pub mod trap; pub mod trap;
pub mod syscall; pub mod syscall;

@ -1,9 +1,11 @@
//! App management syscalls //! App management syscalls
use crate::batch::run_next_app; // use crate::batch::run_next_app;
use crate::println; use crate::println;
use crate::task::exit_current_and_run_next;
/// 任务退出, 并立即切换任务 /// 任务退出, 并立即切换任务
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);
run_next_app() exit_current_and_run_next();
panic!("Unreachable in sys_exit!");
} }

@ -27,8 +27,8 @@ impl TaskContext{
fn __restore(); fn __restore();
} }
Self { Self {
ra: __restore as usize, ra: __restore as usize, // 新创建的任务, 在switch ret 之后 直接进入 trap返回函数
sp: kernel_stack_ptr, sp: kernel_stack_ptr, // 这里设置 应用内核栈的栈顶了, 后面会被switch 恢复, 所以我们在trap.S中 注释mv sp, a0
s: [0; 12], s: [0; 12],
} }
} }

@ -5,6 +5,7 @@ use crate::task::task::{TaskControlBlock, TaskStatus};
use crate::loader::{get_num_app, init_app_cx}; use crate::loader::{get_num_app, init_app_cx};
use crate::println; use crate::println;
use crate::task::context::TaskContext; use crate::task::context::TaskContext;
use crate::task::switch::__switch;
mod context; mod context;
mod switch; mod switch;
@ -19,7 +20,89 @@ pub struct TaskManager {
impl TaskManager { impl TaskManager {
fn run_first_task(&self){ fn run_first_task(&self){
println!("run_first_task"); // 得到下一个需要执行的任务,的上下文 这里我们由于第一次执行, 下一个任务我们指定为0下标的任务即可
let next_task_context_ptr = {
let mut inner = self.inner.exclusive_access();
let task_0 = &mut inner.tasks[0];
// 修改任务0的状态
task_0.task_status = TaskStatus::Running;
&(task_0.task_cx) as *const TaskContext
};
// 由于第一次切换, 我们current task context 不存在, 所以我们手动创建一个, 在调用switch的时候
// 这里调用switch的状态会被保存在unused 这里, 但是一旦程序开始运行, 就开始在内核栈或者用户栈之间切换, 永远
// 不会走到这里了
let mut unused = TaskContext::new();
unsafe {
__switch(&mut unused as *mut TaskContext, next_task_context_ptr)
}
//
panic!("unreachable in run_first_task!");
}
// 停止当前正在运行的任务
fn mark_current_exit(&self){
let mut inner = self.inner.exclusive_access();
let current_task_id = inner.current_task_id;
let current_task = &mut inner.tasks[current_task_id];
current_task.task_status = TaskStatus::Exited;
}
// 挂起当前任务
fn mark_current_suspend(&self){
let mut inner = self.inner.exclusive_access();
let current_task_id = inner.current_task_id;
let current_task = &mut inner.tasks[current_task_id];
current_task.task_status = TaskStatus::Ready;
}
// 运行下一个任务
fn run_next_task(&self){
if let Some(next_task_id) = self.find_next_task() {
// 得到当前任务context ptr 以及 下一个任务context的ptr
let (current_task_ptr,next_task_ptr) = {
let mut inner = self.inner.exclusive_access();
// 当前任务id
let current_task_id = inner.current_task_id;
// 修改current_task_id 为 下一个任务, 因为一旦到switch就是在运行下一个任务了
inner.current_task_id = next_task_id;
// 修改下一个任务的状态
inner.tasks[next_task_id].task_status = TaskStatus::Running;
// 得到current的ptr
let current_task_ptr = &mut inner.tasks[current_task_id].task_cx as *mut TaskContext;
// 得到需要被切换的下一个任务ptr
let next_task_ptr = &inner.tasks[next_task_id].task_cx as *const TaskContext;
(current_task_ptr, next_task_ptr)
};
// 开始伟大的切换!
unsafe {
__switch(current_task_ptr, next_task_ptr);
}
} else {
panic!("All applications completed!");
}
}
// 找到一个除当前任务之外的 是Ready状态的任务的id
fn find_next_task(&self) -> Option<usize>{
let mut inner = self.inner.exclusive_access();
let current = inner.current_task_id;
for task_id in current + 1..current + self.num_app + 1 {
let _tmp_id = task_id % self.num_app;
if inner.tasks[_tmp_id].task_status == TaskStatus::Ready {
return Some(_tmp_id)
}
}
None
} }
} }
@ -27,7 +110,7 @@ impl TaskManager {
// 不公开的结构体, 有一个MAX_APP_NUM大小的数组, 用来保存TCB, 和当前任务的的TCB的下标 // 不公开的结构体, 有一个MAX_APP_NUM大小的数组, 用来保存TCB, 和当前任务的的TCB的下标
struct TaskManagerInner { struct TaskManagerInner {
tasks: [TaskControlBlock; MAX_APP_NUM], tasks: [TaskControlBlock; MAX_APP_NUM],
current_task: usize, current_task_id: usize,
} }
lazy_static!{ lazy_static!{
@ -60,12 +143,12 @@ lazy_static!{
tasks[i].task_status = TaskStatus::Ready tasks[i].task_status = TaskStatus::Ready
}; };
TaskManager { TaskManager { // 直接返回即可, 所有字段都是sync的, 那这个结构体也是sync
num_app, num_app,
inner: unsafe { inner: unsafe {
UPSafeCell::new(TaskManagerInner { UPSafeCell::new(TaskManagerInner {
tasks, tasks,
current_task: 0, current_task_id: 0,
}) })
} }
} }
@ -73,6 +156,19 @@ lazy_static!{
} }
// 由内核调用, 在main中, 用来 作为执行用户应用的开端
pub fn run_first_task() { pub fn run_first_task() {
TASK_MANAGER.run_first_task(); TASK_MANAGER.run_first_task();
} }
// 挂起当前任务, 并运行下一个
pub fn suspend_current_and_run_next(){
TASK_MANAGER.mark_current_suspend();
TASK_MANAGER.run_next_task();
}
// 退出当前任务, 并运行下一个
pub fn exit_current_and_run_next(){
TASK_MANAGER.mark_current_exit();
TASK_MANAGER.run_next_task();
}

@ -7,7 +7,7 @@ use riscv::register::{
stval, stvec, stval, stvec,
}; };
pub use context::TrapContext; pub use context::TrapContext;
use crate::batch::run_next_app; // use crate::batch::run_next_app;
use crate::println; use crate::println;
use crate::syscall::syscall; use crate::syscall::syscall;
@ -43,12 +43,12 @@ pub fn trap_handler(trap_context: &mut TrapContext) -> &mut TrapContext {
// 访问不允许的内存 // 访问不允许的内存
Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => { Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => {
println!("[kernel] PageFault in application, kernel killed it."); println!("[kernel] PageFault in application, kernel killed it.");
run_next_app(); // run_next_app();
} }
// 非法指令 // 非法指令
Trap::Exception(Exception::IllegalInstruction) => { Trap::Exception(Exception::IllegalInstruction) => {
println!("[kernel] IllegalInstruction in application, kernel killed it."); println!("[kernel] IllegalInstruction in application, kernel killed it.");
run_next_app(); // run_next_app();
} }
// 未知错误 // 未知错误
_ => { _ => {

@ -43,7 +43,9 @@ __alltraps: # __alltraps 符号的实现
__restore: # __restore __restore: # __restore
# case1: # case1:
# case2: U # case2: U
mv sp, a0 # a0 sp sp KERNEL_STACK_SIZE,
# , switch
# mv sp, a0 # a0 sp sp KERNEL_STACK_SIZE,
# sstatus/sepc # sstatus/sepc
ld t0, 32*8(sp) # sstatus ld t0, 32*8(sp) # sstatus

Loading…
Cancel
Save