From 8b3ae72470aeda62ceda5fe58993a04c770c20e8 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 24 May 2023 15:20:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=AE=A1=E7=90=86TaskManager=E7=9A=84=E5=AD=90=E5=8A=9F?= =?UTF-8?q?=E8=83=BD,=20=E4=BF=AE=E6=94=B9=E4=BA=86sys=5Fexit=E4=B8=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20switch=E8=BF=9B=E8=A1=8C=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch3/os/src/batch.rs | 222 +++++++++++++++++----------------- ch3/os/src/loader.rs | 2 +- ch3/os/src/main.rs | 2 +- ch3/os/src/syscall/process.rs | 6 +- ch3/os/src/task/context.rs | 4 +- ch3/os/src/task/mod.rs | 104 +++++++++++++++- ch3/os/src/trap/mod.rs | 6 +- ch3/os/src/trap/trap.S | 4 +- 8 files changed, 225 insertions(+), 125 deletions(-) diff --git a/ch3/os/src/batch.rs b/ch3/os/src/batch.rs index 717883d..61fb098 100644 --- a/ch3/os/src/batch.rs +++ b/ch3/os/src/batch.rs @@ -1,111 +1,111 @@ -use core::arch::asm; -use lazy_static::*; -use riscv::register::mcause::Trap; -use crate::println; -use crate::sbi::shutdown; -use crate::sync::UPSafeCell; -use crate::trap::TrapContext; - -const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb -const KERNEL_STACK_SIZE: usize = 4096 * 2; - -const MAX_APP_NUM: usize = 16; // 系统最大支持的运行程序数量 - -const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址 -const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 - -// 在此之后 应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用(首次运行run_next_app时被接管了 mv sp, a0) -// KERNEL_STACK 保存的是 Trap Context - -static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE]; -static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE]; - -lazy_static! { - static ref APP_MANAGER: UPSafeCell = unsafe { - UPSafeCell::new({ - extern "C" { - fn _num_app(); - } - let num_app_ptr = _num_app as usize as *const usize; - 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的起始位置 - - // 得到每个app的起始地址 - let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; - let app_start_raw: &[usize] = - core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1); - app_start_lis[..=num_app].copy_from_slice(app_start_raw); - - AppManager{ - num_app, - current_app: 0, - app_start_lis - } - }) - }; -} - -// 由build.rs 生成的link_app.S, 根据里面的信息生成的结构体 -struct AppManager { - num_app: usize, // 用户app数量 - current_app: usize, // 当前需要执行的第几个app - app_start_lis: [usize; MAX_APP_NUM + 1], // 保存了每个app的起始位置, 后面会跳到这里, +1 是因为end的位置也占了一个usize, 需要知道end的位置 -} - -impl AppManager{ - fn show_app_info(&self){ - println!("[kernel] num_app = {}", self.num_app); - for i in 0..self.num_app { - println!( - "[kernel] app_{} ({:#x}, {:#x})", - i, - self.app_start_lis[i], - self.app_start_lis[i + 1] - ); - } - } -} - - -pub fn init() { - APP_MANAGER.exclusive_access().show_app_info(); -} - -pub fn run_next_app() -> ! { - // 得到下一个需要运行的app的入口地址 - let mut app_manager = APP_MANAGER.exclusive_access(); - let current_app = app_manager.current_app; - if current_app >= app_manager.num_app { - shutdown(); - } - let app_entry_ptr = app_manager.app_start_lis[current_app]; - println!("------------- run_next_app load app {}, {:x}", current_app, app_entry_ptr); - app_manager.current_app += 1; - drop(app_manager); - - - extern "C" { - fn __restore(trap_context_ptr: usize); - } - - unsafe { - // 得到用户栈的栈顶 - let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE; - // 得到用户trap的上下文以及寄存器状态 - let user_trap_context = TrapContext::from(app_entry_ptr, user_stack_top); - - // 把用户trap copy到内核栈 - let kernel_stack_top = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE; // 现在栈顶和栈底都在一个内存位置 - // 为trap context 分配栈空间 - let kernel_trap_context_ptr = (kernel_stack_top - core::mem::size_of::()) as * mut TrapContext; - - unsafe { - // 把user_trap_context copy到内核栈顶 - *kernel_trap_context_ptr = user_trap_context; - // 返回现在的内核栈顶 - __restore(kernel_trap_context_ptr as *const _ as usize); - } - } - panic!("Unreachable in batch::run_current_app!"); -} +// use core::arch::asm; +// use lazy_static::*; +// use riscv::register::mcause::Trap; +// use crate::println; +// use crate::sbi::shutdown; +// use crate::sync::UPSafeCell; +// use crate::trap::TrapContext; +// +// const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb +// const KERNEL_STACK_SIZE: usize = 4096 * 2; +// +// const MAX_APP_NUM: usize = 16; // 系统最大支持的运行程序数量 +// +// const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址 +// const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 +// +// // 在此之后 应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用(首次运行run_next_app时被接管了 mv sp, a0) +// // KERNEL_STACK 保存的是 Trap Context +// +// static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE]; +// static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE]; +// +// lazy_static! { +// static ref APP_MANAGER: UPSafeCell = unsafe { +// UPSafeCell::new({ +// extern "C" { +// fn _num_app(); +// } +// let num_app_ptr = _num_app as usize as *const usize; +// 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的起始位置 +// +// // 得到每个app的起始地址 +// let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; +// let app_start_raw: &[usize] = +// core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1); +// app_start_lis[..=num_app].copy_from_slice(app_start_raw); +// +// AppManager{ +// num_app, +// current_app: 0, +// app_start_lis +// } +// }) +// }; +// } +// +// // 由build.rs 生成的link_app.S, 根据里面的信息生成的结构体 +// struct AppManager { +// num_app: usize, // 用户app数量 +// current_app: usize, // 当前需要执行的第几个app +// app_start_lis: [usize; MAX_APP_NUM + 1], // 保存了每个app的起始位置, 后面会跳到这里, +1 是因为end的位置也占了一个usize, 需要知道end的位置 +// } +// +// impl AppManager{ +// fn show_app_info(&self){ +// println!("[kernel] num_app = {}", self.num_app); +// for i in 0..self.num_app { +// println!( +// "[kernel] app_{} ({:#x}, {:#x})", +// i, +// self.app_start_lis[i], +// self.app_start_lis[i + 1] +// ); +// } +// } +// } +// +// +// pub fn init() { +// APP_MANAGER.exclusive_access().show_app_info(); +// } +// +// pub fn run_next_app() -> ! { +// // 得到下一个需要运行的app的入口地址 +// let mut app_manager = APP_MANAGER.exclusive_access(); +// let current_app = app_manager.current_app; +// if current_app >= app_manager.num_app { +// shutdown(); +// } +// let app_entry_ptr = app_manager.app_start_lis[current_app]; +// println!("------------- run_next_app load app {}, {:x}", current_app, app_entry_ptr); +// app_manager.current_app += 1; +// drop(app_manager); +// +// +// extern "C" { +// fn __restore(trap_context_ptr: usize); +// } +// +// unsafe { +// // 得到用户栈的栈顶 +// let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE; +// // 得到用户trap的上下文以及寄存器状态 +// let user_trap_context = TrapContext::from(app_entry_ptr, user_stack_top); +// +// // 把用户trap copy到内核栈 +// let kernel_stack_top = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE; // 现在栈顶和栈底都在一个内存位置 +// // 为trap context 分配栈空间 +// let kernel_trap_context_ptr = (kernel_stack_top - core::mem::size_of::()) as * mut TrapContext; +// +// unsafe { +// // 把user_trap_context copy到内核栈顶 +// *kernel_trap_context_ptr = user_trap_context; +// // 返回现在的内核栈顶 +// __restore(kernel_trap_context_ptr as *const _ as usize); +// } +// } +// panic!("Unreachable in batch::run_current_app!"); +// } diff --git a/ch3/os/src/loader.rs b/ch3/os/src/loader.rs index 5ef32bd..0afcb64 100644 --- a/ch3/os/src/loader.rs +++ b/ch3/os/src/loader.rs @@ -3,7 +3,7 @@ use core::arch::asm; use crate::config::*; 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]; // 这一行每个用户应用对应一个应用栈 extern "C" { diff --git a/ch3/os/src/main.rs b/ch3/os/src/main.rs index 0fce8c3..1cf5d04 100644 --- a/ch3/os/src/main.rs +++ b/ch3/os/src/main.rs @@ -8,7 +8,7 @@ use lang_items::console; pub mod lang_items; pub mod sbi; -pub mod batch; +// pub mod batch; pub mod sync; pub mod trap; pub mod syscall; diff --git a/ch3/os/src/syscall/process.rs b/ch3/os/src/syscall/process.rs index 6dbed6d..331d9b5 100644 --- a/ch3/os/src/syscall/process.rs +++ b/ch3/os/src/syscall/process.rs @@ -1,9 +1,11 @@ //! App management syscalls -use crate::batch::run_next_app; +// use crate::batch::run_next_app; use crate::println; +use crate::task::exit_current_and_run_next; /// 任务退出, 并立即切换任务 pub fn sys_exit(exit_code: i32) -> ! { println!("[kernel] Application exited with code {}", exit_code); - run_next_app() + exit_current_and_run_next(); + panic!("Unreachable in sys_exit!"); } diff --git a/ch3/os/src/task/context.rs b/ch3/os/src/task/context.rs index 4cea492..7552b75 100644 --- a/ch3/os/src/task/context.rs +++ b/ch3/os/src/task/context.rs @@ -27,8 +27,8 @@ impl TaskContext{ fn __restore(); } Self { - ra: __restore as usize, - sp: kernel_stack_ptr, + ra: __restore as usize, // 新创建的任务, 在switch ret 之后 直接进入 trap返回函数 + sp: kernel_stack_ptr, // 这里设置 应用内核栈的栈顶了, 后面会被switch 恢复, 所以我们在trap.S中 注释mv sp, a0 s: [0; 12], } } diff --git a/ch3/os/src/task/mod.rs b/ch3/os/src/task/mod.rs index 5c61ea8..f680a3f 100644 --- a/ch3/os/src/task/mod.rs +++ b/ch3/os/src/task/mod.rs @@ -5,6 +5,7 @@ use crate::task::task::{TaskControlBlock, TaskStatus}; use crate::loader::{get_num_app, init_app_cx}; use crate::println; use crate::task::context::TaskContext; +use crate::task::switch::__switch; mod context; mod switch; @@ -19,7 +20,89 @@ pub struct TaskManager { impl TaskManager { 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{ + 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的下标 struct TaskManagerInner { tasks: [TaskControlBlock; MAX_APP_NUM], - current_task: usize, + current_task_id: usize, } lazy_static!{ @@ -60,12 +143,12 @@ lazy_static!{ tasks[i].task_status = TaskStatus::Ready }; - TaskManager { + TaskManager { // 直接返回即可, 所有字段都是sync的, 那这个结构体也是sync num_app, inner: unsafe { UPSafeCell::new(TaskManagerInner { tasks, - current_task: 0, + current_task_id: 0, }) } } @@ -73,6 +156,19 @@ lazy_static!{ } +// 由内核调用, 在main中, 用来 作为执行用户应用的开端 pub fn 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(); +} diff --git a/ch3/os/src/trap/mod.rs b/ch3/os/src/trap/mod.rs index 79418b8..a9c43b2 100644 --- a/ch3/os/src/trap/mod.rs +++ b/ch3/os/src/trap/mod.rs @@ -7,7 +7,7 @@ use riscv::register::{ stval, stvec, }; pub use context::TrapContext; -use crate::batch::run_next_app; +// use crate::batch::run_next_app; use crate::println; 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) => { println!("[kernel] PageFault in application, kernel killed it."); - run_next_app(); + // run_next_app(); } // 非法指令 Trap::Exception(Exception::IllegalInstruction) => { println!("[kernel] IllegalInstruction in application, kernel killed it."); - run_next_app(); + // run_next_app(); } // 未知错误 _ => { diff --git a/ch3/os/src/trap/trap.S b/ch3/os/src/trap/trap.S index be27631..aa38042 100644 --- a/ch3/os/src/trap/trap.S +++ b/ch3/os/src/trap/trap.S @@ -43,7 +43,9 @@ __alltraps: # __alltraps 符号的实现 __restore: # __restore 符号的实现 # case1: 开始运行应用程序 # case2: 从处理完中断后返回 U 级别 - mv sp, a0 # 将 a0 中保存的内核栈地址赋值给 sp 这个首次进入是在内核进入首次进入sp 这里会被修改为KERNEL_STACK_SIZE, 被接管 + + # 注释, 栈顶已经由 switch 恢复了 + # mv sp, a0 # 将 a0 中保存的内核栈地址赋值给 sp 这个首次进入是在内核进入首次进入sp 这里会被修改为KERNEL_STACK_SIZE, 被接管 # 恢复 sstatus/sepc ld t0, 32*8(sp) # 从栈空间中读取 sstatus 寄存器的值