1use super::PageTableEntry;
3use crate::mm::address::{ConvertablePaddr, Paddr, PageNum, Ppn, UsizeConvert, Vaddr, Vpn};
4use crate::mm::frame_allocator::{FrameTracker, alloc_frame};
5use crate::mm::page_table::{
6 PageSize, PageTableEntry as PageTableEntryTrait, PageTableInner as PageTableInnerTrait,
7 PagingError, PagingResult, UniversalPTEFlag,
8};
9use alloc::vec::Vec;
10
11#[derive(Debug)]
12pub struct PageTableInner {
13 root: Ppn, frames: Vec<FrameTracker>,
16 is_user: bool, }
18
19impl PageTableInnerTrait<PageTableEntry> for PageTableInner {
21 const LEVELS: usize = 3; const MAX_VA_BITS: usize = 39; const MAX_PA_BITS: usize = 56; fn tlb_flush(vpn: Vpn) {
27 let vaddr = vpn.start_addr();
28 unsafe {
39 core::arch::asm!(
41 "sfence.vma {0}, zero",
42 in(reg) vaddr.as_usize()
43 )
44 }
45 }
46
47 fn tlb_flush_all() {
49 unsafe { core::arch::asm!("sfence.vma") }
51 }
52
53 fn is_user_table(&self) -> bool {
55 self.is_user
56 }
57
58 fn activate(ppn: Ppn) {
60 let satp_value = ppn_to_satp(ppn);
61 unsafe {
63 core::arch::asm!(
65 "csrw satp, {0}",
66 "sfence.vma",
67 in(reg) satp_value
68 )
69 }
70 }
71
72 fn activating_table_ppn() -> Ppn {
74 let satp_value: usize;
75 unsafe {
76 core::arch::asm!("csrr {0}, satp", out(reg) satp_value);
78 }
79 let ppn = satp_value & ((1usize << 44) - 1);
81 Ppn::from_usize(ppn)
82 }
83
84 fn new() -> Self {
86 let frame = alloc_frame().unwrap(); Self {
88 root: frame.ppn(),
89 frames: alloc::vec![frame], is_user: true,
91 }
92 }
93
94 fn from_ppn(ppn: Ppn) -> Self {
96 Self {
97 root: ppn,
98 frames: Vec::new(), is_user: true,
100 }
101 }
102
103 fn new_as_kernel_table() -> Self {
105 let frame = alloc_frame().unwrap(); Self {
107 root: frame.ppn(),
108 frames: alloc::vec![frame],
109 is_user: false,
110 }
111 }
112
113 fn root_ppn(&self) -> Ppn {
115 self.root
116 }
117
118 fn get_entry(&self, vpn: Vpn, level: usize) -> Option<(PageTableEntry, PageSize)> {
120 if level >= Self::LEVELS {
121 return None;
122 }
123
124 let mut ppn = self.root;
125 let vpn_value = vpn.as_usize();
126
127 for current_level in (level..Self::LEVELS).rev() {
129 let idx = (vpn_value >> (9 * current_level)) & 0x1ff;
131
132 let pte_array = unsafe {
134 core::slice::from_raw_parts(
135 ppn.start_addr().to_vaddr().as_usize() as *const PageTableEntry,
136 512, )
138 };
139 let pte = &pte_array[idx];
140
141 if !pte.is_valid() {
142 return None; }
144
145 if current_level == level {
146 let page_size = PageSize::Size4K; return Some((*pte, page_size));
156 }
157
158 ppn = pte.ppn();
160 }
161
162 None
163 }
164
165 fn translate(&self, vaddr: Vaddr) -> Option<Paddr> {
167 let vpn = Vpn::from_addr_ceil(vaddr);
168 let offset = vaddr.as_usize() & 0xfff;
170
171 match self.walk(vpn) {
173 Ok((ppn, page_size, _flags)) => {
174 let paddr_base = match page_size {
175 PageSize::Size4K => ppn.start_addr().as_usize(),
176 _ => ppn.start_addr().as_usize(), };
189 Some(Paddr::from_usize(paddr_base + offset))
191 }
192 Err(_) => None,
193 }
194 }
195
196 fn map(
198 &mut self,
199 vpn: Vpn,
200 ppn: Ppn,
201 _page_size: PageSize,
202 flags: UniversalPTEFlag,
203 ) -> PagingResult<()> {
204 if !flags.intersects(
206 UniversalPTEFlag::READABLE | UniversalPTEFlag::WRITEABLE | UniversalPTEFlag::EXECUTABLE,
207 ) {
208 return Err(PagingError::InvalidFlags);
209 }
210
211 let target_level = 0; let mut current_ppn = self.root;
221 let vpn_value = vpn.as_usize();
222
223 for level in (target_level..Self::LEVELS).rev() {
225 let idx = (vpn_value >> (9 * level)) & 0x1ff;
226
227 let pte_array = unsafe {
229 core::slice::from_raw_parts_mut(
230 current_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
231 512,
232 )
233 };
234 let pte = &mut pte_array[idx];
235
236 if level == target_level {
237 if pte.is_valid() {
239 return Err(PagingError::AlreadyMapped); }
241 *pte = PageTableEntry::new_leaf(ppn, flags | UniversalPTEFlag::VALID);
243
244 Self::tlb_flush(vpn);
247 return Ok(());
248 } else {
249 if !pte.is_valid() {
251 let new_frame = alloc_frame().ok_or(PagingError::FrameAllocFailed)?;
253 let new_ppn = new_frame.ppn();
254
255 let new_table = unsafe {
258 core::slice::from_raw_parts_mut(
259 new_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
260 512,
261 )
262 };
263 for entry in new_table.iter_mut() {
264 *entry = PageTableEntry::empty();
265 }
266
267 *pte = PageTableEntry::new_table(new_ppn);
269 self.frames.push(new_frame); } else if pte.is_huge() {
271 return Err(PagingError::HugePageConflict);
273 }
274
275 current_ppn = pte.ppn();
277 }
278 }
279
280 Err(PagingError::InvalidAddress) }
282
283 fn unmap(&mut self, vpn: Vpn) -> PagingResult<()> {
285 let mut current_ppn = self.root;
286 let vpn_value = vpn.as_usize();
287
288 for level in (0..Self::LEVELS).rev() {
290 let idx = (vpn_value >> (9 * level)) & 0x1ff;
291
292 let pte_array = unsafe {
294 core::slice::from_raw_parts_mut(
295 current_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
296 512,
297 )
298 };
299 let pte = &mut pte_array[idx];
300
301 if !pte.is_valid() {
302 return Err(PagingError::NotMapped); }
304
305 if pte.is_huge() || level == 0 {
307 pte.clear();
309 Self::tlb_flush(vpn); return Ok(());
311 }
312
313 current_ppn = pte.ppn();
315 }
316
317 Err(PagingError::NotMapped) }
319
320 fn mvmap(
322 &mut self,
323 vpn: Vpn,
324 target_ppn: Ppn,
325 page_size: PageSize,
326 flags: UniversalPTEFlag,
327 ) -> PagingResult<()> {
328 self.unmap(vpn)?;
330 self.map(vpn, target_ppn, page_size, flags)
332 }
333
334 fn update_flags(&mut self, vpn: Vpn, flags: UniversalPTEFlag) -> PagingResult<()> {
336 let mut current_ppn = self.root;
337 let vpn_value = vpn.as_usize();
338
339 for level in (0..Self::LEVELS).rev() {
341 let idx = (vpn_value >> (9 * level)) & 0x1ff;
342
343 let pte_array = unsafe {
345 core::slice::from_raw_parts_mut(
346 current_ppn.start_addr().to_vaddr().as_usize() as *mut PageTableEntry,
347 512,
348 )
349 };
350 let pte = &mut pte_array[idx];
351
352 if !pte.is_valid() {
353 return Err(PagingError::NotMapped); }
355
356 if pte.is_huge() || level == 0 {
358 pte.set_flags(flags | UniversalPTEFlag::VALID);
360 Self::tlb_flush(vpn); return Ok(());
362 }
363
364 current_ppn = pte.ppn();
366 }
367
368 Err(PagingError::NotMapped) }
370
371 fn walk(&self, vpn: Vpn) -> PagingResult<(Ppn, PageSize, UniversalPTEFlag)> {
373 let mut ppn = self.root;
374 let vpn_value = vpn.as_usize();
375
376 for level in (0..Self::LEVELS).rev() {
379 let idx = (vpn_value >> (9 * level)) & 0x1ff;
380
381 let pte_array = unsafe {
383 core::slice::from_raw_parts(
384 ppn.start_addr().to_vaddr().as_usize() as *const PageTableEntry,
385 512,
386 )
387 };
388 let pte = &pte_array[idx];
389
390 if !pte.is_valid() {
391 return Err(PagingError::NotMapped); }
393
394 if pte.is_huge() || level == 0 {
396 let page_size = PageSize::Size4K; return Ok((pte.ppn(), page_size, pte.flags()));
406 }
407
408 ppn = pte.ppn();
410 }
411
412 Err(PagingError::NotMapped) }
414}
415
416fn ppn_to_satp(ppn: Ppn) -> usize {
418 ppn.as_usize() | (8usize << 60)
420}
421
422#[cfg(test)]
424mod page_table_tests {
425 use super::*;
426 use crate::mm::page_table::PageTableInner as PageTableInnerTrait;
427 use crate::{kassert, test_case};
428
429 test_case!(test_pt_create, {
431 let pt = PageTableInner::new();
432 kassert!(pt.root_ppn().as_usize() > 0);
434 kassert!(pt.is_user_table());
436 });
437
438 test_case!(test_pt_map_translate, {
440 let mut pt = PageTableInner::new();
441 let vpn = Vpn::from_usize(0x1000);
442 let ppn = Ppn::from_usize(0x80000);
443
444 let result = pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw());
446 kassert!(result.is_ok());
447
448 let vaddr = vpn.start_addr();
450 let translated = pt.translate(vaddr);
451 kassert!(translated.is_some());
452 let paddr = translated.unwrap();
453 kassert!(paddr.as_usize() >> 12 == ppn.as_usize());
455 });
456
457 test_case!(test_pt_unmap, {
459 let mut pt = PageTableInner::new();
460 let vpn = Vpn::from_usize(0x1000);
461 let ppn = Ppn::from_usize(0x80000);
462
463 pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw())
465 .unwrap();
466
467 let result = pt.unmap(vpn);
469 kassert!(result.is_ok());
470
471 let vaddr = vpn.start_addr();
473 let translated = pt.translate(vaddr);
474 kassert!(translated.is_none());
475 });
476
477 test_case!(test_pt_error_already_mapped, {
479 let mut pt = PageTableInner::new();
480 let vpn = Vpn::from_usize(0x1000);
481
482 let result1 = pt.map(
484 vpn,
485 Ppn::from_usize(0x80000),
486 PageSize::Size4K,
487 UniversalPTEFlag::kernel_rw(),
488 );
489 kassert!(result1.is_ok());
490
491 let result2 = pt.map(
493 vpn,
494 Ppn::from_usize(0x80001),
495 PageSize::Size4K,
496 UniversalPTEFlag::kernel_rw(),
497 );
498 kassert!(result2.is_err());
499 });
500
501 test_case!(test_pt_walk, {
503 let mut pt = PageTableInner::new();
504 let vpn = Vpn::from_usize(0x1000);
505 let ppn = Ppn::from_usize(0x80000);
506 let original_flags = UniversalPTEFlag::kernel_rw();
507
508 pt.map(vpn, ppn, PageSize::Size4K, original_flags).unwrap();
510
511 let walk_result = pt.walk(vpn);
513 kassert!(walk_result.is_ok());
514
515 let (mapped_ppn, _, mapped_flags) = walk_result.unwrap();
516 kassert!(mapped_ppn == ppn);
517 let expected_flags = UniversalPTEFlag::kernel_rw();
519 kassert!(mapped_flags.bits() == expected_flags.bits());
520 });
521
522 test_case!(test_pt_update_flags, {
524 let mut pt = PageTableInner::new();
525 let vpn = Vpn::from_usize(0x1000);
526 let ppn = Ppn::from_usize(0x80000);
527
528 pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw())
530 .unwrap();
531
532 let update_flags = UniversalPTEFlag::kernel_r();
534 let result = pt.update_flags(vpn, update_flags);
535 kassert!(result.is_ok());
536
537 let (_, _, flags) = pt.walk(vpn).unwrap();
539 let expected_flags = UniversalPTEFlag::kernel_r();
541 kassert!(flags.bits() == expected_flags.bits());
542 });
543
544 test_case!(test_pt_multiple_mappings, {
546 let mut pt = PageTableInner::new();
547
548 for i in 0..10 {
550 let vpn = Vpn::from_usize(0x1000 + i);
551 let ppn = Ppn::from_usize(0x80000 + i);
552 let result = pt.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::kernel_rw());
553 kassert!(result.is_ok());
554 }
555
556 for i in 0..10 {
558 let vpn = Vpn::from_usize(0x1000 + i);
559 let expected_ppn = Ppn::from_usize(0x80000 + i);
560 let (mapped_ppn, _, _) = pt.walk(vpn).unwrap();
561 kassert!(mapped_ppn == expected_ppn);
562 }
563 });
564}