Nothing to see here, move along
1use crate::cap::cnode;
2use crate::cap::pool::POOL;
3use crate::cap::table::{CapRef, CapSlot, Rights};
4use crate::error::KernelError;
5use crate::mem::phys::BitmapFrameAllocator;
6use crate::proc::PROCESSES;
7use lancer_core::object_layout::KernelObject;
8use lancer_core::object_tag::ObjectTag;
9
10fn alloc_cnode_object(
11 cnode_data: &crate::cap::object::CNodeData,
12 pool: &mut crate::cap::pool::ObjectPool,
13) -> (crate::types::ObjPhys, crate::types::Generation) {
14 let obj_phys = crate::cap::kernel_objects::alloc_slot().expect("alloc slot");
15 let header = lancer_core::header::KernelObjectHeader::new(ObjectTag::CNode, 0, 64);
16 let mut obj = lancer_core::object_layout::CNodeObject::init_default(header);
17 obj.slots_phys = cnode_data.slots_phys.as_u64();
18 obj.size_bits = cnode_data.size_bits;
19 obj.frame_count = cnode_data.frame_count;
20 crate::cap::kernel_objects::write_at(obj_phys, obj);
21 pool.register_object(obj_phys, ObjectTag::CNode)
22 .expect("register")
23}
24
25fn bootstrap_test_cnode(pid: crate::types::Pid, ptable: &mut crate::proc::ProcessManager) {
26 let size_bits = crate::proc::ROOT_CNODE_SIZE_BITS;
27 let allocator = &BitmapFrameAllocator;
28 let cnode_data = cnode::create_cnode(size_bits, allocator).expect("create cnode");
29 let frame_count = cnode_data.frame_count;
30 let (cnode_id, cnode_gen) = alloc_cnode_object(&cnode_data, &mut POOL.lock());
31 let exec = ptable.exec_mut(pid).expect("get exec");
32 exec.root_cnode = Some((cnode_id, cnode_gen));
33 exec.cnode_depth = 64;
34 exec.root_guard_bits = 64 - size_bits;
35 exec.root_guard_value = 0;
36 exec.charge_frames(frame_count as u16)
37 .expect("charge frames");
38}
39
40crate::kernel_test!(
41 fn cnode_create_and_destroy() {
42 let allocator = &BitmapFrameAllocator;
43 let cnode_data = cnode::create_cnode(4, allocator).expect("create cnode");
44 assert!(cnode_data.size_bits == 4);
45 assert!(cnode_data.frame_count > 0);
46 cnode::destroy_cnode(&cnode_data, allocator);
47 }
48);
49
50crate::kernel_test!(
51 fn cnode_create_invalid_size_rejected() {
52 let allocator = &BitmapFrameAllocator;
53 assert!(matches!(
54 cnode::create_cnode(0, allocator),
55 Err(KernelError::InvalidParameter)
56 ));
57 assert!(matches!(
58 cnode::create_cnode(16, allocator),
59 Err(KernelError::InvalidParameter)
60 ));
61 }
62);
63
64crate::kernel_test!(
65 fn single_level_resolve_insert_read() {
66 let allocator = &BitmapFrameAllocator;
67 let cnode_data = cnode::create_cnode(4, allocator).expect("create");
68 let (cid, cgen) = alloc_cnode_object(&cnode_data, &mut POOL.lock());
69
70 let (ep_id, ep_gen) =
71 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc ep");
72 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
73
74 {
75 let pool = POOL.lock();
76 cnode::resolve_and_insert(&pool, cid, cgen, 5, 4, 0, 0, cap).expect("insert");
77 }
78
79 {
80 let pool = POOL.lock();
81 let read = cnode::resolve_and_read(&pool, cid, cgen, 5, 4, 0, 0).expect("read");
82 assert!(read.tag() == ObjectTag::Endpoint);
83 assert!(read.phys() == ep_id);
84 }
85
86 {
87 let pool = POOL.lock();
88 let slot = cnode::resolve(&pool, cid, cgen, 0, 4, 0, 0).expect("empty slot");
89 assert!(matches!(slot, CapSlot::Empty));
90 }
91
92 {
93 let mut pool = POOL.lock();
94 pool.dec_ref_phys(ep_id, ep_gen);
95 pool.dec_ref_phys(cid, cgen);
96 }
97 }
98);
99
100crate::kernel_test!(
101 fn two_level_resolve() {
102 let allocator = &BitmapFrameAllocator;
103
104 let inner_data = cnode::create_cnode(4, allocator).expect("inner cnode");
105 let (inner_id, inner_gen) = alloc_cnode_object(&inner_data, &mut POOL.lock());
106
107 let outer_data = cnode::create_cnode(4, allocator).expect("outer cnode");
108 let (outer_id, outer_gen) = alloc_cnode_object(&outer_data, &mut POOL.lock());
109
110 let inner_cap = CapRef::new(ObjectTag::CNode, inner_id, Rights::ALL, inner_gen);
111 {
112 let pool = POOL.lock();
113 cnode::resolve_and_insert(&pool, outer_id, outer_gen, 3, 4, 0, 0, inner_cap)
114 .expect("insert inner cnode at slot 3");
115 }
116
117 let (ep_id, ep_gen) =
118 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc ep");
119 let ep_cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
120
121 let address: u64 = (3 << 4) | 7;
122 {
123 let pool = POOL.lock();
124 cnode::resolve_and_insert(&pool, outer_id, outer_gen, address, 8, 0, 0, ep_cap)
125 .expect("insert ep at two-level address");
126 }
127
128 {
129 let pool = POOL.lock();
130 let read = cnode::resolve_and_read(&pool, outer_id, outer_gen, address, 8, 0, 0)
131 .expect("two-level read");
132 assert!(read.tag() == ObjectTag::Endpoint);
133 assert!(read.phys() == ep_id);
134 }
135
136 {
137 let mut pool = POOL.lock();
138 pool.dec_ref_phys(ep_id, ep_gen);
139 let _ = cnode::resolve_and_clear(&pool, outer_id, outer_gen, 3, 4, 0, 0);
140 pool.dec_ref_phys(inner_id, inner_gen);
141 pool.dec_ref_phys(outer_id, outer_gen);
142 }
143 }
144);
145
146crate::kernel_test!(
147 fn resolve_empty_slot_fails() {
148 let allocator = &BitmapFrameAllocator;
149 let cnode_data = cnode::create_cnode(4, allocator).expect("create");
150 let (cid, cgen) = alloc_cnode_object(&cnode_data, &mut POOL.lock());
151
152 {
153 let pool = POOL.lock();
154 let result = cnode::resolve_and_read(&pool, cid, cgen, 0, 4, 0, 0);
155 assert!(matches!(result, Err(KernelError::SlotEmpty)));
156 }
157
158 POOL.lock().dec_ref_phys(cid, cgen);
159 }
160);
161
162crate::kernel_test!(
163 fn resolve_non_cnode_in_path_fails() {
164 let allocator = &BitmapFrameAllocator;
165 let cnode_data = cnode::create_cnode(4, allocator).expect("create");
166 let (cid, cgen) = alloc_cnode_object(&cnode_data, &mut POOL.lock());
167
168 let (ep_id, ep_gen) =
169 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc ep");
170 let ep_cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
171
172 {
173 let pool = POOL.lock();
174 cnode::resolve_and_insert(&pool, cid, cgen, 2, 4, 0, 0, ep_cap).expect("insert ep");
175 }
176
177 let address: u64 = (2 << 4) | 5;
178 {
179 let pool = POOL.lock();
180 let result = cnode::resolve_and_read(&pool, cid, cgen, address, 8, 0, 0);
181 assert!(matches!(result, Err(KernelError::InvalidSlot)));
182 }
183
184 {
185 let mut pool = POOL.lock();
186 pool.dec_ref_phys(ep_id, ep_gen);
187 pool.dec_ref_phys(cid, cgen);
188 }
189 }
190);
191
192crate::kernel_test!(
193 fn stale_generation_rejected() {
194 let allocator = &BitmapFrameAllocator;
195 let cnode_data = cnode::create_cnode(4, allocator).expect("create");
196 let (cid, cgen) = alloc_cnode_object(&cnode_data, &mut POOL.lock());
197
198 let stale_gen = cgen;
199 {
200 let mut pool = POOL.lock();
201 let _ = pool.revoke_phys(cid, cgen);
202 }
203
204 {
205 let pool = POOL.lock();
206 let result = cnode::resolve(&pool, cid, stale_gen, 0, 4, 0, 0);
207 assert!(matches!(result, Err(KernelError::StaleGeneration)));
208 }
209
210 POOL.lock().dec_ref_phys(cid, stale_gen.wrapping_inc());
211 }
212);
213
214crate::kernel_test!(
215 fn invalidate_stale_across_cnode() {
216 let allocator = &BitmapFrameAllocator;
217 let cnode_data = cnode::create_cnode(4, allocator).expect("create");
218 let (cid, cgen) = alloc_cnode_object(&cnode_data, &mut POOL.lock());
219
220 let (ep_id, ep_gen) =
221 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc ep");
222 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
223
224 {
225 let pool = POOL.lock();
226 cnode::resolve_and_insert(&pool, cid, cgen, 1, 4, 0, 0, cap).expect("insert");
227 }
228 POOL.lock().inc_ref(ep_id, ep_gen).expect("inc ref");
229 {
230 let pool = POOL.lock();
231 cnode::resolve_and_insert(&pool, cid, cgen, 7, 4, 0, 0, cap).expect("insert 2");
232 }
233
234 {
235 let pool = POOL.lock();
236 cnode::invalidate_stale_in_cnode(&pool, cid, cgen, ep_id, ep_gen).expect("invalidate");
237 }
238
239 {
240 let pool = POOL.lock();
241 let slot1 = cnode::resolve(&pool, cid, cgen, 1, 4, 0, 0).expect("check 1");
242 let slot7 = cnode::resolve(&pool, cid, cgen, 7, 4, 0, 0).expect("check 7");
243 assert!(matches!(slot1, CapSlot::Empty));
244 assert!(matches!(slot7, CapSlot::Empty));
245 }
246
247 {
248 let mut pool = POOL.lock();
249 pool.dec_ref_phys(ep_id, ep_gen);
250 pool.dec_ref_phys(cid, cgen);
251 }
252 }
253);
254
255crate::kernel_test!(
256 fn drain_cnode_tree_cleans_all() {
257 let mut allocator = BitmapFrameAllocator;
258 let mut ptable = PROCESSES.lock();
259 let created = ptable.allocate(&mut allocator).expect("alloc");
260 ptable.start(created).expect("start");
261 let pid = created.pid();
262 bootstrap_test_cnode(pid, &mut ptable);
263
264 let (cnode_id, cnode_gen, depth, gv, gb) =
265 cnode::cnode_coords(pid, &ptable).expect("coords");
266
267 (0..3u64).for_each(|i| {
268 let (eid, egen) = crate::tests::helpers::alloc_endpoint(&mut POOL.lock_after(&ptable))
269 .expect("alloc ep");
270 let cap = CapRef::new(ObjectTag::Endpoint, eid, Rights::ALL, egen);
271 let pool = POOL.lock_after(&ptable);
272 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, i, depth, gv, gb, cap)
273 .expect("insert");
274 });
275
276 let mut drained_count = 0u32;
277 {
278 let mut pool = POOL.lock_after(&ptable);
279 cnode::drain_cnode_tree(&mut pool, cnode_id, cnode_gen, &mut |cap, pool| {
280 pool.dec_ref_phys(cap.phys(), cap.generation());
281 drained_count += 1;
282 })
283 .expect("drain");
284 }
285 assert!(
286 drained_count == 3,
287 "expected 3 drained caps, got {}",
288 drained_count
289 );
290
291 {
292 let pool = POOL.lock_after(&ptable);
293 let slot0 =
294 cnode::resolve(&pool, cnode_id, cnode_gen, 0, depth, gv, gb).expect("slot0");
295 assert!(matches!(slot0, CapSlot::Empty));
296 }
297
298 ptable.destroy(pid, &mut allocator);
299 }
300);
301
302crate::kernel_test!(
303 fn thread_shares_parent_cnode() {
304 let mut allocator = BitmapFrameAllocator;
305 let mut ptable = PROCESSES.lock();
306
307 let parent_created = ptable.allocate(&mut allocator).expect("alloc parent");
308 ptable.start(parent_created).expect("start parent");
309 let parent_pid = parent_created.pid();
310 bootstrap_test_cnode(parent_pid, &mut ptable);
311
312 let parent_cnode = ptable
313 .exec(parent_pid)
314 .expect("get parent exec")
315 .root_cnode();
316
317 let (ut_id, ut_gen, _) = crate::tests::helpers::allocate_small_untyped(&ptable, 16);
318
319 let (cnode_id_p, cnode_gen_p, depth_p, gv_p, gb_p) =
320 cnode::cnode_coords(parent_pid, &ptable).expect("coords");
321 let child_pid = {
322 let mut pool = POOL.lock_after(&ptable);
323 crate::cap::retype::retype_thread_from_untyped(
324 &mut pool,
325 &mut ptable,
326 ut_id,
327 ut_gen,
328 parent_pid,
329 cnode_id_p,
330 cnode_gen_p,
331 210,
332 depth_p,
333 gv_p,
334 gb_p,
335 )
336 .expect("retype thread")
337 };
338
339 let child_cnode = ptable.exec(child_pid).expect("get child exec").root_cnode();
340
341 assert!(
342 parent_cnode == child_cnode,
343 "thread must share parent's root CNode"
344 );
345 assert!(child_cnode.is_some(), "thread must have a root CNode");
346
347 let (cnode_id, cnode_gen, depth, gv, gb) =
348 cnode::cnode_coords(parent_pid, &ptable).expect("coords");
349 let (ep_id, ep_gen) =
350 crate::tests::helpers::alloc_endpoint(&mut POOL.lock_after(&ptable)).expect("alloc ep");
351 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
352 {
353 let pool = POOL.lock_after(&ptable);
354 cnode::resolve_and_insert(&pool, cnode_id, cnode_gen, 5, depth, gv, gb, cap)
355 .expect("insert via parent");
356 }
357
358 {
359 let (child_cid, child_cgen, child_depth, child_gv, child_gb) =
360 cnode::cnode_coords(child_pid, &ptable).expect("child coords");
361 let pool = POOL.lock_after(&ptable);
362 let read = cnode::resolve_and_read(
363 &pool,
364 child_cid,
365 child_cgen,
366 5,
367 child_depth,
368 child_gv,
369 child_gb,
370 )
371 .expect("read via child");
372 assert!(read.tag() == ObjectTag::Endpoint);
373 assert!(read.phys() == ep_id);
374 }
375
376 ptable.destroy(child_pid, &mut allocator);
377 ptable.destroy(parent_pid, &mut allocator);
378 }
379);