Nothing to see here, move along meow
1use crate::cap::cnode;
2use crate::cap::pool::POOL;
3use crate::cap::retype::kernel_retype;
4use crate::proc::PROCESSES;
5use crate::tests::helpers;
6use lancer_core::header::KernelObjectHeader;
7use lancer_core::object_layout::{KernelObject, UntypedObject};
8use lancer_core::object_tag::ObjectTag;
9
10crate::kernel_test!(
11 fn revoke_untyped_destroys_children() {
12 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
13 let mut ptable = PROCESSES.lock();
14 let created = ptable.allocate(&mut allocator).expect("alloc");
15 ptable.start(created).expect("start");
16 let pid = created.pid();
17 helpers::bootstrap_test_cnode(pid, &mut ptable);
18
19 let (ut_id, ut_gen, _phys) = helpers::allocate_untyped(&ptable, false);
20 let (cnode_id, cnode_gen, depth, gv, gb) =
21 cnode::cnode_coords(pid, &ptable).expect("coords");
22 let dest_base = 50u64;
23 let count = 5u32;
24
25 {
26 let mut pool = POOL.lock_after(&ptable);
27 kernel_retype(
28 &mut pool,
29 None,
30 ut_id,
31 ut_gen,
32 ObjectTag::Endpoint,
33 0,
34 cnode_id,
35 cnode_gen,
36 dest_base,
37 depth,
38 gv,
39 gb,
40 count,
41 )
42 .expect("retype 5 endpoints");
43 }
44
45 (0..count as u64).for_each(|i| {
46 let pool = POOL.lock_after(&ptable);
47 let cap =
48 cnode::resolve_and_read(&pool, cnode_id, cnode_gen, dest_base + i, depth, gv, gb)
49 .expect("read slot before revoke");
50 assert!(cap.tag() == ObjectTag::Endpoint);
51 });
52
53 {
54 let mut pool = POOL.lock_after(&ptable);
55 crate::cap::derivation::destroy_children(&mut pool, &mut ptable, ut_id, ut_gen)
56 .expect("destroy_children");
57 }
58
59 {
60 let pool = POOL.lock_after(&ptable);
61 let ut = pool
62 .read_as::<UntypedObject>(ut_id, ut_gen)
63 .expect("untyped still valid");
64 assert!(ut.watermark == 0, "watermark must reset after revoke");
65 assert!(ut.child_count == 0, "child_count must be 0 after revoke");
66 assert!(
67 ut.first_child == lancer_core::header::NONE_SENTINEL,
68 "first_child must be sentinel after revoke"
69 );
70 }
71
72 ptable.destroy(pid, &mut allocator);
73 }
74);
75
76crate::kernel_test!(
77 fn revoke_then_retype_succeeds() {
78 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
79 let mut ptable = PROCESSES.lock();
80 let created = ptable.allocate(&mut allocator).expect("alloc");
81 ptable.start(created).expect("start");
82 let pid = created.pid();
83 helpers::bootstrap_test_cnode(pid, &mut ptable);
84
85 let (ut_id, ut_gen, _phys) = helpers::allocate_untyped(&ptable, false);
86 let (cnode_id, cnode_gen, depth, gv, gb) =
87 cnode::cnode_coords(pid, &ptable).expect("coords");
88
89 {
90 let mut pool = POOL.lock_after(&ptable);
91 kernel_retype(
92 &mut pool,
93 None,
94 ut_id,
95 ut_gen,
96 ObjectTag::Endpoint,
97 0,
98 cnode_id,
99 cnode_gen,
100 50,
101 depth,
102 gv,
103 gb,
104 3,
105 )
106 .expect("first retype");
107 }
108
109 {
110 let mut pool = POOL.lock_after(&ptable);
111 crate::cap::derivation::destroy_children(&mut pool, &mut ptable, ut_id, ut_gen)
112 .expect("destroy_children");
113 }
114
115 {
116 let mut pool = POOL.lock_after(&ptable);
117 kernel_retype(
118 &mut pool,
119 None,
120 ut_id,
121 ut_gen,
122 ObjectTag::Endpoint,
123 0,
124 cnode_id,
125 cnode_gen,
126 60,
127 depth,
128 gv,
129 gb,
130 4,
131 )
132 .expect("second retype after revoke must succeed");
133 }
134
135 (0..4u64).for_each(|i| {
136 let pool = POOL.lock_after(&ptable);
137 let cap = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 60 + i, depth, gv, gb)
138 .expect("read re-retyped slot");
139 assert!(cap.tag() == ObjectTag::Endpoint);
140 });
141
142 ptable.destroy(pid, &mut allocator);
143 }
144);
145
146crate::kernel_test!(
147 fn delete_last_cap_unlinks_from_parent() {
148 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
149 let mut ptable = PROCESSES.lock();
150 let created = ptable.allocate(&mut allocator).expect("alloc");
151 ptable.start(created).expect("start");
152 let pid = created.pid();
153 helpers::bootstrap_test_cnode(pid, &mut ptable);
154
155 let (ut_id, ut_gen, _phys) = helpers::allocate_untyped(&ptable, false);
156 let (cnode_id, cnode_gen, depth, gv, gb) =
157 cnode::cnode_coords(pid, &ptable).expect("coords");
158 let dest_base = 70u64;
159 let count = 3u32;
160
161 {
162 let mut pool = POOL.lock_after(&ptable);
163 kernel_retype(
164 &mut pool,
165 None,
166 ut_id,
167 ut_gen,
168 ObjectTag::Endpoint,
169 0,
170 cnode_id,
171 cnode_gen,
172 dest_base,
173 depth,
174 gv,
175 gb,
176 count,
177 )
178 .expect("retype 3 endpoints");
179 }
180
181 {
182 let pool = POOL.lock_after(&ptable);
183 let ut = pool
184 .read_as::<UntypedObject>(ut_id, ut_gen)
185 .expect("get ut");
186 assert!(ut.child_count == 3, "3 children after retype");
187 }
188
189 (0..count as u64).for_each(|i| {
190 let mut pool = POOL.lock_after(&ptable);
191 let cap =
192 cnode::resolve_and_clear(&pool, cnode_id, cnode_gen, dest_base + i, depth, gv, gb)
193 .expect("clear slot");
194 let freed_id = cap.phys();
195 if let Some((_phys, _tag)) = pool.dec_ref_phys(cap.phys(), cap.generation()) {
196 crate::cap::derivation::unlink_child(&mut pool, freed_id);
197 }
198 });
199
200 {
201 let pool = POOL.lock_after(&ptable);
202 let ut = pool
203 .read_as::<UntypedObject>(ut_id, ut_gen)
204 .expect("get ut after deletes");
205 assert!(
206 ut.child_count == 0,
207 "child_count must be 0 after all deletes"
208 );
209 assert!(
210 ut.watermark == 0,
211 "watermark must reset when last child deleted"
212 );
213 assert!(
214 ut.first_child == lancer_core::header::NONE_SENTINEL,
215 "first_child must be sentinel"
216 );
217 }
218
219 ptable.destroy(pid, &mut allocator);
220 }
221);
222
223crate::kernel_test!(
224 fn revoke_nested_untypeds_cascades() {
225 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
226 let mut ptable = PROCESSES.lock();
227 let created = ptable.allocate(&mut allocator).expect("alloc");
228 ptable.start(created).expect("start");
229 let pid = created.pid();
230 helpers::bootstrap_test_cnode(pid, &mut ptable);
231
232 let (parent_ut_id, parent_ut_gen, _phys) = helpers::allocate_untyped(&ptable, false);
233 let (cnode_id, cnode_gen, depth, gv, gb) =
234 cnode::cnode_coords(pid, &ptable).expect("coords");
235
236 let child_size_bits = 14u8;
237 let child_frames = 1usize << (child_size_bits - 12);
238 let child_phys = crate::mem::phys::BitmapFrameAllocator
239 .allocate_contiguous(child_frames)
240 .expect("alloc child untyped backing");
241 let child_virt = crate::mem::addr::phys_to_virt(child_phys);
242 unsafe {
243 core::ptr::write_bytes(child_virt.as_mut_ptr::<u8>(), 0, child_frames * 4096);
244 }
245
246 let header = KernelObjectHeader::new(ObjectTag::Untyped, 0, 64);
247 let mut child_ut = UntypedObject::init_default(header);
248 child_ut.phys_base = child_phys.as_u64();
249 child_ut.size_bits = child_size_bits;
250 child_ut.is_device = 0;
251 let child_slot_phys =
252 crate::cap::kernel_objects::alloc_slot().expect("alloc child ut slot");
253 crate::cap::kernel_objects::write_at(child_slot_phys, child_ut);
254
255 let (child_ut_id, child_ut_gen) = {
256 let mut pool = POOL.lock_after(&ptable);
257 let (cid, cgen) = pool
258 .register_object(child_slot_phys, ObjectTag::Untyped)
259 .expect("register child ut");
260 crate::cap::derivation::link_child(&mut pool, parent_ut_id, parent_ut_gen, cid)
261 .expect("link child untyped to parent");
262 let cap = crate::cap::table::CapRef::new(
263 ObjectTag::Untyped,
264 cid,
265 crate::cap::table::Rights::ALL,
266 cgen,
267 );
268 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 80, depth, gv, gb, cap)
269 .expect("insert child untyped cap");
270 (cid, cgen)
271 };
272
273 {
274 let mut pool = POOL.lock_after(&ptable);
275 kernel_retype(
276 &mut pool,
277 None,
278 child_ut_id,
279 child_ut_gen,
280 ObjectTag::Endpoint,
281 0,
282 cnode_id,
283 cnode_gen,
284 81,
285 depth,
286 gv,
287 gb,
288 2,
289 )
290 .expect("retype endpoints from child untyped");
291 }
292
293 let ep_ids: [(crate::types::ObjPhys, crate::types::Generation); 2] = {
294 let pool = POOL.lock_after(&ptable);
295 let c0 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 81, depth, gv, gb)
296 .expect("read ep 0");
297 let c1 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 82, depth, gv, gb)
298 .expect("read ep 1");
299 [
300 (c0.phys(), c0.generation()),
301 (c1.phys(), c1.generation()),
302 ]
303 };
304
305 {
306 let mut pool = POOL.lock_after(&ptable);
307 crate::cap::derivation::destroy_children(
308 &mut pool,
309 &mut ptable,
310 parent_ut_id,
311 parent_ut_gen,
312 )
313 .expect("destroy_children on parent");
314 }
315
316 {
317 let pool = POOL.lock_after(&ptable);
318 let ut = pool
319 .read_as::<UntypedObject>(parent_ut_id, parent_ut_gen)
320 .expect("parent untyped still valid");
321 assert!(ut.watermark == 0, "parent watermark must reset");
322 assert!(ut.child_count == 0, "parent child_count must be 0");
323 assert!(
324 ut.first_child == lancer_core::header::NONE_SENTINEL,
325 "parent first_child must be sentinel"
326 );
327
328 assert!(
329 pool.get_tag(child_ut_id, child_ut_gen).is_err(),
330 "child untyped must be destroyed"
331 );
332
333 ep_ids.iter().for_each(|&(eid, egen)| {
334 assert!(
335 pool.get_tag(eid, egen).is_err(),
336 "grandchild endpoint must be destroyed"
337 );
338 });
339 }
340
341 ptable.destroy(pid, &mut allocator);
342 }
343);
344
345crate::kernel_test!(
346 fn revoke_frame_caps_destroys_objects() {
347 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
348 let mut ptable = PROCESSES.lock();
349 let created = ptable.allocate(&mut allocator).expect("alloc");
350 ptable.start(created).expect("start");
351 let pid = created.pid();
352 helpers::bootstrap_test_cnode(pid, &mut ptable);
353
354 let (ut_id, ut_gen, _phys) = helpers::allocate_untyped(&ptable, false);
355 let (cnode_id, cnode_gen, depth, gv, gb) =
356 cnode::cnode_coords(pid, &ptable).expect("coords");
357
358 {
359 let mut pool = POOL.lock_after(&ptable);
360 kernel_retype(
361 &mut pool,
362 None,
363 ut_id,
364 ut_gen,
365 ObjectTag::Frame,
366 12,
367 cnode_id,
368 cnode_gen,
369 90,
370 depth,
371 gv,
372 gb,
373 2,
374 )
375 .expect("retype 2 frames");
376 }
377
378 let frame_ids: [(crate::types::ObjPhys, crate::types::Generation); 2] = {
379 let pool = POOL.lock_after(&ptable);
380 let cap0 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 90, depth, gv, gb)
381 .expect("read frame 0");
382 let cap1 = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 91, depth, gv, gb)
383 .expect("read frame 1");
384 [
385 (cap0.phys(), cap0.generation()),
386 (cap1.phys(), cap1.generation()),
387 ]
388 };
389
390 {
391 let mut pool = POOL.lock_after(&ptable);
392 crate::cap::derivation::destroy_children(&mut pool, &mut ptable, ut_id, ut_gen)
393 .expect("destroy_children");
394 }
395
396 {
397 let pool = POOL.lock_after(&ptable);
398 frame_ids.iter().for_each(|&(fid, fgen)| {
399 assert!(
400 pool.get_tag(fid, fgen).is_err(),
401 "frame object must be destroyed"
402 );
403 });
404
405 let ut = pool
406 .read_as::<UntypedObject>(ut_id, ut_gen)
407 .expect("untyped still valid");
408 assert!(ut.watermark == 0, "watermark must reset");
409 assert!(ut.child_count == 0, "child_count must be 0");
410 }
411
412 ptable.destroy(pid, &mut allocator);
413 }
414);
415
416crate::kernel_test!(
417 fn revoke_with_active_tcb() {
418 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
419 let mut ptable = PROCESSES.lock();
420 let created = ptable.allocate(&mut allocator).expect("alloc");
421 ptable.start(created).expect("start");
422 let pid = created.pid();
423 helpers::bootstrap_test_cnode(pid, &mut ptable);
424
425 let (ut_id, ut_gen, _phys) = helpers::allocate_untyped(&ptable, false);
426 let (cnode_id, cnode_gen, depth, gv, gb) =
427 cnode::cnode_coords(pid, &ptable).expect("coords");
428
429 {
430 let mut pool = POOL.lock_after(&ptable);
431 kernel_retype(
432 &mut pool,
433 Some(&mut ptable),
434 ut_id,
435 ut_gen,
436 ObjectTag::Process,
437 0,
438 cnode_id,
439 cnode_gen,
440 95,
441 depth,
442 gv,
443 gb,
444 1,
445 )
446 .expect("retype process from untyped");
447 }
448
449 let (proc_obj_id, proc_obj_gen) = {
450 let pool = POOL.lock_after(&ptable);
451 let cap = cnode::resolve_and_read(&pool, cnode_id, cnode_gen, 95, depth, gv, gb)
452 .expect("read process cap");
453 assert!(cap.tag() == ObjectTag::Process);
454 (cap.phys(), cap.generation())
455 };
456
457 {
458 let mut pool = POOL.lock_after(&ptable);
459 crate::cap::derivation::destroy_children(&mut pool, &mut ptable, ut_id, ut_gen)
460 .expect("destroy_children with tcb");
461 }
462
463 {
464 let pool = POOL.lock_after(&ptable);
465 assert!(
466 pool.get_tag(proc_obj_id, proc_obj_gen).is_err(),
467 "process object must be destroyed"
468 );
469
470 let ut = pool
471 .read_as::<UntypedObject>(ut_id, ut_gen)
472 .expect("untyped still valid");
473 assert!(ut.watermark == 0, "watermark must reset");
474 }
475
476 ptable.destroy(pid, &mut allocator);
477 }
478);