strat9_kernel/syscall/
chan.rs1use super::error::SyscallError;
7use crate::{
8 capability::{CapId, CapPermissions, 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
19pub fn sys_chan_create(capacity: u64) -> Result<u64, SyscallError> {
21 let cap = capacity.clamp(1, 1024) as usize;
22 let chan_id = channel::create_channel(cap);
23
24 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
25 let caps = unsafe { &mut *task.process.capabilities.get() };
26 let cap_id = caps.insert(crate::capability::Capability {
27 id: crate::capability::CapId::new(),
28 permissions: crate::capability::CapPermissions {
29 read: true,
30 write: true,
31 execute: false,
32 grant: true,
33 revoke: false,
34 },
35 resource_type: ResourceType::Channel,
36 resource: chan_id.as_u64() as usize,
37 });
38
39 log::debug!(
40 "syscall: CHAN_CREATE(cap={}) → chan={} handle={}",
41 cap,
42 chan_id,
43 cap_id.as_u64()
44 );
45 Ok(cap_id.as_u64())
46}
47
48pub fn sys_chan_send(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
50 crate::silo::enforce_cap_for_current_task(handle)?;
51
52 let user_slice = UserSliceRead::new(msg_ptr, MSG_SIZE).map_err(SyscallError::from)?;
53 let mut msg = IpcMessage::new(0);
54 let n = user_slice.copy_to(unsafe {
55 core::slice::from_raw_parts_mut(&mut msg as *mut IpcMessage as *mut u8, MSG_SIZE)
56 });
57 if n != MSG_SIZE {
58 return Err(SyscallError::Fault);
59 }
60
61 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
62 msg.sender = task.id.as_u64();
63
64 let caps = unsafe { &*task.process.capabilities.get() };
65 let cap = caps
66 .get(CapId::from_raw(handle))
67 .ok_or(SyscallError::BadHandle)?;
68 if cap.resource_type != ResourceType::Channel || !cap.permissions.write {
69 return Err(SyscallError::PermissionDenied);
70 }
71 let chan_id = ChanId::from_u64(cap.resource as u64);
72
73 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
74 chan.send(msg).map_err(SyscallError::from)?;
75
76 Ok(0)
77}
78
79pub fn sys_chan_recv(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
81 crate::silo::enforce_cap_for_current_task(handle)?;
82
83 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
84 let caps = unsafe { &*task.process.capabilities.get() };
85 let cap = caps
86 .get(CapId::from_raw(handle))
87 .ok_or(SyscallError::BadHandle)?;
88 if cap.resource_type != ResourceType::Channel || !cap.permissions.read {
89 return Err(SyscallError::PermissionDenied);
90 }
91 let chan_id = ChanId::from_u64(cap.resource as u64);
92
93 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
94 let msg = chan.recv().map_err(SyscallError::from)?;
95
96 let user_slice = UserSliceWrite::new(msg_ptr, MSG_SIZE).map_err(SyscallError::from)?;
97 let n = user_slice.copy_from(unsafe {
98 core::slice::from_raw_parts(&msg as *const IpcMessage as *const u8, MSG_SIZE)
99 });
100 if n != MSG_SIZE {
101 return Err(SyscallError::Fault);
102 }
103
104 Ok(0)
105}
106
107pub fn sys_chan_try_recv(handle: u64, msg_ptr: u64) -> Result<u64, SyscallError> {
109 crate::silo::enforce_cap_for_current_task(handle)?;
110
111 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
112 let caps = unsafe { &*task.process.capabilities.get() };
113 let cap = caps
114 .get(CapId::from_raw(handle))
115 .ok_or(SyscallError::BadHandle)?;
116 if cap.resource_type != ResourceType::Channel || !cap.permissions.read {
117 return Err(SyscallError::PermissionDenied);
118 }
119 let chan_id = ChanId::from_u64(cap.resource as u64);
120
121 let chan = channel::get_channel(chan_id).ok_or(SyscallError::BadHandle)?;
122 match chan.try_recv() {
123 Ok(msg) => {
124 let user_slice = UserSliceWrite::new(msg_ptr, MSG_SIZE).map_err(SyscallError::from)?;
125 let n = user_slice.copy_from(unsafe {
126 core::slice::from_raw_parts(&msg as *const IpcMessage as *const u8, MSG_SIZE)
127 });
128 if n != MSG_SIZE {
129 return Err(SyscallError::Fault);
130 }
131 Ok(0)
132 }
133 Err(e) => Err(SyscallError::from(e)),
134 }
135}
136
137pub fn sys_chan_close(handle: u64) -> Result<u64, SyscallError> {
139 crate::silo::enforce_cap_for_current_task(handle)?;
140
141 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
142 let caps = unsafe { &mut *task.process.capabilities.get() };
143 let cap = caps
144 .get(CapId::from_raw(handle))
145 .ok_or(SyscallError::BadHandle)?;
146 if cap.resource_type != ResourceType::Channel {
147 return Err(SyscallError::BadHandle);
148 }
149 let chan_id = ChanId::from_u64(cap.resource as u64);
150 let cap = caps
151 .remove(CapId::from_raw(handle))
152 .ok_or(SyscallError::BadHandle)?;
153 debug_assert_eq!(cap.resource_type, ResourceType::Channel);
154 crate::capability::release_capability(&cap, Some(task.id));
155
156 log::debug!("syscall: CHAN_CLOSE(handle={}) → chan={}", handle, chan_id);
157 Ok(0)
158}