全局的任务管理器完成

ch3
zhangxinyu 2 years ago
parent a667808a28
commit feebb265d1

@ -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)

@ -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; // 现在栈顶和栈底都在一个内存位置

@ -1,2 +1,6 @@
pub const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址
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;

@ -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;
@ -52,3 +56,40 @@ 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::<TrapContext>()) as * mut TrapContext
};
// copy 数据到内核栈中
*kernel_app_stack_ptr = user_trap_context;
// 返回内核栈的地址
kernel_app_stack_ptr as usize
}
}

@ -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 {

@ -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],
}
}
}

@ -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;
// 公开到外部的一个全局任务管理器的结构体
pub struct TaskManager {
num_app: usize, // app的数量 这个在os运行之后就不会有变化
inner: UPSafeCell<TaskManagerInner>, // 这个内部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();
}

@ -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 {

Loading…
Cancel
Save