Nothing to see here, move along
at main 265 lines 8.2 kB view raw
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}