Skip to main content

os/mm/
address.rs

1//! Implementation of physical and virtual address and page number.
2
3use super::PageTableEntry;
4use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
5use core::fmt::{self, Debug, Formatter};
6
7/// physical address
8const PA_WIDTH_SV39: usize = 56;
9const VA_WIDTH_SV39: usize = 39;
10const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS;
11const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS;
12
13/// Definitions
14#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
15pub struct PhysAddr(pub usize);
16
17/// virtual address
18#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
19pub struct VirtAddr(pub usize);
20
21/// physical page number
22#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
23pub struct PhysPageNum(pub usize);
24
25/// virtual page number
26#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
27pub struct VirtPageNum(pub usize);
28
29/// Debugging
30
31impl Debug for VirtAddr {
32    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
33        f.write_fmt(format_args!("VA:{:#x}", self.0))
34    }
35}
36impl Debug for VirtPageNum {
37    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
38        f.write_fmt(format_args!("VPN:{:#x}", self.0))
39    }
40}
41impl Debug for PhysAddr {
42    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
43        f.write_fmt(format_args!("PA:{:#x}", self.0))
44    }
45}
46impl Debug for PhysPageNum {
47    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
48        f.write_fmt(format_args!("PPN:{:#x}", self.0))
49    }
50}
51
52/// T: {PhysAddr, VirtAddr, PhysPageNum, VirtPageNum}
53/// T -> usize: T.0
54/// usize -> T: usize.into()
55
56impl From<usize> for PhysAddr {
57    fn from(v: usize) -> Self {
58        Self(v & ((1 << PA_WIDTH_SV39) - 1))
59    }
60}
61impl From<usize> for PhysPageNum {
62    fn from(v: usize) -> Self {
63        Self(v & ((1 << PPN_WIDTH_SV39) - 1))
64    }
65}
66impl From<usize> for VirtAddr {
67    fn from(v: usize) -> Self {
68        Self(v & ((1 << VA_WIDTH_SV39) - 1))
69    }
70}
71impl From<usize> for VirtPageNum {
72    fn from(v: usize) -> Self {
73        Self(v & ((1 << VPN_WIDTH_SV39) - 1))
74    }
75}
76impl From<PhysAddr> for usize {
77    fn from(v: PhysAddr) -> Self {
78        v.0
79    }
80}
81impl From<PhysPageNum> for usize {
82    fn from(v: PhysPageNum) -> Self {
83        v.0
84    }
85}
86impl From<VirtAddr> for usize {
87    fn from(v: VirtAddr) -> Self {
88        if v.0 >= (1 << (VA_WIDTH_SV39 - 1)) {
89            v.0 | (!((1 << VA_WIDTH_SV39) - 1))
90        } else {
91            v.0
92        }
93    }
94}
95impl From<VirtPageNum> for usize {
96    fn from(v: VirtPageNum) -> Self {
97        v.0
98    }
99}
100
101impl VirtAddr {
102    pub fn floor(&self) -> VirtPageNum {
103        VirtPageNum(self.0 / PAGE_SIZE)
104    }
105    pub fn ceil(&self) -> VirtPageNum {
106        if self.0 == 0 {
107            VirtPageNum(0)
108        } else {
109            VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
110        }
111    }
112    pub fn page_offset(&self) -> usize {
113        self.0 & (PAGE_SIZE - 1)
114    }
115    pub fn aligned(&self) -> bool {
116        self.page_offset() == 0
117    }
118}
119impl From<VirtAddr> for VirtPageNum {
120    fn from(v: VirtAddr) -> Self {
121        assert_eq!(v.page_offset(), 0);
122        v.floor()
123    }
124}
125impl From<VirtPageNum> for VirtAddr {
126    fn from(v: VirtPageNum) -> Self {
127        Self(v.0 << PAGE_SIZE_BITS)
128    }
129}
130impl PhysAddr {
131    pub fn floor(&self) -> PhysPageNum {
132        PhysPageNum(self.0 / PAGE_SIZE)
133    }
134    pub fn ceil(&self) -> PhysPageNum {
135        if self.0 == 0 {
136            PhysPageNum(0)
137        } else {
138            PhysPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
139        }
140    }
141    pub fn page_offset(&self) -> usize {
142        self.0 & (PAGE_SIZE - 1)
143    }
144    pub fn aligned(&self) -> bool {
145        self.page_offset() == 0
146    }
147}
148impl From<PhysAddr> for PhysPageNum {
149    fn from(v: PhysAddr) -> Self {
150        assert_eq!(v.page_offset(), 0);
151        v.floor()
152    }
153}
154impl From<PhysPageNum> for PhysAddr {
155    fn from(v: PhysPageNum) -> Self {
156        Self(v.0 << PAGE_SIZE_BITS)
157    }
158}
159
160impl VirtPageNum {
161    pub fn indexes(&self) -> [usize; 3] {
162        let mut vpn = self.0;
163        let mut idx = [0usize; 3];
164        for i in (0..3).rev() {
165            idx[i] = vpn & 511;
166            vpn >>= 9;
167        }
168        idx
169    }
170}
171
172impl PhysPageNum {
173    pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
174        let pa: PhysAddr = (*self).into();
175        unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512) }
176    }
177    pub fn get_bytes_array(&self) -> &'static mut [u8] {
178        let pa: PhysAddr = (*self).into();
179        unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096) }
180    }
181    pub fn get_mut<T>(&self) -> &'static mut T {
182        let pa: PhysAddr = (*self).into();
183        unsafe { (pa.0 as *mut T).as_mut().unwrap() }
184    }
185}
186
187pub trait StepByOne {
188    fn step(&mut self);
189}
190impl StepByOne for VirtPageNum {
191    fn step(&mut self) {
192        self.0 += 1;
193    }
194}
195
196#[derive(Copy, Clone)]
197/// a simple range structure for type T
198pub struct SimpleRange<T>
199where
200    T: StepByOne + Copy + PartialEq + PartialOrd + Debug,
201{
202    l: T,
203    r: T,
204}
205impl<T> SimpleRange<T>
206where
207    T: StepByOne + Copy + PartialEq + PartialOrd + Debug,
208{
209    pub fn new(start: T, end: T) -> Self {
210        assert!(start <= end, "start {:?} > end {:?}!", start, end);
211        Self { l: start, r: end }
212    }
213    pub fn get_start(&self) -> T {
214        self.l
215    }
216    pub fn get_end(&self) -> T {
217        self.r
218    }
219}
220impl<T> IntoIterator for SimpleRange<T>
221where
222    T: StepByOne + Copy + PartialEq + PartialOrd + Debug,
223{
224    type Item = T;
225    type IntoIter = SimpleRangeIterator<T>;
226    fn into_iter(self) -> Self::IntoIter {
227        SimpleRangeIterator::new(self.l, self.r)
228    }
229}
230/// iterator for the simple range structure
231pub struct SimpleRangeIterator<T>
232where
233    T: StepByOne + Copy + PartialEq + PartialOrd + Debug,
234{
235    current: T,
236    end: T,
237}
238impl<T> SimpleRangeIterator<T>
239where
240    T: StepByOne + Copy + PartialEq + PartialOrd + Debug,
241{
242    pub fn new(l: T, r: T) -> Self {
243        Self { current: l, end: r }
244    }
245}
246impl<T> Iterator for SimpleRangeIterator<T>
247where
248    T: StepByOne + Copy + PartialEq + PartialOrd + Debug,
249{
250    type Item = T;
251    fn next(&mut self) -> Option<Self::Item> {
252        if self.current == self.end {
253            None
254        } else {
255            let t = self.current;
256            self.current.step();
257            Some(t)
258        }
259    }
260}
261
262/// a simple range structure for virtual page number
263pub type VPNRange = SimpleRange<VirtPageNum>;