os/mm/
page_table.rs

1use super::{FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum, frame_alloc};
2use alloc::string::String;
3use alloc::vec;
4use alloc::vec::Vec;
5use bitflags::*;
6
7bitflags! {
8    pub struct PTEFlags: u8 {
9        const V = 1 << 0;
10        const R = 1 << 1;
11        const W = 1 << 2;
12        const X = 1 << 3;
13        const U = 1 << 4;
14        const G = 1 << 5;
15        const A = 1 << 6;
16        const D = 1 << 7;
17    }
18}
19
20#[derive(Copy, Clone)]
21#[repr(C)]
22pub struct PageTableEntry {
23    pub bits: usize,
24}
25
26impl PageTableEntry {
27    pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self {
28        PageTableEntry {
29            bits: ppn.0 << 10 | flags.bits as usize,
30        }
31    }
32    pub fn empty() -> Self {
33        PageTableEntry { bits: 0 }
34    }
35    pub fn ppn(&self) -> PhysPageNum {
36        (self.bits >> 10 & ((1usize << 44) - 1)).into()
37    }
38    pub fn flags(&self) -> PTEFlags {
39        PTEFlags::from_bits(self.bits as u8).unwrap()
40    }
41    pub fn is_valid(&self) -> bool {
42        (self.flags() & PTEFlags::V) != PTEFlags::empty()
43    }
44    pub fn readable(&self) -> bool {
45        (self.flags() & PTEFlags::R) != PTEFlags::empty()
46    }
47    pub fn writable(&self) -> bool {
48        (self.flags() & PTEFlags::W) != PTEFlags::empty()
49    }
50    pub fn executable(&self) -> bool {
51        (self.flags() & PTEFlags::X) != PTEFlags::empty()
52    }
53}
54
55pub struct PageTable {
56    root_ppn: PhysPageNum,
57    frames: Vec<FrameTracker>,
58}
59
60/// Assume that it won't oom when creating/mapping.
61impl PageTable {
62    pub fn new() -> Self {
63        let frame = frame_alloc().unwrap();
64        PageTable {
65            root_ppn: frame.ppn,
66            frames: vec![frame],
67        }
68    }
69    /// Temporarily used to get arguments from user space.
70    pub fn from_token(satp: usize) -> Self {
71        Self {
72            root_ppn: PhysPageNum::from(satp & ((1usize << 44) - 1)),
73            frames: Vec::new(),
74        }
75    }
76    fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
77        let idxs = vpn.indexes();
78        let mut ppn = self.root_ppn;
79        let mut result: Option<&mut PageTableEntry> = None;
80        for (i, idx) in idxs.iter().enumerate() {
81            let pte = &mut ppn.get_pte_array()[*idx];
82            if i == 2 {
83                result = Some(pte);
84                break;
85            }
86            if !pte.is_valid() {
87                let frame = frame_alloc().unwrap();
88                *pte = PageTableEntry::new(frame.ppn, PTEFlags::V);
89                self.frames.push(frame);
90            }
91            ppn = pte.ppn();
92        }
93        result
94    }
95    fn find_pte(&self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
96        let idxs = vpn.indexes();
97        let mut ppn = self.root_ppn;
98        let mut result: Option<&mut PageTableEntry> = None;
99        for (i, idx) in idxs.iter().enumerate() {
100            let pte = &mut ppn.get_pte_array()[*idx];
101            if i == 2 {
102                result = Some(pte);
103                break;
104            }
105            if !pte.is_valid() {
106                return None;
107            }
108            ppn = pte.ppn();
109        }
110        result
111    }
112    #[allow(unused)]
113    pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
114        let pte = self.find_pte_create(vpn).unwrap();
115        assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
116        *pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
117    }
118    #[allow(unused)]
119    pub fn unmap(&mut self, vpn: VirtPageNum) {
120        let pte = self.find_pte(vpn).unwrap();
121        assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
122        *pte = PageTableEntry::empty();
123    }
124    pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
125        self.find_pte(vpn).map(|pte| *pte)
126    }
127    pub fn translate_va(&self, va: VirtAddr) -> Option<PhysAddr> {
128        self.find_pte(va.clone().floor()).map(|pte| {
129            let aligned_pa: PhysAddr = pte.ppn().into();
130            let offset = va.page_offset();
131            let aligned_pa_usize: usize = aligned_pa.into();
132            (aligned_pa_usize + offset).into()
133        })
134    }
135    pub fn token(&self) -> usize {
136        8usize << 60 | self.root_ppn.0
137    }
138}
139
140pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> {
141    let page_table = PageTable::from_token(token);
142    let mut start = ptr as usize;
143    let end = start + len;
144    let mut v = Vec::new();
145    while start < end {
146        let start_va = VirtAddr::from(start);
147        let mut vpn = start_va.floor();
148        let ppn = page_table.translate(vpn).unwrap().ppn();
149        vpn.step();
150        let mut end_va: VirtAddr = vpn.into();
151        end_va = end_va.min(VirtAddr::from(end));
152        if end_va.page_offset() == 0 {
153            v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..]);
154        } else {
155            v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..end_va.page_offset()]);
156        }
157        start = end_va.into();
158    }
159    v
160}
161
162/// Load a string from other address spaces into kernel space without an end `\0`.
163pub fn translated_str(token: usize, ptr: *const u8) -> String {
164    let page_table = PageTable::from_token(token);
165    let mut string = String::new();
166    let mut va = ptr as usize;
167    loop {
168        let ch: u8 = *(page_table
169            .translate_va(VirtAddr::from(va))
170            .unwrap()
171            .get_mut());
172        if ch == 0 {
173            break;
174        }
175        string.push(ch as char);
176        va += 1;
177    }
178    string
179}
180
181pub fn translated_ref<T>(token: usize, ptr: *const T) -> &'static T {
182    let page_table = PageTable::from_token(token);
183    page_table
184        .translate_va(VirtAddr::from(ptr as usize))
185        .unwrap()
186        .get_ref()
187}
188
189pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
190    let page_table = PageTable::from_token(token);
191    let va = ptr as usize;
192    page_table
193        .translate_va(VirtAddr::from(va))
194        .unwrap()
195        .get_mut()
196}
197
198pub struct UserBuffer {
199    pub buffers: Vec<&'static mut [u8]>,
200}
201
202impl UserBuffer {
203    pub fn new(buffers: Vec<&'static mut [u8]>) -> Self {
204        Self { buffers }
205    }
206    pub fn len(&self) -> usize {
207        let mut total: usize = 0;
208        for b in self.buffers.iter() {
209            total += b.len();
210        }
211        total
212    }
213}
214
215impl IntoIterator for UserBuffer {
216    type Item = *mut u8;
217    type IntoIter = UserBufferIterator;
218    fn into_iter(self) -> Self::IntoIter {
219        UserBufferIterator {
220            buffers: self.buffers,
221            current_buffer: 0,
222            current_idx: 0,
223        }
224    }
225}
226
227pub struct UserBufferIterator {
228    buffers: Vec<&'static mut [u8]>,
229    current_buffer: usize,
230    current_idx: usize,
231}
232
233impl Iterator for UserBufferIterator {
234    type Item = *mut u8;
235    fn next(&mut self) -> Option<Self::Item> {
236        if self.current_buffer >= self.buffers.len() {
237            None
238        } else {
239            let r = &mut self.buffers[self.current_buffer][self.current_idx] as *mut _;
240            if self.current_idx + 1 == self.buffers[self.current_buffer].len() {
241                self.current_idx = 0;
242                self.current_buffer += 1;
243            } else {
244                self.current_idx += 1;
245            }
246            Some(r)
247        }
248    }
249}