Nothing to see here, move along meow
1use crate::cap::pool::POOL;
2use crate::ipc::{AlwaysBlocked, IpcOutcome, endpoint, message};
3use crate::proc::context::{CpuContext, IpcMessage};
4use crate::proc::{BlockedReason, PROCESSES, ProcessState};
5use crate::tests::helpers::alloc_endpoint_cap;
6use lancer_core::object_layout::EndpointObject;
7
8crate::kernel_test!(
9 fn send_blocks_when_no_receiver() {
10 let (id, generation, cap) = alloc_endpoint_cap();
11 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
12 let mut ptable = PROCESSES.lock();
13
14 let created = ptable.allocate(&mut allocator).expect("alloc");
15 ptable.start(created).expect("start");
16 let pid = created.pid();
17 ptable.simulate_dispatch(pid);
18
19 ptable.exec_mut(pid).unwrap().ipc_message = IpcMessage::from_regs([1, 2, 3, 4, 5, 6]);
20 let result = endpoint::do_send(&cap, pid, &mut ptable);
21 match result {
22 Ok(IpcOutcome::Blocked) => {
23 assert!(ptable[pid].state() == ProcessState::Blocked);
24 assert!(matches!(
25 ptable[pid].blocked_reason(),
26 Some(BlockedReason::Sending(eid, _)) if eid == id
27 ));
28 }
29 _ => panic!("expected Blocked when no receiver"),
30 }
31
32 ptable.destroy(pid, &mut allocator);
33 let _ = POOL.lock().dec_ref_phys(id, generation);
34 }
35);
36
37crate::kernel_test!(
38 fn multiple_senders_fifo_order() {
39 let (id, generation, cap) = alloc_endpoint_cap();
40 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
41 let mut ptable = PROCESSES.lock();
42
43 let a_created = ptable.allocate(&mut allocator).expect("alloc A");
44 let b_created = ptable.allocate(&mut allocator).expect("alloc B");
45 let recv_created = ptable.allocate(&mut allocator).expect("alloc recv");
46 ptable.start(a_created).expect("start A");
47 ptable.start(b_created).expect("start B");
48 ptable.start(recv_created).expect("start recv");
49 let a_pid = a_created.pid();
50 let b_pid = b_created.pid();
51 let recv_pid = recv_created.pid();
52
53 ptable.exec_mut(a_pid).unwrap().ipc_message =
54 IpcMessage::from_regs([0xAAAA, 0, 0, 0, 0, 0]);
55 ptable.simulate_dispatch(a_pid);
56 let _ = endpoint::do_send(&cap, a_pid, &mut ptable);
57
58 ptable.exec_mut(b_pid).unwrap().ipc_message =
59 IpcMessage::from_regs([0xBBBB, 0, 0, 0, 0, 0]);
60 ptable.simulate_dispatch(b_pid);
61 let _ = endpoint::do_send(&cap, b_pid, &mut ptable);
62
63 let result = endpoint::do_recv(&cap, recv_pid, &mut ptable);
64 match result {
65 Ok(IpcOutcome::Done(sender)) => {
66 assert!(sender == a_pid, "first recv should get sender A (FIFO)");
67 }
68 _ => panic!("expected Done from recv"),
69 }
70
71 let result2 = endpoint::do_recv(&cap, recv_pid, &mut ptable);
72 match result2 {
73 Ok(IpcOutcome::Done(sender)) => {
74 assert!(sender == b_pid, "second recv should get sender B (FIFO)");
75 }
76 _ => panic!("expected Done from second recv"),
77 }
78
79 ptable.destroy(a_pid, &mut allocator);
80 ptable.destroy(b_pid, &mut allocator);
81 ptable.destroy(recv_pid, &mut allocator);
82 let _ = POOL.lock().dec_ref_phys(id, generation);
83 }
84);
85
86crate::kernel_test!(
87 fn recv_blocks_when_no_sender() {
88 let (id, generation, cap) = alloc_endpoint_cap();
89 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
90 let mut ptable = PROCESSES.lock();
91
92 let created = ptable.allocate(&mut allocator).expect("alloc");
93 ptable.start(created).expect("start");
94 let pid = created.pid();
95 ptable.simulate_dispatch(pid);
96
97 let result = endpoint::do_recv(&cap, pid, &mut ptable);
98 match result {
99 Ok(IpcOutcome::Blocked) => {
100 assert!(ptable[pid].state() == ProcessState::Blocked);
101 assert!(matches!(
102 ptable[pid].blocked_reason(),
103 Some(BlockedReason::Receiving(eid, _)) if eid == id
104 ));
105 }
106 _ => panic!("expected Blocked when no sender"),
107 }
108
109 ptable.destroy(pid, &mut allocator);
110 let _ = POOL.lock().dec_ref_phys(id, generation);
111 }
112);
113
114crate::kernel_test!(
115 fn call_blocks_caller() {
116 let (id, generation, cap) = alloc_endpoint_cap();
117 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
118 let mut ptable = PROCESSES.lock();
119
120 let created = ptable.allocate(&mut allocator).expect("alloc");
121 ptable.start(created).expect("start");
122 let pid = created.pid();
123 ptable.simulate_dispatch(pid);
124
125 ptable.exec_mut(pid).unwrap().ipc_message = IpcMessage::from_regs([0xCA11, 0, 0, 0, 0, 0]);
126 let result = endpoint::do_call(&cap, pid, &mut ptable);
127 match result {
128 Ok(AlwaysBlocked) => {
129 assert!(ptable[pid].state() == ProcessState::Blocked);
130 assert!(matches!(
131 ptable[pid].blocked_reason(),
132 Some(BlockedReason::Calling(eid, _)) if eid == id
133 ));
134 }
135 _ => panic!("expected Blocked from call with no receiver"),
136 }
137
138 ptable.destroy(pid, &mut allocator);
139 let _ = POOL.lock().dec_ref_phys(id, generation);
140 }
141);
142
143crate::kernel_test!(
144 fn endpoint_holder_set_on_recv() {
145 let (id, generation, cap) = alloc_endpoint_cap();
146 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
147 let mut ptable = PROCESSES.lock();
148
149 let sender_created = ptable.allocate(&mut allocator).expect("alloc sender");
150 let recv_created = ptable.allocate(&mut allocator).expect("alloc recv");
151 ptable.start(sender_created).expect("start sender");
152 ptable.start(recv_created).expect("start recv");
153 let sender_pid = sender_created.pid();
154 let recv_pid = recv_created.pid();
155
156 ptable.exec_mut(sender_pid).unwrap().ipc_message =
157 IpcMessage::from_regs([0, 0, 0, 0, 0, 0]);
158 ptable.simulate_dispatch(sender_pid);
159 let _ = endpoint::do_send(&cap, sender_pid, &mut ptable);
160
161 let _ = endpoint::do_recv(&cap, recv_pid, &mut ptable);
162
163 let pool = POOL.lock();
164 let ep = pool.read_as::<EndpointObject>(id, generation).unwrap();
165 assert!(
166 endpoint::load_holder(ep) == Some(recv_pid),
167 "endpoint holder should be set to receiver after do_recv"
168 );
169 drop(pool);
170
171 ptable.destroy(sender_pid, &mut allocator);
172 ptable.destroy(recv_pid, &mut allocator);
173 let _ = POOL.lock().dec_ref_phys(id, generation);
174 }
175);
176
177crate::kernel_test!(
178 fn dequeue_genuine_receiver_skips_callers() {
179 let (id, generation, cap) = alloc_endpoint_cap();
180 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
181 let mut ptable = PROCESSES.lock();
182
183 let caller_created = ptable.allocate(&mut allocator).expect("alloc caller");
184 let recv_created = ptable.allocate(&mut allocator).expect("alloc recv");
185 let sender_created = ptable.allocate(&mut allocator).expect("alloc sender");
186 ptable.start(caller_created).expect("start caller");
187 ptable.start(recv_created).expect("start recv");
188 ptable.start(sender_created).expect("start sender");
189 let caller_pid = caller_created.pid();
190 let recv_pid = recv_created.pid();
191 let sender_pid = sender_created.pid();
192
193 ptable.simulate_dispatch(recv_pid);
194 let blocked_recv = ptable[recv_pid]
195 .block_on(BlockedReason::Receiving(id, generation))
196 .expect("block recv");
197
198 {
199 let mut pool = POOL.lock();
200 let ep = pool.write_as::<EndpointObject>(id, generation).unwrap();
201 let mut receivers = endpoint::load_receivers(ep);
202 endpoint::enqueue(&mut receivers, blocked_recv, &mut ptable).expect("enqueue recv");
203 let ep = pool.write_as::<EndpointObject>(id, generation).unwrap();
204 endpoint::store_receivers(ep, &receivers);
205 }
206
207 ptable.exec_mut(caller_pid).unwrap().ipc_message =
208 IpcMessage::from_regs([0xCA11, 0, 0, 0, 0, 0]);
209 ptable.simulate_dispatch(caller_pid);
210 let result = endpoint::do_call(&cap, caller_pid, &mut ptable);
211 assert!(matches!(result, Ok(AlwaysBlocked)));
212
213 assert!(
214 ptable[recv_pid].state() == ProcessState::Ready,
215 "genuine receiver should be unblocked by call"
216 );
217
218 ptable.exec_mut(sender_pid).unwrap().ipc_message =
219 IpcMessage::from_regs([0x5E4D, 0, 0, 0, 0, 0]);
220 ptable.simulate_dispatch(sender_pid);
221 let send_result = endpoint::do_send(&cap, sender_pid, &mut ptable);
222 assert!(
223 matches!(send_result, Ok(IpcOutcome::Blocked)),
224 "send should block because only caller (not genuine recv) is in queue"
225 );
226
227 ptable.destroy(caller_pid, &mut allocator);
228 ptable.destroy(recv_pid, &mut allocator);
229 ptable.destroy(sender_pid, &mut allocator);
230 let _ = POOL.lock().dec_ref_phys(id, generation);
231 }
232);
233
234crate::kernel_test!(
235 fn send_delivers_all_six_registers() {
236 let (id, generation, cap) = alloc_endpoint_cap();
237 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
238 let mut ptable = PROCESSES.lock();
239
240 let sender_created = ptable.allocate(&mut allocator).expect("alloc sender");
241 let recv_created = ptable.allocate(&mut allocator).expect("alloc recv");
242 ptable.start(sender_created).expect("start sender");
243 ptable.start(recv_created).expect("start recv");
244 let sender_pid = sender_created.pid();
245 let recv_pid = recv_created.pid();
246
247 let regs = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
248 ptable.exec_mut(sender_pid).unwrap().ipc_message = IpcMessage::from_regs(regs);
249 ptable.simulate_dispatch(sender_pid);
250 let _ = endpoint::do_send(&cap, sender_pid, &mut ptable);
251
252 let result = endpoint::do_recv(&cap, recv_pid, &mut ptable);
253 match result {
254 Ok(IpcOutcome::Done(sender)) => assert!(sender == sender_pid),
255 _ => panic!("expected Done from recv"),
256 }
257
258 let recv_msg = ptable.exec(recv_pid).unwrap().ipc_message;
259 let mut ctx = CpuContext::zero();
260 message::inject_into_context(&mut ctx, &recv_msg);
261 ctx.rax = sender_pid.raw() as u64;
262
263 assert!(ctx.rsi == 0x11, "reg[0] mismatch");
264 assert!(ctx.rdx == 0x22, "reg[1] mismatch");
265 assert!(ctx.r10 == 0x33, "reg[2] mismatch");
266 assert!(ctx.r8 == 0x44, "reg[3] mismatch");
267 assert!(ctx.r9 == 0x55, "reg[4] mismatch");
268 assert!(ctx.r12 == 0x66, "reg[5] mismatch");
269
270 ptable.destroy(sender_pid, &mut allocator);
271 ptable.destroy(recv_pid, &mut allocator);
272 let _ = POOL.lock().dec_ref_phys(id, generation);
273 }
274);
275
276crate::kernel_test!(
277 fn try_recv_returns_would_block_when_empty() {
278 let (id, generation, cap) = alloc_endpoint_cap();
279 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
280 let mut ptable = PROCESSES.lock();
281
282 let created = ptable.allocate(&mut allocator).expect("alloc");
283 ptable.start(created).expect("start");
284 let pid = created.pid();
285 ptable.simulate_dispatch(pid);
286
287 let result = endpoint::do_try_recv(&cap, pid, &mut ptable);
288 assert!(
289 matches!(result, Err(crate::error::KernelError::WouldBlock)),
290 "try_recv with no senders should return WouldBlock"
291 );
292 assert!(
293 ptable[pid].state() == ProcessState::Running,
294 "process should remain Running after WouldBlock"
295 );
296
297 ptable.destroy(pid, &mut allocator);
298 let _ = POOL.lock().dec_ref_phys(id, generation);
299 }
300);
301
302crate::kernel_test!(
303 fn try_recv_delivers_when_sender_waiting() {
304 let (id, generation, cap) = alloc_endpoint_cap();
305 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
306 let mut ptable = PROCESSES.lock();
307
308 let sender_created = ptable.allocate(&mut allocator).expect("alloc sender");
309 let recv_created = ptable.allocate(&mut allocator).expect("alloc recv");
310 ptable.start(sender_created).expect("start sender");
311 ptable.start(recv_created).expect("start recv");
312 let sender_pid = sender_created.pid();
313 let recv_pid = recv_created.pid();
314
315 ptable.exec_mut(sender_pid).unwrap().ipc_message =
316 IpcMessage::from_regs([0xABCD, 0, 0, 0, 0, 0]);
317 ptable.simulate_dispatch(sender_pid);
318 let _ = endpoint::do_send(&cap, sender_pid, &mut ptable);
319
320 assert!(
321 ptable[sender_pid].state() == ProcessState::Blocked,
322 "sender should be blocked after send with no receiver"
323 );
324
325 let result = endpoint::do_try_recv(&cap, recv_pid, &mut ptable);
326 match result {
327 Ok(IpcOutcome::Done(from)) => {
328 assert!(from == sender_pid, "should receive from sender");
329 }
330 _ => panic!("expected Done from try_recv"),
331 }
332
333 assert!(
334 ptable[sender_pid].state() != ProcessState::Blocked,
335 "sender should be unblocked after try_recv delivers"
336 );
337
338 let recv_msg = ptable.exec(recv_pid).unwrap().ipc_message;
339 assert!(
340 recv_msg.regs[0] == 0xABCD,
341 "message content should be delivered"
342 );
343
344 ptable.destroy(sender_pid, &mut allocator);
345 ptable.destroy(recv_pid, &mut allocator);
346 let _ = POOL.lock().dec_ref_phys(id, generation);
347 }
348);
349
350crate::kernel_test!(
351 fn recv_caller_reenqueue_sets_reply_target() {
352 let (ep_id, ep_gen, cap) = alloc_endpoint_cap();
353 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
354 let mut ptable = PROCESSES.lock();
355
356 let caller_created = ptable.allocate(&mut allocator).expect("alloc caller");
357 let server_created = ptable.allocate(&mut allocator).expect("alloc server");
358 ptable.start(caller_created).expect("start caller");
359 ptable.start(server_created).expect("start server");
360 let caller_pid = caller_created.pid();
361 let server_pid = server_created.pid();
362
363 ptable.simulate_dispatch(caller_pid);
364 ptable.exec_mut(caller_pid).unwrap().ipc_message =
365 IpcMessage::from_regs([0xCA, 0, 0, 0, 0, 0]);
366 let blocked_caller = ptable[caller_pid]
367 .block_on(BlockedReason::Calling(ep_id, ep_gen))
368 .expect("block caller");
369
370 {
371 let mut pool = POOL.lock();
372 let ep = pool
373 .write_as::<EndpointObject>(ep_id, ep_gen)
374 .expect("get ep");
375 let mut senders = endpoint::load_senders(ep);
376 endpoint::enqueue(&mut senders, blocked_caller, &mut ptable)
377 .expect("enqueue caller as sender");
378 let ep = pool
379 .write_as::<EndpointObject>(ep_id, ep_gen)
380 .expect("get ep");
381 endpoint::store_senders(ep, &senders);
382 }
383
384 ptable.simulate_dispatch(server_pid);
385
386 let result = endpoint::do_recv(&cap, server_pid, &mut ptable);
387 assert!(
388 matches!(result, Ok(IpcOutcome::Done(_))),
389 "server should receive caller's message"
390 );
391
392 assert!(
393 ptable.exec(server_pid).unwrap().reply_target == Some(caller_pid),
394 "server should have reply_target pointing to caller"
395 );
396
397 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen);
398 ptable.destroy(caller_pid, &mut allocator);
399 ptable.destroy(server_pid, &mut allocator);
400 }
401);