Nothing to see here, move along
1use crate::cap::cnode;
2use crate::cap::object::ObjectTag;
3use crate::cap::pool::POOL;
4use crate::cap::table::Rights;
5use crate::ipc::{AlwaysBlocked, IpcOutcome, endpoint, message};
6use crate::proc::BlockedReason;
7use crate::proc::context::CpuContext;
8use crate::proc::{PROCESSES, ProcessManager, ProcessState};
9use crate::syscall::{SyscallResult, try_syscall};
10use crate::types::Pid;
11use lancer_core::object_layout::{EndpointObject, NotificationObject};
12
13fn drain_bound_notification(pid: Pid, ptable: &ProcessManager) -> Option<u64> {
14 let (notif_id, notif_gen) = ptable.get(pid)?.bound_notification()?;
15 let mut pool = POOL.lock();
16 pool.write_as::<NotificationObject>(notif_id, notif_gen)
17 .ok()
18 .and_then(|notif| {
19 (notif.word != 0).then(|| {
20 let w = notif.word;
21 notif.word = 0;
22 w
23 })
24 })
25}
26
27pub fn sys_send(ctx: &mut CpuContext) {
28 let cap_addr = ctx.rdi;
29 let pid = crate::arch::syscall::current_pid();
30
31 let msg = message::extract_from_context(ctx);
32
33 let mut ptable = PROCESSES.lock();
34 let cap = {
35 let pool = POOL.lock_after(&ptable);
36 try_syscall!(
37 ctx,
38 cnode::resolve_caller_validate(
39 pid,
40 cap_addr,
41 ObjectTag::Endpoint,
42 Rights::WRITE,
43 &ptable,
44 &pool,
45 )
46 )
47 };
48
49 ptable.exec_mut(pid).unwrap().ipc_message = msg;
50
51 match endpoint::do_send(&cap, pid, &mut ptable) {
52 Ok(IpcOutcome::Done(())) => ctx.rax = SyscallResult::ok().raw(),
53 Ok(IpcOutcome::Blocked) => {
54 ctx.rax = SyscallResult::ok().raw();
55 drop(ptable);
56 crate::sched::schedule(ctx);
57 }
58 Err(e) => ctx.rax = SyscallResult::error(e).raw(),
59 }
60}
61
62pub fn sys_recv(ctx: &mut CpuContext) {
63 let cap_addr = ctx.rdi;
64 let pid = crate::arch::syscall::current_pid();
65
66 let mut ptable = PROCESSES.lock();
67 let cap = {
68 let pool = POOL.lock_after(&ptable);
69 try_syscall!(
70 ctx,
71 cnode::resolve_caller_validate(
72 pid,
73 cap_addr,
74 ObjectTag::Endpoint,
75 Rights::READ,
76 &ptable,
77 &pool,
78 )
79 )
80 };
81
82 if let Some(word) = drain_bound_notification(pid, &ptable) {
83 ctx.rax = crate::ipc::notification::BOUND_NOTIFICATION_BADGE;
84 ctx.rdx = word;
85 return;
86 }
87
88 match endpoint::do_recv(&cap, pid, &mut ptable) {
89 Ok(IpcOutcome::Done(sender_pid)) => {
90 let msg = ptable.exec(pid).unwrap().ipc_message;
91 message::inject_into_context(ctx, &msg);
92 ctx.rax = SyscallResult::success(sender_pid.raw() as u64).raw();
93 }
94 Ok(IpcOutcome::Blocked) => {
95 ctx.rax = SyscallResult::ok().raw();
96 drop(ptable);
97 crate::sched::schedule(ctx);
98 }
99 Err(e) => ctx.rax = SyscallResult::error(e).raw(),
100 }
101}
102
103pub fn sys_nb_recv(ctx: &mut CpuContext) {
104 let cap_addr = ctx.rdi;
105 let pid = crate::arch::syscall::current_pid();
106
107 let mut ptable = PROCESSES.lock();
108 let cap = {
109 let pool = POOL.lock_after(&ptable);
110 try_syscall!(
111 ctx,
112 cnode::resolve_caller_validate(
113 pid,
114 cap_addr,
115 ObjectTag::Endpoint,
116 Rights::READ,
117 &ptable,
118 &pool,
119 )
120 )
121 };
122
123 if let Some(word) = drain_bound_notification(pid, &ptable) {
124 ctx.rax = crate::ipc::notification::BOUND_NOTIFICATION_BADGE;
125 ctx.rdx = word;
126 return;
127 }
128
129 match endpoint::do_try_recv(&cap, pid, &mut ptable) {
130 Ok(IpcOutcome::Done(sender_pid)) => {
131 let msg = ptable.exec(pid).unwrap().ipc_message;
132 message::inject_into_context(ctx, &msg);
133 ctx.rax = SyscallResult::success(sender_pid.raw() as u64).raw();
134 }
135 Err(e) => ctx.rax = SyscallResult::error(e).raw(),
136 Ok(IpcOutcome::Blocked) => unreachable!(),
137 }
138}
139
140pub fn sys_call(ctx: &mut CpuContext) {
141 let cap_addr = ctx.rdi;
142 let pid = crate::arch::syscall::current_pid();
143
144 let msg = message::extract_from_context(ctx);
145
146 let mut ptable = PROCESSES.lock();
147 let cap = {
148 let pool = POOL.lock_after(&ptable);
149 let needs = Rights::READ | Rights::WRITE;
150 try_syscall!(
151 ctx,
152 cnode::resolve_caller_validate(
153 pid,
154 cap_addr,
155 ObjectTag::Endpoint,
156 needs,
157 &ptable,
158 &pool,
159 )
160 )
161 };
162
163 ptable.exec_mut(pid).unwrap().ipc_message = msg;
164
165 match endpoint::do_call(&cap, pid, &mut ptable) {
166 Ok(AlwaysBlocked) => {
167 ctx.rax = SyscallResult::ok().raw();
168 drop(ptable);
169 crate::sched::schedule(ctx);
170 }
171 Err(e) => ctx.rax = SyscallResult::error(e).raw(),
172 }
173}
174
175pub fn sys_reply_recv(ctx: &mut CpuContext) {
176 let cap_addr = ctx.rdi;
177 let reply_to_raw = try_syscall!(ctx, super::u32_from_reg(ctx.rsi));
178 let pid = crate::arch::syscall::current_pid();
179
180 let msg = message::extract_reply_from_context(ctx);
181
182 let mut ptable = PROCESSES.lock();
183
184 let cap = {
185 let pool = POOL.lock_after(&ptable);
186 let needs = Rights::READ | Rights::WRITE;
187 try_syscall!(
188 ctx,
189 cnode::resolve_caller_validate(
190 pid,
191 cap_addr,
192 ObjectTag::Endpoint,
193 needs,
194 &ptable,
195 &pool,
196 )
197 )
198 };
199
200 let reply_delivered = match Pid::try_new(reply_to_raw) {
201 Some(reply_pid) => {
202 let reply_target_ok = ptable.exec(pid).unwrap().reply_target == Some(reply_pid);
203 let target_sched = &ptable[reply_pid];
204 let is_call_target = reply_target_ok
205 && target_sched.state() == ProcessState::Blocked
206 && matches!(
207 target_sched.blocked_reason(),
208 Some(BlockedReason::Calling(id, _))
209 if id == cap.phys()
210 );
211 if is_call_target {
212 let proof = ptable[reply_pid].blocked_proof();
213 {
214 let mut pool = POOL.lock_after(&ptable);
215 if let Ok(ep) =
216 pool.write_as::<EndpointObject>(cap.phys(), cap.generation())
217 {
218 endpoint::remove_from_recv(ep, reply_pid, &mut ptable);
219 }
220 }
221 let full_msg = msg.into_full();
222 let exec_target = ptable.exec_mut(reply_pid).unwrap();
223 exec_target.ipc_message = full_msg;
224 message::inject_into_context(&mut exec_target.saved_context, &full_msg);
225 exec_target.saved_context.rax = SyscallResult::success(pid.raw() as u64).raw();
226 exec_target.seal_context();
227 let unblocked = ptable.unblock_and_enqueue(reply_pid, proof).is_ok();
228 if unblocked {
229 ptable.exec_mut(pid).unwrap().reply_target = None;
230 true
231 } else {
232 false
233 }
234 } else {
235 false
236 }
237 }
238 None => false,
239 };
240
241 ctx.rbx = if reply_delivered { 0 } else { 1 };
242
243 if let Some(word) = drain_bound_notification(pid, &ptable) {
244 ctx.rax = crate::ipc::notification::BOUND_NOTIFICATION_BADGE;
245 ctx.rdx = word;
246 return;
247 }
248
249 match endpoint::do_recv(&cap, pid, &mut ptable) {
250 Ok(IpcOutcome::Done(sender_pid)) => {
251 let msg = ptable.exec(pid).unwrap().ipc_message;
252 message::inject_into_context(ctx, &msg);
253 ctx.rax = SyscallResult::success(sender_pid.raw() as u64).raw();
254 }
255 Ok(IpcOutcome::Blocked) => {
256 ctx.rax = SyscallResult::ok().raw();
257 drop(ptable);
258 crate::sched::schedule(ctx);
259 }
260 Err(e) => ctx.rax = SyscallResult::error(e).raw(),
261 }
262}