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, ProcessState, ProcessManager};
9use crate::syscall::{SyscallResult, try_syscall};
10use crate::types::Pid;
11
12fn drain_bound_notification(pid: Pid, ptable: &ProcessManager) -> Option<u64> {
13 let (notif_id, notif_gen) = ptable.get(pid)?.bound_notification()?;
14 let mut pool = POOL.lock();
15 pool.get_mut(notif_id, notif_gen)
16 .and_then(|d| d.as_notification_mut())
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[pid].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[pid].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[pid].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[pid].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::u16_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[pid].reply_target == Some(reply_pid);
203 let target = &ptable[reply_pid];
204 let is_call_target = reply_target_ok
205 && target.state() == ProcessState::Blocked
206 && matches!(
207 target.blocked_reason(),
208 Some(BlockedReason::Calling(id, _))
209 if id == cap.object_id()
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) = pool
216 .get_mut(cap.object_id(), cap.generation())
217 .and_then(|d| d.as_endpoint_mut())
218 {
219 endpoint::remove_from_recv(ep, reply_pid, &mut ptable);
220 }
221 }
222 let full_msg = msg.into_full();
223 let unblocked = {
224 let target = &mut ptable[reply_pid];
225 target.ipc_message = full_msg;
226 message::inject_into_context(&mut target.saved_context, &full_msg);
227 target.saved_context.rax = SyscallResult::success(pid.raw() as u64).raw();
228 target.seal_context();
229 target.unblock(proof).is_ok()
230 };
231 if unblocked {
232 ptable[pid].reply_target = None;
233 true
234 } else {
235 false
236 }
237 } else {
238 false
239 }
240 }
241 None => false,
242 };
243
244 ctx.rbx = if reply_delivered { 0 } else { 1 };
245
246 if let Some(word) = drain_bound_notification(pid, &ptable) {
247 ctx.rax = crate::ipc::notification::BOUND_NOTIFICATION_BADGE;
248 ctx.rdx = word;
249 return;
250 }
251
252 match endpoint::do_recv(&cap, pid, &mut ptable) {
253 Ok(IpcOutcome::Done(sender_pid)) => {
254 let msg = ptable[pid].ipc_message;
255 message::inject_into_context(ctx, &msg);
256 ctx.rax = SyscallResult::success(sender_pid.raw() as u64).raw();
257 }
258 Ok(IpcOutcome::Blocked) => {
259 ctx.rax = SyscallResult::ok().raw();
260 drop(ptable);
261 crate::sched::schedule(ctx);
262 }
263 Err(e) => ctx.rax = SyscallResult::error(e).raw(),
264 }
265}