Nothing to see here, move along
1use crate::cap::object::ObjectTag;
2use crate::cap::pool::POOL;
3use crate::cap::table::{CapRef, Rights};
4use crate::ipc::{AlwaysBlocked, IpcOutcome, endpoint, message};
5use crate::proc::context::{CpuContext, IpcMessage};
6use crate::proc::{BlockedReason, PROCESSES, ProcessState};
7use lancer_core::object_layout::EndpointObject;
8
9crate::kernel_test!(
10 fn recv_fast_path_delivers_message() {
11 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
12 let mut ptable = PROCESSES.lock();
13
14 let sender_created = ptable.allocate(&mut allocator).expect("alloc sender");
15 let recv_created = ptable.allocate(&mut allocator).expect("alloc receiver");
16 ptable.start(sender_created).expect("start sender");
17 ptable.start(recv_created).expect("start receiver");
18 let sender_pid = sender_created.pid();
19 let recv_pid = recv_created.pid();
20
21 let (ep_id, ep_gen) =
22 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc endpoint");
23
24 let msg = IpcMessage::from_regs([
25 0xCAFE_0001,
26 0xCAFE_0002,
27 0xCAFE_0003,
28 0xCAFE_0004,
29 0xCAFE_0005,
30 0xCAFE_0006,
31 ]);
32 ptable.exec_mut(sender_pid).unwrap().ipc_message = msg;
33
34 ptable.simulate_dispatch(sender_pid);
35 let blocked = ptable[sender_pid]
36 .block_on(BlockedReason::Sending(ep_id, ep_gen))
37 .expect("block sender");
38
39 {
40 let mut pool = POOL.lock();
41 let ep = pool
42 .write_as::<EndpointObject>(ep_id, ep_gen)
43 .expect("get ep");
44 let mut senders = endpoint::load_senders(ep);
45 endpoint::enqueue(&mut senders, blocked, &mut ptable).expect("enqueue sender");
46 let ep = pool
47 .write_as::<EndpointObject>(ep_id, ep_gen)
48 .expect("get ep");
49 endpoint::store_senders(ep, &senders);
50 }
51
52 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
53 let result = endpoint::do_recv(&cap, recv_pid, &mut ptable);
54
55 let returned_sender = match result {
56 Ok(IpcOutcome::Done(pid)) => pid,
57 _ => panic!("expected Done from do_recv fast path"),
58 };
59 assert!(
60 returned_sender == sender_pid,
61 "do_recv should return the sender's pid"
62 );
63
64 let recv_msg = ptable.exec(recv_pid).unwrap().ipc_message;
65
66 let mut ctx = CpuContext::zero();
67 message::inject_into_context(&mut ctx, &recv_msg);
68 ctx.rax = returned_sender.raw() as u64;
69
70 assert!(
71 ctx.rsi == 0xCAFE_0001,
72 "msg[0] must be delivered to ctx.rsi"
73 );
74 assert!(
75 ctx.rdx == 0xCAFE_0002,
76 "msg[1] must be delivered to ctx.rdx"
77 );
78 assert!(
79 ctx.r10 == 0xCAFE_0003,
80 "msg[2] must be delivered to ctx.r10"
81 );
82 assert!(ctx.r8 == 0xCAFE_0004, "msg[3] must be delivered to ctx.r8");
83 assert!(ctx.r9 == 0xCAFE_0005, "msg[4] must be delivered to ctx.r9");
84 assert!(
85 ctx.r12 == 0xCAFE_0006,
86 "msg[5] must be delivered to ctx.r12"
87 );
88
89 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen);
90 ptable.destroy(sender_pid, &mut allocator);
91 ptable.destroy(recv_pid, &mut allocator);
92 }
93);
94
95crate::kernel_test!(
96 fn call_fast_path_sets_reply_target() {
97 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
98 let mut ptable = PROCESSES.lock();
99
100 let caller_created = ptable.allocate(&mut allocator).expect("alloc caller");
101 let recv_created = ptable.allocate(&mut allocator).expect("alloc receiver");
102 ptable.start(caller_created).expect("start caller");
103 ptable.start(recv_created).expect("start receiver");
104 let caller_pid = caller_created.pid();
105 let recv_pid = recv_created.pid();
106
107 let (ep_id, ep_gen) =
108 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc endpoint");
109
110 ptable.simulate_dispatch(recv_pid);
111 let blocked_recv = ptable[recv_pid]
112 .block_on(BlockedReason::Receiving(ep_id, ep_gen))
113 .expect("block receiver");
114
115 {
116 let mut pool = POOL.lock();
117 let ep = pool
118 .write_as::<EndpointObject>(ep_id, ep_gen)
119 .expect("get ep");
120 let mut receivers = endpoint::load_receivers(ep);
121 endpoint::enqueue(&mut receivers, blocked_recv, &mut ptable).expect("enqueue receiver");
122 let ep = pool
123 .write_as::<EndpointObject>(ep_id, ep_gen)
124 .expect("get ep");
125 endpoint::store_receivers(ep, &receivers);
126 }
127
128 let msg = IpcMessage::from_regs([0x1234, 0x5678, 0, 0, 0, 0]);
129 ptable.exec_mut(caller_pid).unwrap().ipc_message = msg;
130 ptable.simulate_dispatch(caller_pid);
131
132 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
133 let result = endpoint::do_call(&cap, caller_pid, &mut ptable);
134
135 match result {
136 Ok(AlwaysBlocked) => {}
137 _ => panic!("expected Blocked from do_call fast path"),
138 }
139
140 assert!(
141 ptable[recv_pid].state() == ProcessState::Ready,
142 "receiver should be unblocked after do_call fast path"
143 );
144
145 assert!(
146 ptable.exec(recv_pid).unwrap().saved_context.rax == caller_pid.raw() as u64,
147 "receiver's rax should hold the caller's pid"
148 );
149
150 assert!(
151 ptable.exec(recv_pid).unwrap().reply_target == Some(caller_pid),
152 "do_call fast path must set reply_target so receiver can reply"
153 );
154
155 assert!(
156 ptable[caller_pid].state() == ProcessState::Blocked,
157 "caller should be blocked waiting for reply"
158 );
159
160 assert!(
161 matches!(
162 ptable[caller_pid].blocked_reason(),
163 Some(BlockedReason::Calling(id, _)) if id == ep_id
164 ),
165 "caller should be blocked as Calling on the endpoint"
166 );
167
168 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen);
169 ptable.destroy(caller_pid, &mut allocator);
170 ptable.destroy(recv_pid, &mut allocator);
171 }
172);
173
174crate::kernel_test!(
175 fn send_skips_call_waiters() {
176 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
177 let mut ptable = PROCESSES.lock();
178
179 let server_created = ptable.allocate(&mut allocator).expect("alloc server");
180 let client_a_created = ptable.allocate(&mut allocator).expect("alloc client_a");
181 let client_b_created = ptable.allocate(&mut allocator).expect("alloc client_b");
182 ptable.start(server_created).expect("start server");
183 ptable.start(client_a_created).expect("start client_a");
184 ptable.start(client_b_created).expect("start client_b");
185 let server_pid = server_created.pid();
186 let client_a_pid = client_a_created.pid();
187 let client_b_pid = client_b_created.pid();
188
189 let (ep_id, ep_gen) =
190 crate::tests::helpers::alloc_endpoint(&mut POOL.lock()).expect("alloc endpoint");
191
192 ptable.simulate_dispatch(server_pid);
193 let blocked_server = ptable[server_pid]
194 .block_on(BlockedReason::Receiving(ep_id, ep_gen))
195 .expect("block server");
196
197 {
198 let mut pool = POOL.lock();
199 let ep = pool
200 .write_as::<EndpointObject>(ep_id, ep_gen)
201 .expect("get ep");
202 let mut receivers = endpoint::load_receivers(ep);
203 endpoint::enqueue(&mut receivers, blocked_server, &mut ptable).expect("enqueue server");
204 let ep = pool
205 .write_as::<EndpointObject>(ep_id, ep_gen)
206 .expect("get ep");
207 endpoint::store_receivers(ep, &receivers);
208 }
209
210 let msg_a = IpcMessage::from_regs([0xAAAA, 0, 0, 0, 0, 0]);
211 ptable.exec_mut(client_a_pid).unwrap().ipc_message = msg_a;
212 ptable.simulate_dispatch(client_a_pid);
213
214 let cap = CapRef::new(ObjectTag::Endpoint, ep_id, Rights::ALL, ep_gen);
215 let call_result = endpoint::do_call(&cap, client_a_pid, &mut ptable);
216 match call_result {
217 Ok(AlwaysBlocked) => {}
218 _ => panic!("expected Blocked from client_a do_call"),
219 }
220
221 assert!(
222 ptable[server_pid].state() == ProcessState::Ready,
223 "server should be Ready after receiving call"
224 );
225 assert!(
226 ptable[client_a_pid].state() == ProcessState::Blocked,
227 "client_a should be Blocked waiting for reply"
228 );
229
230 let msg_b = IpcMessage::from_regs([0xBBBB, 0, 0, 0, 0, 0]);
231 ptable.exec_mut(client_b_pid).unwrap().ipc_message = msg_b;
232 ptable.simulate_dispatch(client_b_pid);
233
234 let send_result = endpoint::do_send(&cap, client_b_pid, &mut ptable);
235 match send_result {
236 Ok(IpcOutcome::Blocked) => {}
237 _ => panic!("expected Blocked from client_b do_send (no genuine receiver)"),
238 }
239
240 assert!(
241 ptable[client_a_pid].state() == ProcessState::Blocked,
242 "client_a must still be blocked. send must not wake call-waiters"
243 );
244 assert!(
245 matches!(
246 ptable[client_a_pid].blocked_reason(),
247 Some(BlockedReason::Calling(id, _)) if id == ep_id
248 ),
249 "client_a should still have Calling blocked reason"
250 );
251
252 assert!(
253 ptable[client_b_pid].state() == ProcessState::Blocked,
254 "client_b should be blocked as sender (no genuine receiver available)"
255 );
256 assert!(
257 matches!(
258 ptable[client_b_pid].blocked_reason(),
259 Some(BlockedReason::Sending(id, _)) if id == ep_id
260 ),
261 "client_b should have Sending blocked reason"
262 );
263
264 let _ = POOL.lock().dec_ref_phys(ep_id, ep_gen);
265 ptable.destroy(server_pid, &mut allocator);
266 ptable.destroy(client_a_pid, &mut allocator);
267 ptable.destroy(client_b_pid, &mut allocator);
268 }
269);