From feebb265d1e96497bd04b9560553c88089e0de86 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 24 May 2023 14:05:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E5=B1=80=E7=9A=84=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch3/os/Makefile | 2 +- ch3/os/src/batch.rs | 2 +- ch3/os/src/config.rs | 6 ++- ch3/os/src/loader.rs | 45 +++++++++++++++++++++- ch3/os/src/main.rs | 3 +- ch3/os/src/task/context.rs | 30 +++++++++++++-- ch3/os/src/task/mod.rs | 77 +++++++++++++++++++++++++++++++++++++- ch3/os/src/trap/context.rs | 5 ++- 8 files changed, 157 insertions(+), 13 deletions(-) diff --git a/ch3/os/Makefile b/ch3/os/Makefile index 0c03143..5ed77c9 100644 --- a/ch3/os/Makefile +++ b/ch3/os/Makefile @@ -44,7 +44,7 @@ run:build_elf $(KERNEL_BIN) $(SYMBOL_MAP) kill -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY) clean: - rm -rf ./target* && rm -rf ./src/link_app.S + #rm -rf ./target* && rm -rf ./src/link_app.S kill: -kill -9 $(QEMU_PID) diff --git a/ch3/os/src/batch.rs b/ch3/os/src/batch.rs index a42c9e9..717883d 100644 --- a/ch3/os/src/batch.rs +++ b/ch3/os/src/batch.rs @@ -93,7 +93,7 @@ pub fn run_next_app() -> ! { // 得到用户栈的栈顶 let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE; // 得到用户trap的上下文以及寄存器状态 - let user_trap_context = TrapContext::app_init_context(app_entry_ptr, user_stack_top); + 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; // 现在栈顶和栈底都在一个内存位置 diff --git a/ch3/os/src/config.rs b/ch3/os/src/config.rs index 23e601c..4fa0a12 100644 --- a/ch3/os/src/config.rs +++ b/ch3/os/src/config.rs @@ -1,2 +1,6 @@ pub const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址 -pub const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 \ No newline at end of file +pub const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 +pub const MAX_APP_NUM: usize = 4; // 支持最大的用户应用数量 + +pub const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb +pub const KERNEL_STACK_SIZE: usize = 4096 * 2; \ No newline at end of file diff --git a/ch3/os/src/loader.rs b/ch3/os/src/loader.rs index 2fa5b83..5ef32bd 100644 --- a/ch3/os/src/loader.rs +++ b/ch3/os/src/loader.rs @@ -1,19 +1,23 @@ 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 USER_STACK: [[u8; USER_STACK_SIZE]; MAX_APP_NUM] = [[0; USER_STACK_SIZE]; MAX_APP_NUM]; // 这一行每个用户应用对应一个应用栈 extern "C" { fn _num_app(); } // 得到用户app的数量 -fn get_num_app() -> usize{ +pub fn get_num_app() -> usize{ unsafe{ (_num_app as usize as *const usize).read_volatile() } } -// 把把 app一次性都加载到内存, 并分配二进制空间 +// 把 app一次性都加载到内存指定位置 pub fn load_app() { // 得到符号位 let num_app_ptr = _num_app as usize as *const usize; @@ -51,4 +55,41 @@ pub fn load_app() { }; dst.copy_from_slice(src); } +} + + +// 初始化用户应用栈, 并返回用户应用栈在内核栈中的trap_context的地址 +// 这个函数根据 app_id得到 USER_STACK的所在的位置, 初始化之后, 再构造 KERNEL_STACK +pub fn init_app_cx(app_id: usize) -> usize { + // 得到 用户栈 + unsafe { + // 构造 trap_context + let user_trap_context = { + // 初始化用户栈顶 + let user_stack_top = { + let _tmp_stack = USER_STACK.as_ptr() as usize + USER_STACK_SIZE * app_id; // 用户栈开始 + (每个用户栈的大小 * 指定用户栈的索引) 得到栈顶位置, + _tmp_stack + USER_STACK_SIZE // 加上栈大小, 得到新的栈顶位置 + }; + + // 用户应用的开始位置 + let user_entry = APP_BASE_ADDRESS + APP_SIZE_LIMIT * app_id; + + TrapContext::from(user_entry, user_stack_top) + }; + + // 把构造的 user_trap_context 放到 KERNEL_STACK指定应用的内核栈中 + let kernel_app_stack_ptr = { + // 栈顶位置 + 栈大小 = 栈底 + let _tme_stack_low = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE * app_id + KERNEL_STACK_SIZE; + + // 给TrapContext 分配栈空间, 得到新的栈顶 + (_tme_stack_low - core::mem::size_of::()) as * mut TrapContext + }; + + // copy 数据到内核栈中 + *kernel_app_stack_ptr = user_trap_context; + + // 返回内核栈的地址 + kernel_app_stack_ptr as usize + } } \ No newline at end of file diff --git a/ch3/os/src/main.rs b/ch3/os/src/main.rs index d7018a4..0fce8c3 100644 --- a/ch3/os/src/main.rs +++ b/ch3/os/src/main.rs @@ -39,8 +39,9 @@ pub fn rust_main(){ println!("sbss: {:#x}, ebss: {:#x}", sbss as usize, ebss as usize); println!("boot_stack_top_bound: {:#x}, boot_stack_lower_bound: {:#x}", boot_stack_top_bound as usize, boot_stack_lower_bound as usize); - loader::load_app(); trap::init(); + loader::load_app(); + task::run_first_task(); // batch::init(); // batch::run_next_app(); loop { diff --git a/ch3/os/src/task/context.rs b/ch3/os/src/task/context.rs index 2c11a00..4cea492 100644 --- a/ch3/os/src/task/context.rs +++ b/ch3/os/src/task/context.rs @@ -1,13 +1,35 @@ // TCB的字段 用来保存cpu 在内核切换人物的时候 寄存器还有栈顶的信息, 这个结构体将来会传到 switch.S 中的汇编中 +#[derive(Copy, Clone)] +#[repr(C)] pub struct TaskContext{ - ra: usize, // 保存了进行切换之后需要 跳转继续执行的地址 - sp: usize, // 当前任务的内核栈的栈顶 + ra: usize, // 保存了进行切换完毕之后需要 跳转继续执行的地址 + sp: usize, // 当前任务的在内核中的内核栈的栈顶, 这个会被switch 保存与恢复 s: [usize; 12] // 当前任务内核 有必要 保存的寄存器 } +impl TaskContext{ + // 初始的内容 + pub fn new() -> Self { + Self { + ra: 0, + sp: 0, + s: [0; 12], + } + } - - + // 从kernel_stack_ptr 创建一个 任务上下文 + // 并把任务上下文的返回地址设置为 trap.S的返回符号的地方 + pub fn from(kernel_stack_ptr: usize) -> Self{ + extern "C" { + fn __restore(); + } + Self { + ra: __restore as usize, + sp: kernel_stack_ptr, + s: [0; 12], + } + } +} diff --git a/ch3/os/src/task/mod.rs b/ch3/os/src/task/mod.rs index d265f93..5c61ea8 100644 --- a/ch3/os/src/task/mod.rs +++ b/ch3/os/src/task/mod.rs @@ -1,3 +1,78 @@ +use lazy_static::lazy_static; +use crate::config::MAX_APP_NUM; +use crate::sync::UPSafeCell; +use crate::task::task::{TaskControlBlock, TaskStatus}; +use crate::loader::{get_num_app, init_app_cx}; +use crate::println; +use crate::task::context::TaskContext; + mod context; mod switch; -mod task; \ No newline at end of file +mod task; + + +// 公开到外部的一个全局任务管理器的结构体 +pub struct TaskManager { + num_app: usize, // app的数量 这个在os运行之后就不会有变化 + inner: UPSafeCell, // 这个内部TaskControlBlock 会随着系统运行发生变化 +} + +impl TaskManager { + fn run_first_task(&self){ + println!("run_first_task"); + } +} + + +// 不公开的结构体, 有一个MAX_APP_NUM大小的数组, 用来保存TCB, 和当前任务的的TCB的下标 +struct TaskManagerInner { + tasks: [TaskControlBlock; MAX_APP_NUM], + current_task: usize, +} + +lazy_static!{ + pub static ref TASK_MANAGER: TaskManager = { + // 得到app的总数 + let num_app = get_num_app(); + + // 初始化内核中的任务列表 + let mut tasks = [ + TaskControlBlock { + task_cx: TaskContext::new(), + // UnInit 这个tcb 还没用户应用填充加载 + task_status: TaskStatus::UnInit + }; + MAX_APP_NUM + ]; + + // 初始化用户的应用对应的 TCB + for i in 0..num_app { + // 初始化用户应用的内核栈 + let kernel_app_stack_ptr = init_app_cx(i); + + // 从 初始内核栈的栈顶(保存 trap_context的位置) 创建 任务context + let task_context = TaskContext::from(kernel_app_stack_ptr); + + // 把内核栈的信息保存到 TCB中 + tasks[i].task_cx = task_context; + + // 初始为 准备好的状态 + tasks[i].task_status = TaskStatus::Ready + }; + + TaskManager { + num_app, + inner: unsafe { + UPSafeCell::new(TaskManagerInner { + tasks, + current_task: 0, + }) + } + } + }; +} + + +pub fn run_first_task() { + TASK_MANAGER.run_first_task(); +} diff --git a/ch3/os/src/trap/context.rs b/ch3/os/src/trap/context.rs index 7ed956d..3cd7482 100644 --- a/ch3/os/src/trap/context.rs +++ b/ch3/os/src/trap/context.rs @@ -25,8 +25,9 @@ impl TrapContext { pub fn set_sp(&mut self, sp: usize) { self.x[2] = sp; } - /// init app context - pub fn app_init_context(entry: usize, sp: usize) -> Self { + + // 根据entry和sp构造一个 trap_context + pub fn from(entry: usize, sp: usize) -> Self { let mut sstatus = sstatus::read(); // 读取CSR sstatus sstatus.set_spp(SPP::User); // 设置特权级为用户模式 let mut cx = Self {