strat9_kernel/syscall/
chan.rs1use super::error::SyscallError;
7use crate::{
8 capability::{CapId, ResourceType},
9 ipc::{
10 channel::{self, ChanId},
11 message::IpcMessage,
12 },
13 memory::{UserSliceRead, UserSliceWrite},
14 process::current_task_clone,
15};
16
17const MSG_SIZE: usize = core::mem::size_of::<IpcMessage>();
18
19const _: () = assert!(
22 MSG_SIZE == 256,
23 "IpcMessage size changed : update userspace ABI"
24);
25
26pub fn sys_chan_create(capacity: u64) -> Result<u64, SyscallError> {
28 let cap = capacity.clamp(1, 1024) as usize;
29
30 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
31
32 task.process
34 .ipc_quota
35 .try_reserve(cap)
36 .map_err(|_| SyscallError::OutOfMemory)?;
37
38 let chan_id = match channel::create_channel(cap) {
39 id => id,
40 };
41
42 let caps = unsafe { &mut *task.process.capabilities.get() };
43 let cap_id = crate::capability::CapId::new();
44 let chan_cap = crate::capability::Capability {
45 id: cap_id,
46 permissions: crate::capability::CapPermissions {
47 read: true,
48 write: true,
49 execute: false,
50 grant: true,
51 revoke: false,
52 },
53 resource_type: ResourceType::Channel,
54 resource: chan_id.as_u64() as usize,
55 badge: cap_id.as_u64(),
59 };
60 let handle = caps.insert(chan_cap);
61
62 log::debug!(
63 "syscall: CHAN_CREATE(cap={}) => chan={} handle={}",
64 cap,
65 chan_id,
66 handle.as_u64()
67 );
68 Ok(handle.as_u64())
69}
70
71pub fn sys_chan_send(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
79 crate::silo::enforce_cap_for_current_task(handle)?;
80
81 let user_slice = UserSliceRead::new(msg_ptr, MSG_SIZE).map_err(SyscallError::from)?;
82 let mut msg = IpcMessage::new(0);
83 let n = user_slice.copy_to(unsafe {
84 core::slice::from_raw_parts_mut(&mut msg as *mut IpcMessage as *mut u8, MSG_SIZE)
85 });
86 if n != MSG_SIZE {
87 return Err(SyscallError::Fault);
88 }
89
90 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
91 let caps = unsafe { &*task.process.capabilities.get() };
92 let cap = caps
93 .get(CapId::from_raw(handle))
94 .ok_or(SyscallError::BadHandle)?;
95 if cap.resource_type != ResourceType::Channel || !cap.permissions.write {
96 return Err(SyscallError::PermissionDenied);
97 }
98 let chan_id = ChanId::from_u64(cap.resource as u64);
99
100 msg.sender = cap.badge;
104
105 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
106 chan.send(msg).map_err(SyscallError::from)?;
107
108 Ok(0)
109}
110
111pub fn sys_chan_recv(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
114 crate::silo::enforce_cap_for_current_task(handle)?;
115
116 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
117 let caps = unsafe { &*task.process.capabilities.get() };
118 let cap = caps
119 .get(CapId::from_raw(handle))
120 .ok_or(SyscallError::BadHandle)?;
121 if cap.resource_type != ResourceType::Channel || !cap.permissions.read {
122 return Err(SyscallError::PermissionDenied);
123 }
124 let chan_id = ChanId::from_u64(cap.resource as u64);
125
126 let user_slice = UserSliceWrite::new(msg_ptr, MSG_SIZE).map_err(SyscallError::from)?;
129
130 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
131 let msg = chan.recv().map_err(SyscallError::from)?;
132
133 let n = user_slice.copy_from(unsafe {
134 core::slice::from_raw_parts(&msg as *const IpcMessage as *const u8, MSG_SIZE)
135 });
136 if n != MSG_SIZE {
137 return Err(SyscallError::Fault);
140 }
141
142 Ok(0)
143}
144
145pub fn sys_chan_try_recv(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
150 crate::silo::enforce_cap_for_current_task(handle)?;
151
152 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
153 let caps = unsafe { &*task.process.capabilities.get() };
154 let cap = caps
155 .get(CapId::from_raw(handle))
156 .ok_or(SyscallError::BadHandle)?;
157 if cap.resource_type != ResourceType::Channel || !cap.permissions.read {
158 return Err(SyscallError::PermissionDenied);
159 }
160 let chan_id = ChanId::from_u64(cap.resource as u64);
161
162 let user_slice = UserSliceWrite::new(msg_ptr, MSG_SIZE).map_err(SyscallError::from)?;
163
164 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
165 match chan.try_recv() {
166 Ok(msg) => {
167 let n = user_slice.copy_from(unsafe {
168 core::slice::from_raw_parts(&msg as *const IpcMessage as *const u8, MSG_SIZE)
169 });
170 if n != MSG_SIZE {
171 return Err(SyscallError::Fault);
172 }
173 Ok(0)
174 }
175 Err(e) => Err(SyscallError::from(e)),
176 }
177}
178
179pub fn sys_chan_close(handle: u64) -> Result<u64, SyscallError> {
182 crate::silo::enforce_cap_for_current_task(handle)?;
183
184 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
185 let caps = unsafe { &mut *task.process.capabilities.get() };
186 let cap = caps
187 .get(CapId::from_raw(handle))
188 .ok_or(SyscallError::BadHandle)?;
189 if cap.resource_type != ResourceType::Channel {
190 return Err(SyscallError::BadHandle);
191 }
192 let chan_id = ChanId::from_u64(cap.resource as u64);
193 let has_revoke = cap.permissions.revoke;
194
195 let capacity = channel::get_channel(chan_id)
197 .map(|c| c.capacity())
198 .unwrap_or(0);
199
200 let cap = caps
201 .remove(CapId::from_raw(handle))
202 .ok_or(SyscallError::BadHandle)?;
203 debug_assert_eq!(cap.resource_type, ResourceType::Channel);
204
205 task.process.ipc_quota.release(capacity);
207
208 if has_revoke {
209 crate::capability::release_capability(&cap, Some(task.id));
212 } else {
213 crate::capability::get_capability_manager().revoke_capability(cap.id);
217 }
218
219 log::debug!("syscall: CHAN_CLOSE(handle={}) => chan={}", handle, chan_id);
220 Ok(0)
221}