os/mm/
frame_allocator.rs

1//! Implementation of [`FrameAllocator`] which
2//! controls all the frames in the operating system.
3use 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
10/// manage a frame which has the same lifecycle as the tracker
11pub struct FrameTracker {
12    ///
13    pub ppn: PhysPageNum,
14}
15
16impl FrameTracker {
17    ///Create an empty `FrameTracker`
18    pub fn new(ppn: PhysPageNum) -> Self {
19        // page cleaning
20        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}
45/// an implementation for frame allocator
46pub 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        // validity check
80        if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) {
81            panic!("Frame ppn={:#x} has not been allocated!", ppn);
82        }
83        // recycle
84        self.recycled.push(ppn);
85    }
86}
87
88type FrameAllocatorImpl = StackFrameAllocator;
89
90lazy_static! {
91    /// frame allocator instance through lazy_static!
92    pub static ref FRAME_ALLOCATOR: UPSafeCell<FrameAllocatorImpl> =
93        unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) };
94}
95/// initiate the frame allocator using `ekernel` and `MEMORY_END`
96pub 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}
105/// allocate a frame
106pub fn frame_alloc() -> Option<FrameTracker> {
107    FRAME_ALLOCATOR
108        .exclusive_access()
109        .alloc()
110        .map(FrameTracker::new)
111}
112/// deallocate a frame
113fn frame_dealloc(ppn: PhysPageNum) {
114    FRAME_ALLOCATOR.exclusive_access().dealloc(ppn);
115}
116
117#[allow(unused)]
118/// a simple test for frame allocator
119pub 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}