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