page_table/table/
visit.rs1use super::Pos;
2use crate::{PageTable, Pte, VmMeta};
3use core::ptr::NonNull;
4
5pub trait Visitor<Meta: VmMeta> {
7 fn arrive(&mut self, pte: Pte<Meta>, target: Pos<Meta>) -> Pos<Meta>;
9
10 fn meet(
12 &mut self,
13 level: usize,
14 pte: Pte<Meta>,
15 target: Pos<Meta>,
16 ) -> Option<NonNull<Pte<Meta>>>;
17
18 fn block(&mut self, level: usize, pte: Pte<Meta>, target: Pos<Meta>) -> Pos<Meta>;
25}
26
27pub trait Decorator<Meta: VmMeta> {
29 fn arrive(&mut self, pte: &mut Pte<Meta>, target_hint: Pos<Meta>) -> Pos<Meta>;
31
32 fn meet(
34 &mut self,
35 level: usize,
36 pte: Pte<Meta>,
37 target: Pos<Meta>,
38 ) -> Option<NonNull<Pte<Meta>>>;
39
40 fn block(&mut self, level: usize, pte: Pte<Meta>, target_hint: Pos<Meta>) -> Update<Meta>;
47}
48
49pub enum Update<Meta: VmMeta> {
51 Target(Pos<Meta>),
53 Pte(Pte<Meta>, NonNull<Pte<Meta>>),
55}
56
57pub(super) fn walk_inner<Meta: VmMeta>(
59 table: &PageTable<Meta>,
60 visitor: &mut impl Visitor<Meta>,
61 target: &mut Pos<Meta>,
62) {
63 let range = table.range();
64 let level = table.level;
65 while level >= target.level && range.contains(&target.vpn) {
67 let index = target.vpn.index_in(level);
69 let pte = table.mem[index];
71 if level > target.level {
73 if pte.is_valid() && !pte.is_leaf() {
75 match visitor.meet(level, pte, *target) {
76 Some(ptr) => {
77 let table = unsafe {
78 PageTable::from_raw_parts(
79 ptr,
80 range.start + index * Meta::pages_in_table(level - 1),
81 level - 1,
82 )
83 };
84 walk_inner(&table, visitor, target);
85 }
86 None => *target = Pos::stop(),
87 }
88 }
89 else {
91 *target = visitor.block(level, pte, *target);
92 }
93 }
94 else {
96 *target = visitor.arrive(pte, *target);
97 }
98 }
99}
100
101pub(super) fn walk_inner_mut<Meta: VmMeta>(
103 table: &mut PageTable<Meta>,
104 visitor: &mut impl Decorator<Meta>,
105 target: &mut Pos<Meta>,
106) {
107 let range = table.range();
108 let level = table.level;
109 while level >= target.level && range.contains(&target.vpn) {
111 let index = target.vpn.index_in(level);
113 let pte = &mut table.mem[index];
115 if level > target.level {
117 if pte.is_valid() && !pte.is_leaf() {
119 match visitor.meet(level, *pte, *target) {
120 Some(ptr) => {
121 let mut table = unsafe {
122 PageTable::from_raw_parts(
123 ptr,
124 range.start + index * Meta::pages_in_table(level - 1),
125 level - 1,
126 )
127 };
128 walk_inner_mut(&mut table, visitor, target);
129 }
130 None => *target = Pos::stop(),
131 }
132 }
133 else {
135 match visitor.block(level, *pte, *target) {
136 Update::Target(new) => *target = new,
138 Update::Pte(new, ptr) => {
140 *pte = new;
141 let mut table = unsafe {
142 PageTable::from_raw_parts(
143 ptr,
144 range.start + index * Meta::pages_in_table(level - 1),
145 level - 1,
146 )
147 };
148 walk_inner_mut(&mut table, visitor, target);
149 }
150 }
151 }
152 }
153 else {
155 *target = visitor.arrive(pte, *target);
156 }
157 }
158}