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