增加了内核栈和pid结构体, 用于单独管理每个应用的内核栈, 和对应的PID

ch5
zhangxinyu 2 years ago
parent a8bf43b113
commit b5bd4bfee7

@ -11,15 +11,3 @@ pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; // __alltraps对齐
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; // 用户 trap context开始的位置 在 每个用户程序 它本身地址空间 的次高页
pub use crate::board::*;
/// 得到 "用户程序的内核栈" 的在 内核本身地址空间 中的虚拟位置(当然由于恒等映射其实也是实际的物理地址)
/// 这个在 跳板的下面的某个位置
/// 每个用户除了分配 KERNEL_STACK_SIZE 大小外, 还额外 增加 一个PAGE_SIZE 放在比栈底要高的地址 用来隔离每个用户内核栈
pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
// 栈底只需要 KERNEL_STACK_SIZE 即可,
let bottom = top - KERNEL_STACK_SIZE;
(bottom, top)
}

@ -51,7 +51,7 @@ pub fn rust_main(){
// 初始化动态内存分配器, 使我们能在内核中使用动态大小数据类型
mm::init();
use loader;
loader::list_apps();
println!("{:?}", loader::get_app_data_by_name("00power_3"));
// trap::init();
// trap::enable_timer_interrupt(); // 允许定时器中断

@ -13,6 +13,7 @@ use crate::trap::TrapContext;
mod context;
mod switch;
mod task;
mod pid;
// 公开到外部的一个全局任务管理器的结构体

@ -0,0 +1,122 @@
use alloc::vec::Vec;
use lazy_static::lazy_static;
use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE};
use crate::mm::memory_set::{KERNEL_SPACE, MapPermission};
use crate::sync::UPSafeCell;
// pid分配器
pub struct PidAllocator {
current: usize, // 当前分配到多少号了
recycled: Vec<usize>, // 被回收的pid, 后续可以再次利用
}
// 全局的pid分配器
lazy_static! {
pub static ref PID_ALLOCATOR: UPSafeCell<PidAllocator> =
unsafe { UPSafeCell::new(PidAllocator::new()) };
}
impl PidAllocator {
pub fn new() -> Self {
Self {
current: 0,
recycled: Vec::new(),
}
}
}
impl PidAllocator {
// 分配一个pid
pub fn alloc(&mut self) -> PidHandle {
if let Some(pid) = self.recycled.pop() {
PidHandle(pid)
} else {
let current = self.current;
self.current += 1;
PidHandle(current)
}
}
// 取消分配一个pid
pub fn dealloc(&mut self, pid: usize) {
assert!(pid < self.current);
// 防止二次释放
assert!(
!self.recycled.iter().any(|tmp_pid| *tmp_pid == pid),
"pid {} has been deallocated!",
pid
);
self.recycled.push(pid);
}
}
// 用来表示进程的唯一标识符, RAII思想来进行释放管理
pub struct PidHandle(pub usize);
// pid_handle 被drop时, 同时把pid 还给全局管理器
impl Drop for PidHandle {
fn drop(&mut self) {
PID_ALLOCATOR.exclusive_access().dealloc(self.0);
}
}
/// 得到 "用户程序的内核栈" 的在 内核本身地址空间 中的虚拟位置(当然由于恒等映射其实也是实际的物理地址)
/// 这个在 跳板的下面的某个位置
/// 每个用户除了分配 KERNEL_STACK_SIZE 大小外, 还额外 增加 一个PAGE_SIZE 放在比栈底要高的地址 用来隔离每个用户内核栈
/// 根据 pid 在相应的位置, 得到app 内核栈的它处于的位置, 位置, 注意代码实现, 这个是有保护页面的(1 pagesize),
/// 在逻辑地址空间存在保护页面(保护页面不会被映射), 但是在物理地址空间,这个保护页会被随时被物理页帧管理器分配走
/// 返回的 top是内存的高地址, bottom是内存的低地址
pub fn kernel_stack_position(pid: usize) -> (usize, usize) {
let top = TRAMPOLINE - pid * (KERNEL_STACK_SIZE + PAGE_SIZE);
// 栈底只需要 KERNEL_STACK_SIZE 即可,
let bottom = top - KERNEL_STACK_SIZE;
(bottom, top)
}
// 新的结构体, 内核栈, 之前我们是根据 app_id 找到的, 现在我们需要改成 统一分配的pid, 根据pid摆放应用内核栈的位置
pub struct KernelStack {
pid: usize,
}
impl KernelStack {
// push 一个 泛型, 到 内核栈中, 直接减去T的大小, 再写入即可
pub fn push_on_top<T: Sized>(&self, value: T) -> *mut T {
let kernel_stack_top = self.get_top();
let kernel_stack_top = self.get_top();
let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
unsafe {
*ptr_mut = value;
}
ptr_mut
}
// 得到当前内核栈的 栈底(高地址)
pub fn get_top(&self) -> usize {
let (_, kernel_stack_top) = kernel_stack_position(self.pid);
kernel_stack_top
}
}
impl KernelStack {
// 根据 pid handle 在内核空间(最高页的下面) 某个位置, 创建一个 逻辑段 作为应用的内核栈
pub fn from(pid_handle: &PidHandle) -> Self {
let pid = pid_handle.0;
let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(pid);
KERNEL_SPACE
.exclusive_access()
.insert_framed_area(
kernel_stack_bottom.into(),
kernel_stack_top.into(),
MapPermission::R | MapPermission::W,
);
KernelStack { pid: pid_handle.0 }
}
}

@ -1,8 +1,9 @@
use crate::config::{kernel_stack_position, TRAP_CONTEXT};
use crate::config::{TRAP_CONTEXT};
use crate::mm::address::{PhysPageNum, VirtAddr};
use crate::mm::memory_set::{KERNEL_SPACE, MapPermission, MemorySet};
use crate::println;
use crate::task::context::{TaskContext};
use crate::task::pid::kernel_stack_position;
use crate::trap::{trap_handler, TrapContext};
// TCB的字段, 用来保存任务的状态

Loading…
Cancel
Save