1use super::{PhysAddr, PhysPageNum};
2use crate::config::MEMORY_END;
3use crate::sync::UPIntrFreeCell;
4use alloc::vec::Vec;
5use core::fmt::{self, Debug, Formatter};
6use lazy_static::*;
7
8pub struct FrameTracker {
9 pub ppn: PhysPageNum,
10}
11
12impl FrameTracker {
13 pub fn new(ppn: PhysPageNum) -> Self {
14 let bytes_array = ppn.get_bytes_array();
16 for i in bytes_array {
17 *i = 0;
18 }
19 Self { ppn }
20 }
21}
22
23impl Debug for FrameTracker {
24 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
25 f.write_fmt(format_args!("FrameTracker:PPN={:#x}", self.ppn.0))
26 }
27}
28
29impl Drop for FrameTracker {
30 fn drop(&mut self) {
31 frame_dealloc(self.ppn);
32 }
33}
34
35trait FrameAllocator {
36 fn new() -> Self;
37 fn alloc(&mut self) -> Option<PhysPageNum>;
38 fn alloc_more(&mut self, pages: usize) -> Option<Vec<PhysPageNum>>;
39 fn dealloc(&mut self, ppn: PhysPageNum);
40}
41
42pub struct StackFrameAllocator {
43 current: usize,
44 end: usize,
45 recycled: Vec<usize>,
46}
47
48impl StackFrameAllocator {
49 pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) {
50 self.current = l.0;
51 self.end = r.0;
52 }
54}
55impl FrameAllocator for StackFrameAllocator {
56 fn new() -> Self {
57 Self {
58 current: 0,
59 end: 0,
60 recycled: Vec::new(),
61 }
62 }
63 fn alloc(&mut self) -> Option<PhysPageNum> {
64 if let Some(ppn) = self.recycled.pop() {
65 Some(ppn.into())
66 } else if self.current == self.end {
67 None
68 } else {
69 self.current += 1;
70 Some((self.current - 1).into())
71 }
72 }
73 fn alloc_more(&mut self, pages: usize) -> Option<Vec<PhysPageNum>> {
74 if self.current + pages >= self.end {
75 None
76 } else {
77 self.current += pages;
78 let arr: Vec<usize> = (1..pages + 1).collect();
79 let v = arr.iter().map(|x| (self.current - x).into()).collect();
80 Some(v)
81 }
82 }
83 fn dealloc(&mut self, ppn: PhysPageNum) {
84 let ppn = ppn.0;
85 if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) {
87 panic!("Frame ppn={:#x} has not been allocated!", ppn);
88 }
89 self.recycled.push(ppn);
91 }
92}
93
94type FrameAllocatorImpl = StackFrameAllocator;
95
96lazy_static! {
97 pub static ref FRAME_ALLOCATOR: UPIntrFreeCell<FrameAllocatorImpl> =
98 unsafe { UPIntrFreeCell::new(FrameAllocatorImpl::new()) };
99}
100
101pub fn init_frame_allocator() {
102 unsafe extern "C" {
103 safe fn ekernel();
104 }
105 FRAME_ALLOCATOR.exclusive_access().init(
106 PhysAddr::from(linker_symbol_addr!(ekernel)).ceil(),
107 PhysAddr::from(MEMORY_END).floor(),
108 );
109}
110
111pub fn frame_alloc() -> Option<FrameTracker> {
112 FRAME_ALLOCATOR
113 .exclusive_access()
114 .alloc()
115 .map(FrameTracker::new)
116}
117
118pub fn frame_alloc_more(num: usize) -> Option<Vec<FrameTracker>> {
119 FRAME_ALLOCATOR
120 .exclusive_access()
121 .alloc_more(num)
122 .map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect())
123}
124
125pub fn frame_dealloc(ppn: PhysPageNum) {
126 FRAME_ALLOCATOR.exclusive_access().dealloc(ppn);
127}
128
129#[allow(unused)]
130pub fn frame_allocator_test() {
131 let mut v: Vec<FrameTracker> = Vec::new();
132 for i in 0..5 {
133 let frame = frame_alloc().unwrap();
134 println!("{:?}", frame);
135 v.push(frame);
136 }
137 v.clear();
138 for i in 0..5 {
139 let frame = frame_alloc().unwrap();
140 println!("{:?}", frame);
141 v.push(frame);
142 }
143 drop(v);
144 println!("frame_allocator_test passed!");
145}
146
147#[allow(unused)]
148pub fn frame_allocator_alloc_more_test() {
149 let mut v: Vec<FrameTracker> = Vec::new();
150 let frames = frame_alloc_more(5).unwrap();
151 for frame in &frames {
152 println!("{:?}", frame);
153 }
154 v.extend(frames);
155 v.clear();
156 let frames = frame_alloc_more(5).unwrap();
157 for frame in &frames {
158 println!("{:?}", frame);
159 }
160 drop(v);
161 println!("frame_allocator_test passed!");
162}