1use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE};
2use crate::mm::{KERNEL_SPACE, MapPermission, VirtAddr};
3use crate::sync::UPSafeCell;
4use alloc::vec::Vec;
5use lazy_static::*;
6
7struct PidAllocator {
8 current: usize,
9 recycled: Vec<usize>,
10}
11
12impl PidAllocator {
13 pub fn new() -> Self {
14 PidAllocator {
15 current: 1,
16 recycled: Vec::new(),
17 }
18 }
19 pub fn alloc(&mut self) -> PidHandle {
20 if let Some(pid) = self.recycled.pop() {
21 PidHandle(pid)
22 } else {
23 self.current += 1;
24 PidHandle(self.current - 1)
25 }
26 }
27 pub fn dealloc(&mut self, pid: usize) {
28 assert!(pid < self.current);
29 assert!(
30 !self.recycled.iter().any(|ppid| *ppid == pid),
31 "pid {} has been deallocated!",
32 pid
33 );
34 self.recycled.push(pid);
35 }
36}
37
38lazy_static! {
39 static ref PID_ALLOCATOR: UPSafeCell<PidAllocator> =
40 unsafe { UPSafeCell::new(PidAllocator::new()) };
41}
42
43pub struct PidHandle(pub usize);
44
45impl Drop for PidHandle {
46 fn drop(&mut self) {
47 PID_ALLOCATOR.exclusive_access().dealloc(self.0);
49 }
50}
51
52pub fn pid_alloc() -> PidHandle {
53 PID_ALLOCATOR.exclusive_access().alloc()
54}
55
56pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
58 let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
59 let bottom = top - KERNEL_STACK_SIZE;
60 (bottom, top)
61}
62
63pub struct KernelStack {
64 pid: usize,
65}
66
67impl KernelStack {
68 pub fn new(pid_handle: &PidHandle) -> Self {
69 let pid = pid_handle.0;
70 let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(pid);
71 KERNEL_SPACE.exclusive_access().insert_framed_area(
72 kernel_stack_bottom.into(),
73 kernel_stack_top.into(),
74 MapPermission::R | MapPermission::W,
75 );
76 KernelStack { pid: pid_handle.0 }
77 }
78 #[allow(unused)]
79 pub fn push_on_top<T>(&self, value: T) -> *mut T
80 where
81 T: Sized,
82 {
83 let kernel_stack_top = self.get_top();
84 let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
85 unsafe {
86 *ptr_mut = value;
87 }
88 ptr_mut
89 }
90 pub fn get_top(&self) -> usize {
91 let (_, kernel_stack_top) = kernel_stack_position(self.pid);
92 kernel_stack_top
93 }
94}
95
96impl Drop for KernelStack {
97 fn drop(&mut self) {
98 let (kernel_stack_bottom, _) = kernel_stack_position(self.pid);
99 let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into();
100 KERNEL_SPACE
101 .exclusive_access()
102 .remove_area_with_start_vpn(kernel_stack_bottom_va.into());
103 }
104}