use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE}; use crate::mm::{MapPermission, VirtAddr, KERNEL_SPACE}; use crate::sync::UPSafeCell; use alloc::vec::Vec; use lazy_static::*; struct PidAllocator { current: usize, recycled: Vec, } impl PidAllocator { pub fn new() -> Self { PidAllocator { current: 0, recycled: Vec::new(), } } pub fn alloc(&mut self) -> PidHandle { if let Some(pid) = self.recycled.pop() { PidHandle(pid) } else { self.current += 1; PidHandle(self.current - 1) } } pub fn dealloc(&mut self, pid: usize) { assert!(pid < self.current); assert!( !self.recycled.iter().any(|ppid| *ppid == pid), "pid {} has been deallocated!", pid ); self.recycled.push(pid); } } lazy_static! { static ref PID_ALLOCATOR: UPSafeCell = unsafe { UPSafeCell::new(PidAllocator::new()) }; } pub struct PidHandle(pub usize); impl Drop for PidHandle { fn drop(&mut self) { //println!("drop pid {}", self.0); PID_ALLOCATOR.exclusive_access().dealloc(self.0); } } pub fn pid_alloc() -> PidHandle { PID_ALLOCATOR.exclusive_access().alloc() } /// Return (bottom, top) of a kernel stack in kernel space. pub fn kernel_stack_position(app_id: usize) -> (usize, usize) { let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE); let bottom = top - KERNEL_STACK_SIZE; (bottom, top) } pub struct KernelStack { pid: usize, } impl KernelStack { pub fn new(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 } } #[allow(unused)] pub fn push_on_top(&self, value: T) -> *mut T where T: Sized, { let kernel_stack_top = self.get_top(); let ptr_mut = (kernel_stack_top - core::mem::size_of::()) 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 Drop for KernelStack { fn drop(&mut self) { let (kernel_stack_bottom, _) = kernel_stack_position(self.pid); let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into(); KERNEL_SPACE .exclusive_access() .remove_area_with_start_vpn(kernel_stack_bottom_va.into()); } }