Nothing to see here, move along meow
1use lancer_core::header::{NONE_SENTINEL, obj_link_to_phys, phys_to_obj_link};
2use lancer_core::header::KernelObjectHeader;
3use lancer_core::object_layout::UntypedObject;
4use lancer_core::object_tag::ObjectTag;
5
6use super::pool::ObjectPool;
7use crate::error::KernelError;
8use crate::mem::addr;
9use crate::types::{Generation, ObjPhys};
10use x86_64::PhysAddr;
11
12const MAX_REVOKE_DEPTH: u8 = 16;
13const MAX_CHILDREN_WALK: u32 = 65535;
14
15pub fn link_child(
16 pool: &mut ObjectPool,
17 parent_phys: ObjPhys,
18 parent_gen: Generation,
19 child_phys: ObjPhys,
20) -> Result<(), KernelError> {
21 let ut = pool.write_as::<UntypedObject>(parent_phys, parent_gen)?;
22 let old_first = ut.first_child;
23 ut.first_child = phys_to_obj_link(child_phys.raw());
24
25 let child_hdr = unsafe {
26 &mut *(addr::phys_to_virt(PhysAddr::new(child_phys.raw())).as_mut_ptr::<KernelObjectHeader>())
27 };
28 child_hdr.set_parent_untyped(phys_to_obj_link(parent_phys.raw()));
29 child_hdr.set_next_child(old_first);
30 Ok(())
31}
32
33pub fn unlink_child(pool: &mut ObjectPool, child_phys: ObjPhys) {
34 let child_hdr = unsafe {
35 &*(addr::phys_to_virt(PhysAddr::new(child_phys.raw())).as_ptr::<KernelObjectHeader>())
36 };
37 let parent_link = child_hdr.parent_untyped();
38 if parent_link == NONE_SENTINEL {
39 return;
40 }
41
42 let parent_phys = ObjPhys::new(obj_link_to_phys(parent_link));
43
44 let parent_gen = match pool.generation_of(parent_phys) {
45 Some(g) => g,
46 None => {
47 let child_hdr_mut = unsafe {
48 &mut *(addr::phys_to_virt(PhysAddr::new(child_phys.raw()))
49 .as_mut_ptr::<KernelObjectHeader>())
50 };
51 child_hdr_mut.set_parent_untyped(NONE_SENTINEL);
52 child_hdr_mut.set_next_child(NONE_SENTINEL);
53 return;
54 }
55 };
56
57 let parent_generation = Generation::new(parent_gen);
58 let splice_result = splice_child_from_parent(pool, parent_phys, parent_generation, child_phys);
59
60 let child_hdr_mut = unsafe {
61 &mut *(addr::phys_to_virt(PhysAddr::new(child_phys.raw())).as_mut_ptr::<KernelObjectHeader>())
62 };
63 child_hdr_mut.set_parent_untyped(NONE_SENTINEL);
64 child_hdr_mut.set_next_child(NONE_SENTINEL);
65
66 if splice_result && let Ok(ut) = pool.write_as::<UntypedObject>(parent_phys, parent_generation) {
67 let mut state = ut.to_state();
68 let all_gone = state.remove_child();
69 if all_gone {
70 state.reset_watermark();
71 }
72 ut.apply_state(&state);
73 if all_gone {
74 ut.first_child = NONE_SENTINEL;
75 }
76 }
77}
78
79fn splice_child_from_parent(
80 pool: &mut ObjectPool,
81 parent_phys: ObjPhys,
82 parent_gen: Generation,
83 child_phys: ObjPhys,
84) -> bool {
85 let first_link = match pool.read_as::<UntypedObject>(parent_phys, parent_gen) {
86 Ok(ut) => ut.first_child,
87 Err(_) => return false,
88 };
89
90 match first_link {
91 NONE_SENTINEL => return false,
92 _ => {}
93 }
94
95 let child_link = phys_to_obj_link(child_phys.raw());
96
97 if first_link == child_link {
98 let child_hdr = unsafe {
99 &*(addr::phys_to_virt(PhysAddr::new(child_phys.raw())).as_ptr::<KernelObjectHeader>())
100 };
101 let next = child_hdr.next_child();
102 if let Ok(ut) = pool.write_as::<UntypedObject>(parent_phys, parent_gen) {
103 ut.first_child = next;
104 }
105 return true;
106 }
107
108 let mut prev_phys = obj_link_to_phys(first_link);
109 let mut steps = 0u32;
110 loop {
111 if steps >= MAX_CHILDREN_WALK {
112 return false;
113 }
114 steps += 1;
115
116 let prev_hdr = unsafe {
117 &*(addr::phys_to_virt(PhysAddr::new(prev_phys)).as_ptr::<KernelObjectHeader>())
118 };
119 let next_link = prev_hdr.next_child();
120 match next_link {
121 NONE_SENTINEL => return false,
122 link if link == child_link => {
123 let child_hdr = unsafe {
124 &*(addr::phys_to_virt(PhysAddr::new(child_phys.raw()))
125 .as_ptr::<KernelObjectHeader>())
126 };
127 let child_next = child_hdr.next_child();
128 let prev_hdr_mut = unsafe {
129 &mut *(addr::phys_to_virt(PhysAddr::new(prev_phys))
130 .as_mut_ptr::<KernelObjectHeader>())
131 };
132 prev_hdr_mut.set_next_child(child_next);
133 return true;
134 }
135 link => prev_phys = obj_link_to_phys(link),
136 }
137 }
138}
139
140pub fn destroy_children(
141 pool: &mut ObjectPool,
142 ptable: &mut crate::proc::ProcessManager,
143 untyped_phys: ObjPhys,
144 untyped_gen: Generation,
145) -> Result<(), KernelError> {
146 destroy_children_inner(pool, ptable, untyped_phys, untyped_gen, 0)
147}
148
149fn destroy_children_inner(
150 pool: &mut ObjectPool,
151 ptable: &mut crate::proc::ProcessManager,
152 untyped_phys: ObjPhys,
153 untyped_gen: Generation,
154 depth: u8,
155) -> Result<(), KernelError> {
156 if depth >= MAX_REVOKE_DEPTH {
157 return Err(KernelError::DepthLimit);
158 }
159
160 let first_child_link = {
161 let ut = pool.read_as::<UntypedObject>(untyped_phys, untyped_gen)?;
162 ut.first_child
163 };
164
165 let mut current_link = match first_child_link {
166 NONE_SENTINEL => return Ok(()),
167 link => link,
168 };
169
170 let mut steps = 0u32;
171 loop {
172 if current_link == NONE_SENTINEL || steps >= MAX_CHILDREN_WALK {
173 break;
174 }
175 steps += 1;
176
177 let current_phys = ObjPhys::new(obj_link_to_phys(current_link));
178
179 let child_hdr = unsafe {
180 &*(addr::phys_to_virt(PhysAddr::new(current_phys.raw())).as_ptr::<KernelObjectHeader>())
181 };
182 let next_sibling_link = child_hdr.next_child();
183
184 let child_gen = match pool.generation_of(current_phys) {
185 Some(g) => g,
186 None => {
187 let child_hdr_mut = unsafe {
188 &mut *(addr::phys_to_virt(PhysAddr::new(current_phys.raw()))
189 .as_mut_ptr::<KernelObjectHeader>())
190 };
191 child_hdr_mut.set_parent_untyped(NONE_SENTINEL);
192 child_hdr_mut.set_next_child(NONE_SENTINEL);
193 current_link = next_sibling_link;
194 continue;
195 }
196 };
197
198 let child_generation = Generation::new(child_gen);
199
200 let child_tag = match pool.get_tag(current_phys, child_generation) {
201 Ok(tag) => tag,
202 Err(_) => {
203 let child_hdr_mut = unsafe {
204 &mut *(addr::phys_to_virt(PhysAddr::new(current_phys.raw()))
205 .as_mut_ptr::<KernelObjectHeader>())
206 };
207 child_hdr_mut.set_parent_untyped(NONE_SENTINEL);
208 child_hdr_mut.set_next_child(NONE_SENTINEL);
209 current_link = next_sibling_link;
210 continue;
211 }
212 };
213
214 let stale_gen = child_generation;
215
216 match child_tag {
217 ObjectTag::Untyped => {
218 destroy_children_inner(pool, ptable, current_phys, child_generation, depth + 1)?;
219 let _ = pool.revoke_phys(current_phys, child_generation);
220 }
221
222 ObjectTag::Process => {
223 let pid = pool
224 .read_as::<lancer_core::object_layout::ProcessObject>(
225 current_phys,
226 child_generation,
227 )
228 .ok()
229 .and_then(|p| crate::types::Pid::try_new(p.pid));
230
231 if let Some(pid) = pid {
232 ptable.force_destroy_with_pool(pid, pool);
233 }
234
235 let _ = pool.revoke_phys(current_phys, child_generation);
236 }
237
238 ObjectTag::CNode => {
239 let cnode_snapshot = pool
240 .read_as::<lancer_core::object_layout::CNodeObject>(
241 current_phys,
242 child_generation,
243 )
244 .ok()
245 .map(|c| {
246 (
247 x86_64::PhysAddr::new(c.slots_phys),
248 c.size_bits,
249 c.frame_count,
250 )
251 });
252
253 let _ = pool.revoke_phys(current_phys, child_generation);
254
255 if let Some((slots_phys, size_bits, frame_count)) = cnode_snapshot {
256 super::cnode::drain_cnode_phys(
257 slots_phys,
258 size_bits,
259 frame_count,
260 pool,
261 ptable,
262 );
263 }
264 }
265
266 _ => {
267 let revoke_result = pool.revoke_phys(current_phys, child_generation);
268 if let Ok((_new_gen, Some((phys, tag)))) = revoke_result {
269 super::ops::cleanup_by_tag_with_ptable(tag, phys, ptable);
270 }
271 }
272 }
273
274 super::ops::invalidate_stale_caps_via_cnode(ptable, pool, current_phys, stale_gen);
275
276 let child_hdr_mut = unsafe {
277 &mut *(addr::phys_to_virt(PhysAddr::new(current_phys.raw()))
278 .as_mut_ptr::<KernelObjectHeader>())
279 };
280 child_hdr_mut.set_parent_untyped(NONE_SENTINEL);
281 child_hdr_mut.set_next_child(NONE_SENTINEL);
282
283 current_link = next_sibling_link;
284 }
285
286 let ut = pool.write_as::<UntypedObject>(untyped_phys, untyped_gen)?;
287 ut.first_child = NONE_SENTINEL;
288 let mut state = ut.to_state();
289 state.reset_all_children();
290 ut.apply_state(&state);
291
292 Ok(())
293}