1use super::{PhysAddr, PhysPageNum};
2use crate::config::MEMORY_END;
3use crate::sync::UPSafeCell;
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 dealloc(&mut self, ppn: PhysPageNum);
39}
40
41pub struct StackFrameAllocator {
42 current: usize,
43 end: usize,
44 recycled: Vec<usize>,
45}
46
47impl StackFrameAllocator {
48 pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) {
49 self.current = l.0;
50 self.end = r.0;
51 println!("last {} Physical Frames.", self.end - self.current);
52 }
53}
54impl FrameAllocator for StackFrameAllocator {
55 fn new() -> Self {
56 Self {
57 current: 0,
58 end: 0,
59 recycled: Vec::new(),
60 }
61 }
62 fn alloc(&mut self) -> Option<PhysPageNum> {
63 if let Some(ppn) = self.recycled.pop() {
64 Some(ppn.into())
65 } else if self.current == self.end {
66 None
67 } else {
68 self.current += 1;
69 Some((self.current - 1).into())
70 }
71 }
72 fn dealloc(&mut self, ppn: PhysPageNum) {
73 let ppn = ppn.0;
74 if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) {
76 panic!("Frame ppn={:#x} has not been allocated!", ppn);
77 }
78 self.recycled.push(ppn);
80 }
81}
82
83type FrameAllocatorImpl = StackFrameAllocator;
84
85lazy_static! {
86 pub static ref FRAME_ALLOCATOR: UPSafeCell<FrameAllocatorImpl> =
87 unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) };
88}
89
90pub fn init_frame_allocator() {
91 unsafe extern "C" {
92 safe fn ekernel();
93 }
94 FRAME_ALLOCATOR.exclusive_access().init(
95 PhysAddr::from(ekernel as usize).ceil(),
96 PhysAddr::from(MEMORY_END).floor(),
97 );
98}
99
100pub fn frame_alloc() -> Option<FrameTracker> {
101 FRAME_ALLOCATOR
102 .exclusive_access()
103 .alloc()
104 .map(FrameTracker::new)
105}
106
107pub fn frame_dealloc(ppn: PhysPageNum) {
108 FRAME_ALLOCATOR.exclusive_access().dealloc(ppn);
109}
110
111#[allow(unused)]
112pub fn frame_allocator_test() {
113 let mut v: Vec<FrameTracker> = Vec::new();
114 for i in 0..5 {
115 let frame = frame_alloc().unwrap();
116 println!("{:?}", frame);
117 v.push(frame);
118 }
119 v.clear();
120 for i in 0..5 {
121 let frame = frame_alloc().unwrap();
122 println!("{:?}", frame);
123 v.push(frame);
124 }
125 drop(v);
126 println!("frame_allocator_test passed!");
127}