Skip to main content

os/mm/
address.rs

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