strat9_kernel/syscall/
transport.rs1use crate::{
11 capability::{get_capability_manager, CapId, CapPermissions, ResourceType},
12 ipc::transport::{
13 IpcConsumer, IpcError, IpcProducer, IpcTransport, TransportConfig, TransportId,
14 TransportLevel, TransportManager,
15 },
16 memory::{UserSliceRead, UserSliceWrite},
17 process::current_task_clone,
18 silo::{self, SiloId},
19 syscall::error::SyscallError,
20};
21use alloc::vec;
22
23pub(crate) static TRANSPORT_MANAGER: TransportManager = TransportManager::new();
25
26pub fn sys_transport_create(dst_silo_val: u64, config_flags: u64) -> Result<u64, SyscallError> {
32 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
33 let src_silo_id = silo::try_silo_id_for_task(task.id).ok_or(SyscallError::BadHandle)?;
34 let src_silo = SiloId::new(src_silo_id);
35 let dst_silo = SiloId::new(dst_silo_val as u32);
36
37 let level_raw = (config_flags & 0xF) as u8;
39 let min_level = match level_raw {
40 1 => TransportLevel::TypeSafe,
41 2 => TransportLevel::LockFree,
42 3 => TransportLevel::Mmu,
43 _ => TransportLevel::LockFree, };
45 let ring_capacity = {
46 let cap = ((config_flags >> 8) & 0xFFFF) as u32;
47 if cap == 0 {
48 256
49 } else {
50 cap
51 }
52 };
53
54 let config = TransportConfig {
55 min_level,
56 ring_capacity: Some(ring_capacity),
57 slot_size: Some(2048),
58 };
59
60 let result = TRANSPORT_MANAGER
61 .establish(src_silo, dst_silo, config)
62 .map_err(|_| SyscallError::NotSupported)?;
63
64 let cap = get_capability_manager().create_capability(
65 ResourceType::IpcTransport,
66 result.id.as_u64() as usize,
67 CapPermissions::read_write(),
68 );
69
70 let mut caps = unsafe { (*task.process.capabilities.get()).clone() };
71 let cap_id = caps.insert(cap);
72 unsafe {
73 *task.process.capabilities.get() = caps;
74 }
75
76 Ok(cap_id.as_u64())
77}
78
79pub fn sys_transport_send(handle: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
81 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
82 let caps = unsafe { &*task.process.capabilities.get() };
83
84 let cap = caps
85 .get_with_permissions(CapId::from_raw(handle), CapPermissions::read_write())
86 .ok_or(SyscallError::BadHandle)?;
87
88 if cap.resource_type != ResourceType::IpcTransport {
89 return Err(SyscallError::BadHandle);
90 }
91
92 let len = buf_len as usize;
93 let user_buf = UserSliceRead::new(buf_ptr, len)?;
94 let data = user_buf.read_to_vec();
95
96 let tid = TransportId::from_u64(cap.resource as u64);
97 let endpoint = TRANSPORT_MANAGER
98 .get_endpoint(tid)
99 .ok_or(SyscallError::BadHandle)?;
100
101 endpoint
102 .send(&data)
103 .map_err(|e| transport_to_syscall_err(e))?;
104
105 TRANSPORT_MANAGER.stats.lock().sent += 1;
107
108 log::trace!("transport_send: handle={} len={}", handle, len);
109 Ok(len as u64)
110}
111
112pub fn sys_transport_recv(handle: u64, buf_ptr: u64, buf_len: u64) -> Result<u64, SyscallError> {
114 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
115 let caps = unsafe { &*task.process.capabilities.get() };
116
117 let cap = caps
118 .get_with_permissions(CapId::from_raw(handle), CapPermissions::read_write())
119 .ok_or(SyscallError::BadHandle)?;
120
121 if cap.resource_type != ResourceType::IpcTransport {
122 return Err(SyscallError::BadHandle);
123 }
124
125 if buf_len == 0 {
126 return Err(SyscallError::Fault);
127 }
128
129 let tid = TransportId::from_u64(cap.resource as u64);
130 let endpoint = TRANSPORT_MANAGER
131 .get_endpoint(tid)
132 .ok_or(SyscallError::BadHandle)?;
133
134 let user_buf = UserSliceWrite::new(buf_ptr, buf_len as usize)?;
135 let mut kbuf = vec![0u8; buf_len as usize];
136 let n = endpoint
137 .recv(&mut kbuf)
138 .map_err(|e| transport_to_syscall_err(e))?;
139 user_buf.copy_from(&kbuf[..n]);
140
141 TRANSPORT_MANAGER.stats.lock().received += 1;
143
144 log::trace!("transport_recv: handle={} n={}", handle, n);
145 Ok(n as u64)
146}
147
148pub fn sys_transport_close(handle: u64) -> Result<u64, SyscallError> {
150 use crate::capability::release_capability;
151
152 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
153 let cap_id = CapId::from_raw(handle);
154 let caps = unsafe { &mut *task.process.capabilities.get() };
155 if let Some(cap) = caps.remove(cap_id) {
156 release_capability(&cap, Some(task.id));
157 log::trace!("transport_close: handle={}", handle);
158 Ok(0)
159 } else {
160 Err(SyscallError::BadHandle)
161 }
162}
163
164pub fn sys_transport_info(handle: u64, out_ptr: u64) -> Result<u64, SyscallError> {
166 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
167 let caps = unsafe { &*task.process.capabilities.get() };
168
169 let _cap = caps
170 .get_with_permissions(CapId::from_raw(handle), CapPermissions::read_write())
171 .ok_or(SyscallError::BadHandle)?;
172
173 if out_ptr == 0 {
174 return Err(SyscallError::Fault);
175 }
176
177 let tid = TransportId::from_u64(_cap.resource as u64);
178 let endpoint = TRANSPORT_MANAGER
179 .get_endpoint(tid)
180 .ok_or(SyscallError::BadHandle)?;
181 let level = endpoint.level() as u64;
182 let out = UserSliceWrite::new(out_ptr, 8)?;
183 out.copy_from(&level.to_ne_bytes());
184 Ok(8)
185}
186
187fn transport_to_syscall_err(e: IpcError) -> SyscallError {
189 match e {
190 IpcError::WouldBlock => SyscallError::Again,
191 IpcError::Disconnected => SyscallError::Pipe,
192 IpcError::MessageTooLarge => SyscallError::Fault,
193 IpcError::BufferTooSmall => SyscallError::Fault,
194 IpcError::TransportNotFound => SyscallError::BadHandle,
195 IpcError::PermissionDenied => SyscallError::PermissionDenied,
196 IpcError::TransportFailed => SyscallError::IoError,
197 IpcError::InvalidRip => SyscallError::Fault,
198 IpcError::TimedOut => SyscallError::TimedOut,
199 }
200}