1use super::{FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum, frame_alloc};
4use alloc::string::String;
5use alloc::vec;
6use alloc::vec::Vec;
7use bitflags::*;
8
9bitflags! {
10 pub struct PTEFlags: u8 {
11 const V = 1 << 0;
12 const R = 1 << 1;
13 const W = 1 << 2;
14 const X = 1 << 3;
15 const U = 1 << 4;
16 const G = 1 << 5;
17 const A = 1 << 6;
18 const D = 1 << 7;
19 }
20}
21
22#[derive(Copy, Clone)]
23#[repr(C)]
24pub struct PageTableEntry {
26 pub bits: usize,
28}
29
30impl PageTableEntry {
31 pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self {
33 PageTableEntry {
34 bits: ppn.0 << 10 | flags.bits as usize,
35 }
36 }
37 pub fn empty() -> Self {
39 PageTableEntry { bits: 0 }
40 }
41 pub fn ppn(&self) -> PhysPageNum {
43 (self.bits >> 10 & ((1usize << 44) - 1)).into()
44 }
45 pub fn flags(&self) -> PTEFlags {
47 PTEFlags::from_bits(self.bits as u8).unwrap()
48 }
49 pub fn is_valid(&self) -> bool {
51 (self.flags() & PTEFlags::V) != PTEFlags::empty()
52 }
53 pub fn readable(&self) -> bool {
55 (self.flags() & PTEFlags::R) != PTEFlags::empty()
56 }
57 pub fn writable(&self) -> bool {
59 (self.flags() & PTEFlags::W) != PTEFlags::empty()
60 }
61 pub fn executable(&self) -> bool {
63 (self.flags() & PTEFlags::X) != PTEFlags::empty()
64 }
65}
66
67pub struct PageTable {
68 root_ppn: PhysPageNum,
69 frames: Vec<FrameTracker>,
70}
71
72impl PageTable {
74 pub fn new() -> Self {
75 let frame = frame_alloc().unwrap();
76 PageTable {
77 root_ppn: frame.ppn,
78 frames: vec![frame],
79 }
80 }
81 pub fn from_token(satp: usize) -> Self {
83 Self {
84 root_ppn: PhysPageNum::from(satp & ((1usize << 44) - 1)),
85 frames: Vec::new(),
86 }
87 }
88 fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
89 let idxs = vpn.indexes();
90 let mut ppn = self.root_ppn;
91 let mut result: Option<&mut PageTableEntry> = None;
92 for (i, idx) in idxs.iter().enumerate() {
93 let pte = &mut ppn.get_pte_array()[*idx];
94 if i == 2 {
95 result = Some(pte);
96 break;
97 }
98 if !pte.is_valid() {
99 let frame = frame_alloc().unwrap();
100 *pte = PageTableEntry::new(frame.ppn, PTEFlags::V);
101 self.frames.push(frame);
102 }
103 ppn = pte.ppn();
104 }
105 result
106 }
107 fn find_pte(&self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
108 let idxs = vpn.indexes();
109 let mut ppn = self.root_ppn;
110 let mut result: Option<&mut PageTableEntry> = None;
111 for (i, idx) in idxs.iter().enumerate() {
112 let pte = &mut ppn.get_pte_array()[*idx];
113 if i == 2 {
114 result = Some(pte);
115 break;
116 }
117 if !pte.is_valid() {
118 return None;
119 }
120 ppn = pte.ppn();
121 }
122 result
123 }
124 #[allow(unused)]
125 pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
126 let pte = self.find_pte_create(vpn).unwrap();
127 assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
128 *pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
129 }
130 #[allow(unused)]
131 pub fn unmap(&mut self, vpn: VirtPageNum) {
132 let pte = self.find_pte(vpn).unwrap();
133 assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
134 *pte = PageTableEntry::empty();
135 }
136 pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
137 self.find_pte(vpn).map(|pte| *pte)
138 }
139 pub fn translate_va(&self, va: VirtAddr) -> Option<PhysAddr> {
140 self.find_pte(va.clone().floor()).map(|pte| {
141 let aligned_pa: PhysAddr = pte.ppn().into();
143 let offset = va.page_offset();
145 let aligned_pa_usize: usize = aligned_pa.into();
146 (aligned_pa_usize + offset).into()
147 })
148 }
149 pub fn token(&self) -> usize {
150 8usize << 60 | self.root_ppn.0
151 }
152}
153pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> {
155 let page_table = PageTable::from_token(token);
156 let mut start = ptr as usize;
157 let end = start + len;
158 let mut v = Vec::new();
159 while start < end {
160 let start_va = VirtAddr::from(start);
161 let mut vpn = start_va.floor();
162 let ppn = page_table.translate(vpn).unwrap().ppn();
163 vpn.step();
164 let mut end_va: VirtAddr = vpn.into();
165 end_va = end_va.min(VirtAddr::from(end));
166 if end_va.page_offset() == 0 {
167 v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..]);
168 } else {
169 v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..end_va.page_offset()]);
170 }
171 start = end_va.into();
172 }
173 v
174}
175pub fn translated_str(token: usize, ptr: *const u8) -> String {
177 let page_table = PageTable::from_token(token);
178 let mut string = String::new();
179 let mut va = ptr as usize;
180 loop {
181 let ch: u8 = *(page_table
182 .translate_va(VirtAddr::from(va))
183 .unwrap()
184 .get_mut());
185 if ch == 0 {
186 break;
187 } else {
188 string.push(ch as char);
189 va += 1;
190 }
191 }
192 string
193}
194pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
196 let page_table = PageTable::from_token(token);
198 let va = ptr as usize;
199 page_table
201 .translate_va(VirtAddr::from(va))
202 .unwrap()
203 .get_mut()
204}