1use super::ProcessControlBlock;
2use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT_BASE, USER_STACK_SIZE};
3use crate::mm::{KERNEL_SPACE, MapPermission, PhysPageNum, VirtAddr};
4use crate::sync::UPIntrFreeCell;
5use alloc::{
6 sync::{Arc, Weak},
7 vec::Vec,
8};
9use lazy_static::*;
10
11pub struct RecycleAllocator {
12 current: usize,
13 recycled: Vec<usize>,
14}
15
16impl RecycleAllocator {
17 pub fn new() -> Self {
18 Self::new_start(0)
19 }
20 pub fn new_start(current: usize) -> Self {
21 RecycleAllocator {
22 current,
23 recycled: Vec::new(),
24 }
25 }
26 pub fn alloc(&mut self) -> usize {
27 if let Some(id) = self.recycled.pop() {
28 id
29 } else {
30 self.current += 1;
31 self.current - 1
32 }
33 }
34 pub fn dealloc(&mut self, id: usize) {
35 assert!(id < self.current);
36 assert!(
37 !self.recycled.iter().any(|i| *i == id),
38 "id {} has been deallocated!",
39 id
40 );
41 self.recycled.push(id);
42 }
43}
44
45lazy_static! {
46 static ref PID_ALLOCATOR: UPIntrFreeCell<RecycleAllocator> =
47 unsafe { UPIntrFreeCell::new(RecycleAllocator::new_start(1)) };
48 static ref KSTACK_ALLOCATOR: UPIntrFreeCell<RecycleAllocator> =
49 unsafe { UPIntrFreeCell::new(RecycleAllocator::new()) };
50}
51
52pub const IDLE_PID: usize = 1;
53
54pub struct PidHandle(pub usize);
55
56pub fn pid_alloc() -> PidHandle {
57 PidHandle(PID_ALLOCATOR.exclusive_access().alloc())
58}
59
60impl Drop for PidHandle {
61 fn drop(&mut self) {
62 PID_ALLOCATOR.exclusive_access().dealloc(self.0);
63 }
64}
65
66pub fn kernel_stack_position(kstack_id: usize) -> (usize, usize) {
68 let top = TRAMPOLINE - kstack_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
69 let bottom = top - KERNEL_STACK_SIZE;
70 (bottom, top)
71}
72
73pub struct KernelStack(pub usize);
74
75pub fn kstack_alloc() -> KernelStack {
76 let kstack_id = KSTACK_ALLOCATOR.exclusive_access().alloc();
77 let (kstack_bottom, kstack_top) = kernel_stack_position(kstack_id);
78 KERNEL_SPACE.exclusive_access().insert_framed_area(
79 kstack_bottom.into(),
80 kstack_top.into(),
81 MapPermission::R | MapPermission::W,
82 );
83 KernelStack(kstack_id)
84}
85
86impl Drop for KernelStack {
87 fn drop(&mut self) {
88 let (kernel_stack_bottom, _) = kernel_stack_position(self.0);
89 let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into();
90 KERNEL_SPACE
91 .exclusive_access()
92 .remove_area_with_start_vpn(kernel_stack_bottom_va.into());
93 KSTACK_ALLOCATOR.exclusive_access().dealloc(self.0);
94 }
95}
96
97impl KernelStack {
98 #[allow(unused)]
99 pub fn push_on_top<T>(&self, value: T) -> *mut T
100 where
101 T: Sized,
102 {
103 let kernel_stack_top = self.get_top();
104 let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
105 unsafe {
106 *ptr_mut = value;
107 }
108 ptr_mut
109 }
110 pub fn get_top(&self) -> usize {
111 let (_, kernel_stack_top) = kernel_stack_position(self.0);
112 kernel_stack_top
113 }
114}
115
116pub struct TaskUserRes {
117 pub tid: usize,
118 pub ustack_base: usize,
119 pub process: Weak<ProcessControlBlock>,
120}
121
122fn trap_cx_bottom_from_tid(tid: usize) -> usize {
123 TRAP_CONTEXT_BASE - tid * PAGE_SIZE
124}
125
126fn ustack_bottom_from_tid(ustack_base: usize, tid: usize) -> usize {
127 ustack_base + tid * (PAGE_SIZE + USER_STACK_SIZE)
128}
129
130impl TaskUserRes {
131 pub fn new(
132 process: Arc<ProcessControlBlock>,
133 ustack_base: usize,
134 alloc_user_res: bool,
135 ) -> Self {
136 let tid = process.inner_exclusive_access().alloc_tid();
137 let task_user_res = Self {
138 tid,
139 ustack_base,
140 process: Arc::downgrade(&process),
141 };
142 if alloc_user_res {
143 task_user_res.alloc_user_res();
144 }
145 task_user_res
146 }
147
148 pub fn alloc_user_res(&self) {
149 let process = self.process.upgrade().unwrap();
150 let mut process_inner = process.inner_exclusive_access();
151 let ustack_bottom = ustack_bottom_from_tid(self.ustack_base, self.tid);
153 let ustack_top = ustack_bottom + USER_STACK_SIZE;
154 process_inner.memory_set.insert_framed_area(
155 ustack_bottom.into(),
156 ustack_top.into(),
157 MapPermission::R | MapPermission::W | MapPermission::U,
158 );
159 let trap_cx_bottom = trap_cx_bottom_from_tid(self.tid);
161 let trap_cx_top = trap_cx_bottom + PAGE_SIZE;
162 process_inner.memory_set.insert_framed_area(
163 trap_cx_bottom.into(),
164 trap_cx_top.into(),
165 MapPermission::R | MapPermission::W,
166 );
167 }
168
169 fn dealloc_user_res(&self) {
170 let process = self.process.upgrade().unwrap();
172 let mut process_inner = process.inner_exclusive_access();
173 let ustack_bottom_va: VirtAddr = ustack_bottom_from_tid(self.ustack_base, self.tid).into();
175 process_inner
176 .memory_set
177 .remove_area_with_start_vpn(ustack_bottom_va.into());
178 let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into();
180 process_inner
181 .memory_set
182 .remove_area_with_start_vpn(trap_cx_bottom_va.into());
183 }
184
185 #[allow(unused)]
186 pub fn alloc_tid(&mut self) {
187 self.tid = self
188 .process
189 .upgrade()
190 .unwrap()
191 .inner_exclusive_access()
192 .alloc_tid();
193 }
194
195 pub fn dealloc_tid(&self) {
196 let process = self.process.upgrade().unwrap();
197 let mut process_inner = process.inner_exclusive_access();
198 process_inner.dealloc_tid(self.tid);
199 }
200
201 pub fn trap_cx_user_va(&self) -> usize {
202 trap_cx_bottom_from_tid(self.tid)
203 }
204
205 pub fn trap_cx_ppn(&self) -> PhysPageNum {
206 let process = self.process.upgrade().unwrap();
207 let process_inner = process.inner_exclusive_access();
208 let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into();
209 process_inner
210 .memory_set
211 .translate(trap_cx_bottom_va.into())
212 .unwrap()
213 .ppn()
214 }
215
216 pub fn ustack_base(&self) -> usize {
217 self.ustack_base
218 }
219 pub fn ustack_top(&self) -> usize {
220 ustack_bottom_from_tid(self.ustack_base, self.tid) + USER_STACK_SIZE
221 }
222}
223
224impl Drop for TaskUserRes {
225 fn drop(&mut self) {
226 self.dealloc_tid();
227 self.dealloc_user_res();
228 }
229}