Skip to main content

os/mm/
frame_allocator.rs

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        // page cleaning
15        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        // println!("last {} Physical Frames.", self.end - self.current);
53    }
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        // validity check
86        if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) {
87            panic!("Frame ppn={:#x} has not been allocated!", ppn);
88        }
89        // recycle
90        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}