os/mm/
frame_allocator.rs

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        // 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 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        // validity check
75        if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) {
76            panic!("Frame ppn={:#x} has not been allocated!", ppn);
77        }
78        // recycle
79        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}